GeniAuthority.pm.in 9.83 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
69
70
71
    elsif ($token =~ /^P([\w]+)$/) {
	# Only SAs are looked up this way.
	# This will be flushed after URNs are fully pushed out.
	return GeniAuthority->LookupByPrefix($1);
    }
72
73
    elsif ($token =~ /^[\w\.]*$/) {
	$query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
74
	    DBQueryWarn("select uuid from geni_authorities ".
75
			"where hrn='$token'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
76
77
	return undef
	    if (! $query_result || !$query_result->numrows);
78

Leigh B. Stoller's avatar
Leigh B. Stoller committed
79
	($uuid) = $query_result->fetchrow_array();
80
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
81
82
83
84
    else {
	return undef;
    }
    # Look in cache first
Leigh B. Stoller's avatar
Leigh B. Stoller committed
85
86
    return $authorities{"$uuid"}
        if (exists($authorities{"$uuid"}));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
87
88

    $query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
89
	DBQueryWarn("select * from geni_authorities where uuid='$uuid'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
90
91
92
93
94
95
    
    return undef
	if (!$query_result || !$query_result->numrows);

    my $self              = {};
    $self->{'AUTHORITY'}  = $query_result->fetchrow_hashref();
96
    $self->{'version'}    = undef;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
97
98
99
100
101
    bless($self, $class);

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

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
124
    return "[GeniAuthority: $hrn]";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
125
126
127
128
129
}

#
# Create a Geni authority in the DB.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
130
sub Create($$$$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
131
{
132
    my ($class, $certificate, $url, $type) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
133
134

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

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

153
    if ($certificate->Store() != 0) {
154
	print STDERR "Could not store certificate for new authority.\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
155
156
157
	return undef;
    }

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

164
165
166
    # Delete from cache, since we use replace above. 
    delete($authorities{$certificate->uuid()});

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

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#
# Expired?
#
sub IsExpired($)
{
    my ($self)  = @_;
    my $expires = $self->expires();

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

    return ($when < time());
}

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#
# 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;

219
    # Delete from cache. 
220
221
222
223
    delete($authorities{$uuid});
    return 0;
}

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

232
233
234
235
    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
236
237

    my $query_result =
238
239
	DBQueryWarn("select urn,type from geni_authorities ".
		    "where urn=$safe_urn");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
240
241
242
243
244
245

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

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

251
	# Same urn, different type.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
252
	return 1
253
	    if ($urn eq $DBurn && $type ne $DBtype);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
254

255
	# Different urn, same type.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
256
	return 1
257
	    if ($urn ne $DBurn && $type eq $DBtype);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
258
259
260
261
    }
    return 0;
}

262
263
264
265
266
#
# Create authority from the ClearingHouse, by looking up the info.
#
sub CreateFromRegistry($$$)
{
267
    my ($class, $type, $name) = @_;
268

269
270
271
272
    my $authority = GeniAuthority->Lookup($name);
    return $authority
	if (defined($authority) && $authority->urn());

Leigh B. Stoller's avatar
Leigh B. Stoller committed
273
274
275
276
    my $clearinghouse = GeniRegistry::ClearingHouse->Create();
    return undef
	if (!defined($clearinghouse));

277
278
    my $blob;
    return undef
279
	if ($clearinghouse->Resolve($name, $type, \$blob) != 0);
280
281
282
283
284

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

285
286
287
288
289
290
291
292
293
294
295
296
297
298
    #
    # 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'});
299
300
301
302
303
304
    $certificate->Delete()
	if (!defined($authority));

    return $authority;
}

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
#
# 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();
}

334
#
335
336
# Check that the authority is the issuer of the given certificate.
# This check is not quite complete yet.
337
#
338
sub CheckValidIssuer($$)
339
{
340
    my ($self, $certificate) = @_;
341

342
343
    my ($hisauthority, undef, undef) = GeniHRN::Parse($self->urn());
    my ($herauthority, undef, undef) = GeniHRN::Parse($certificate->urn());
344
    return 0
345
346
	if (! (defined($hisauthority) && defined($herauthority) &&
	       $hisauthority eq $herauthority));
347

348
    return 1;
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
375
376
377
378
379
#
# 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;
}

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
#
# Find an authority by looking for the prefix. This will eventually go
# away when we fully switch to URNs
#
# Note tha only SAs are looked up this way.
#
sub LookupByPrefix($$)
{
    my ($class, $uuid) = @_;
    my $prefix;
    
    if ($uuid =~ /^\w+\-\w+\-\w+\-\w+\-(\w+)$/) {
	$prefix = $1;
    }
    elsif ($uuid =~ /^(\w+)$/) {
	$prefix = $1;
    }
    else {
	print STDERR "Could not parse uuid for prefix\n";
	return undef;
    }
    
    my $query_result =
	DBQueryWarn("select uuid from geni_authorities ".
		    "where uuid_prefix='$prefix' and type='sa'");

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

    ($uuid) = $query_result->fetchrow_array();

    return GeniAuthority->Lookup($uuid);
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
414
415
416
# _Always_ make sure that this 1 is at the end of the file...
1;