GeniAuthority.pm.in 8.94 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
#!/usr/bin/perl -wT
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# All rights reserved.
#
package GeniAuthority;

#
# Some simple ticket stuff.
#
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);

@ISA    = "Exporter";
@EXPORT = qw ( );

# Must come after package declaration!
use GeniDB;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
21
use GeniRegistry;
22
use GeniHRN;
23
24
use Genixmlrpc;
use GeniResponse;
25
use emutil qw(TBGetUniqueIndex);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
26
27
28
use English;
use overload ('""' => 'Stringify');
use XML::Simple;
29
use Date::Parse;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
30
31
32
33
34
35
36
37
38
39
40
41
42

# Configure variables
my $TB		   = "@prefix@";
my $TBOPS          = "@TBOPSEMAIL@";
my $TBAPPROVAL     = "@TBAPPROVALEMAIL@";
my $TBAUDIT   	   = "@TBAUDITEMAIL@";
my $BOSSNODE       = "@BOSSNODE@";
my $OURDOMAIN      = "@OURDOMAIN@";
my $SIGNCRED	   = "$TB/sbin/signgenicred";
my $VERIFYCRED	   = "$TB/sbin/verifygenicred";

# Cache of instances to avoid regenerating them.
my %authorities    = ();
43
BEGIN { use GeniUtil; GeniUtil::AddCache(\%authorities); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
44
45

#
46
# Lookup by URN (and also UUID, for compatibility).
Leigh B. Stoller's avatar
Leigh B. Stoller committed
47
48
49
50
51
#
sub Lookup($$)
{
    my ($class, $token) = @_;
    my $query_result;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
52
    my $uuid;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
53

54
55
56
    if (GeniHRN::IsValid($token)) {
	$query_result =
	    DBQueryWarn("select uuid from geni_authorities ".
57
			"where urn='$token'");
58
59
60
61
62

	return undef
	    if (! $query_result || !$query_result->numrows);

	($uuid) = $query_result->fetchrow_array();
63
64
    }
    elsif ($token =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
65
	$uuid = $token;
66
    }
67
68
    elsif ($token =~ /^[\w\.]*$/) {
	$query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
69
	    DBQueryWarn("select uuid from geni_authorities ".
70
			"where hrn='$token'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
71
72
	return undef
	    if (! $query_result || !$query_result->numrows);
73

Leigh B. Stoller's avatar
Leigh B. Stoller committed
74
	($uuid) = $query_result->fetchrow_array();
75
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
76
77
78
79
    else {
	return undef;
    }
    # Look in cache first
Leigh B. Stoller's avatar
Leigh B. Stoller committed
80
81
    return $authorities{"$uuid"}
        if (exists($authorities{"$uuid"}));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
82
83

    $query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
84
	DBQueryWarn("select * from geni_authorities where uuid='$uuid'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
85
86
87
88
89
90
    
    return undef
	if (!$query_result || !$query_result->numrows);

    my $self              = {};
    $self->{'AUTHORITY'}  = $query_result->fetchrow_hashref();
91
    $self->{'version'}    = undef;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
92
93
94
95
96
    bless($self, $class);

    #
    # Grab the certificate, since we will probably want it.
    #
97
98
    my $certificate = GeniCertificate->Lookup($uuid);
    if (!defined($certificate)) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
99
	print STDERR "Could not find certificate for authority $uuid\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
100
101
	return undef;
    }
102
    $self->{'CERT'} = $certificate;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
103
104
    
    # Add to cache. 
Leigh B. Stoller's avatar
Leigh B. Stoller committed
105
    $authorities{$self->{'AUTHORITY'}->{'uuid'}} = $self;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
106
107
108
109
110
111
112
113
114
115
116
    
    return $self;
}

#
# Stringify for output.
#
sub Stringify($)
{
    my ($self) = @_;
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
117
    my $hrn = $self->hrn();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
118

Leigh B. Stoller's avatar
Leigh B. Stoller committed
119
    return "[GeniAuthority: $hrn]";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
120
121
122
123
124
}

#
# Create a Geni authority in the DB.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
125
sub Create($$$$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
126
{
127
    my ($class, $certificate, $url, $type) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
128
129

    my @insert_data = ();
130
    my ($prefix) = ($certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-(\w+)$/);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
131

132
    my $safe_hrn    = DBQuoteSpecial($certificate->hrn());
133
    my $safe_urn    = DBQuoteSpecial($certificate->URN());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
134
    my $safe_url    = DBQuoteSpecial($url);
135
    my $safe_uuid   = DBQuoteSpecial($certificate->uuid());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
136
    my $safe_prefix = DBQuoteSpecial($prefix);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
137
    my $safe_type   = DBQuoteSpecial(lc($type));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
138
139
140
141
    
    # Now tack on other stuff we need.
    push(@insert_data, "created=now()");
    push(@insert_data, "hrn=$safe_hrn");
142
    push(@insert_data, "urn=$safe_urn");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
143
144
    push(@insert_data, "url=$safe_url");
    push(@insert_data, "uuid=$safe_uuid");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
145
    push(@insert_data, "uuid_prefix=$safe_prefix");
146
    push(@insert_data, "type=$safe_type");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
147

148
    if ($certificate->Store() != 0) {
149
	print STDERR "Could not store certificate for new authority.\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
150
151
152
	return undef;
    }

153
154
    # Insert into DB. Use "replace" here since we reload the auth info
    # periodically, and do not want to cause a race by deleting it. 
155
156
157
158
    return undef
	if (!DBQueryWarn("replace into geni_authorities set " .
			 join(",", @insert_data)));

159
160
161
    # Delete from cache, since we use replace above. 
    delete($authorities{$certificate->uuid()});

162
163
    return GeniAuthority->Lookup( defined( $certificate->urn() ) ?
	$certificate->urn() : $certificate->uuid() );
Leigh B. Stoller's avatar
Leigh B. Stoller committed
164
165
166
167
}
# accessors
sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'AUTHORITY'}->{$_[1]}); }
sub uuid($)		{ return field($_[0], "uuid"); }
168
sub expires($)		{ return field($_[0], "expires"); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
169
sub uuid_prefix($)	{ return field($_[0], "uuid_prefix"); }
170
sub urn($)		{ return field($_[0], "urn"); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
171
172
sub url($)		{ return field($_[0], "url"); }
sub hrn($)		{ return field($_[0], "hrn"); }
173
sub type($)		{ return field($_[0], "type"); }
174
sub disabled($)		{ return field($_[0], "disabled"); }
175
sub version($)		{ return field($_[0], "version"); }
176
177
sub cert($)		{ return $_[0]->{'CERT'}->cert(); }
sub GetCertificate($)   { return $_[0]->{'CERT'}; }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
178

179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#
# Expired?
#
sub IsExpired($)
{
    my ($self)  = @_;
    my $expires = $self->expires();

    return 1
	if (!defined($expires) || $expires eq "");
    
    my $when = strptime($expires);

    return ($when < time());
}

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#
# Delete from the DB.
#
sub Delete($)
{
    my ($self) = @_;

    return -1
	if (! ref($self));

    if ($self->GetCertificate()->Delete() != 0) {
	print STDERR "Could not delete certificate for $self\n";
	return -1;
    }
    my $uuid = $self->uuid();
    DBQueryWarn("delete from geni_authorities ".
		"where uuid='$uuid'")
	or return -1;

214
    # Delete from cache. 
215
216
217
218
    delete($authorities{$uuid});
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
219
#
220
# Check to see if there is an existing authority with the same urn.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
221
#
222
sub CheckExisting($$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
223
{
224
225
    my ($class, $certificate) = @_;
    my $urn = $certificate->urn();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
226

227
228
229
230
    my (undef, undef, $type) = GeniHRN::Parse($urn);
    return -1
	if (!defined($type));
    my $safe_urn = DBQuoteSpecial($urn);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
231
232

    my $query_result =
233
234
	DBQueryWarn("select urn,type from geni_authorities ".
		    "where urn=$safe_urn");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
235
236
237
238
239
240

    return -1
	if (!$query_result);
    return 0
	if (!$query_result->numrows);

241
    while (my ($DBurn,$DBtype) = $query_result->fetchrow_array()) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
242
243
	# Look for an exact match, which means its just a replacement.
	next
244
	    if ($urn eq $DBurn && $type eq $DBtype);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
245

246
	# Same urn, different type.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
247
	return 1
248
	    if ($urn eq $DBurn && $type ne $DBtype);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
249

250
	# Different urn, same type.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
251
	return 1
252
	    if ($urn ne $DBurn && $type eq $DBtype);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
253
254
255
256
    }
    return 0;
}

257
258
259
260
261
#
# Create authority from the ClearingHouse, by looking up the info.
#
sub CreateFromRegistry($$$)
{
262
    my ($class, $type, $name) = @_;
263

264
265
266
267
    my $authority = GeniAuthority->Lookup($name);
    return $authority
	if (defined($authority) && $authority->urn());

Leigh B. Stoller's avatar
Leigh B. Stoller committed
268
269
270
271
    my $clearinghouse = GeniRegistry::ClearingHouse->Create();
    return undef
	if (!defined($clearinghouse));

272
273
    my $blob;
    return undef
274
	if ($clearinghouse->Resolve($name, $type, \$blob) != 0);
275
276
277
278
279

    my $certificate = GeniCertificate->LoadFromString($blob->{'gid'});
    return undef
	if (!defined($certificate));

280
281
282
283
284
285
286
287
288
289
290
291
292
293
    #
    # At this point, we do not support non-urn sites. They must re-register.
    #
    my $urn = $certificate->urn();
    if (!defined($urn)) {
	print STDERR "GeniAuthority::CreateFromRegistry: ".
	    "$certificate does not have a urn.\n";
	$certificate->Delete();
	return undef;
    }

    $authority = GeniAuthority->Create($certificate,
				       $blob->{'url'},
				       $blob->{'type'});
294
295
296
297
298
299
    $certificate->Delete()
	if (!defined($authority));

    return $authority;
}

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#
# Get Version. Ask the Authority what version it is running. 
#
sub Version($)
{
    my ($self) = @_;

    return $self->version()
	if (defined($self->version()));

    #
    # The caller had to set up the xmlrpc context.
    #
    my $response =
	Genixmlrpc::CallMethod($self->url(), undef, "GetVersion");
    
    if (!defined($response)) {
	print STDERR "*** Internal error getting version for $self\n";
	return undef;
    }
    if ($response->code() != GENIRESPONSE_SUCCESS) {
	print STDERR "Could not get version for $self Error: ";
	print STDERR "  " . $response->output() . "\n";
	return undef;
    }
    $self->{'version'} = $response->value();
    return $response->value();
}

329
#
330
331
# Check that the authority is the issuer of the given certificate.
# This check is not quite complete yet.
332
#
333
sub CheckValidIssuer($$)
334
{
335
    my ($self, $certificate) = @_;
336

337
338
    my ($hisauthority, undef, undef) = GeniHRN::Parse($self->urn());
    my ($herauthority, undef, undef) = GeniHRN::Parse($certificate->urn());
339
    return 0
340
341
	if (! (defined($hisauthority) && defined($herauthority) &&
	       $hisauthority eq $herauthority));
342

343
    return 1;
344
345
}

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
#
# List all authorities.
#
sub ListAll($$)
{
    my ($class, $pref) = @_;
    my @result = ();
    @$pref = ();

    my $query = "select uuid from geni_authorities";
    my $query_result = DBQueryWarn($query);

    return -1
	if (! $query_result);
    return 0
	if (!$query_result->numrows);

    while (my ($uuid) = $query_result->fetchrow_array()) {
	my $authority = GeniAuthority->Lookup($uuid);
	if (!defined($authority)) {
	    print STDERR "Could not lookup authority $uuid\n";
	    return -1;
	}
	push(@result, $authority);
    }
    @$pref = @result;
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
375
376
377
# _Always_ make sure that this 1 is at the end of the file...
1;