Revision 9530
Added by Chris Jones over 8 years ago
src/perl/register-dataset.cgi | ||
---|---|---|
44 | 44 |
use File::Temp; |
45 | 45 |
use File::Copy; |
46 | 46 |
use Fcntl qw(:flock); |
47 |
use Crypt::JWT qw(decode_jwt); |
|
48 |
use Crypt::X509; |
|
49 |
use IO::Socket::SSL; |
|
47 | 50 |
use strict; |
48 | 51 |
|
49 | 52 |
#debug("running register-dataset.cgi"); |
... | ... | |
66 | 69 |
$properties->load(*METACAT_PROPERTIES); |
67 | 70 |
|
68 | 71 |
# local directory configuration |
69 |
my $skinsDir = "${workingDirectory}/../style/skins"; |
|
70 |
my $templatesDir = abs_path("${workingDirectory}/../style/common/templates"); |
|
71 |
my $tempDir = $properties->getProperty('application.tempDir'); |
|
72 |
my $dataDir = $properties->getProperty('application.datafilepath'); |
|
73 |
my $metacatDir = "/var/metacat"; |
|
72 |
my $skinsDir = "${workingDirectory}/../style/skins"; |
|
73 |
my $templatesDir = abs_path("${workingDirectory}/../style/common/templates"); |
|
74 |
my $tempDir = $properties->getProperty('application.tempDir'); |
|
75 |
my $dataDir = $properties->getProperty('application.datafilepath'); |
|
76 |
my $metacatDir = "/var/metacat"; |
|
77 |
my $cnUrl = $properties->getProperty('D1Client.CN_URL'); |
|
78 |
my $cn = "server"; |
|
79 |
my $pem_file_path = "/tmp/server.pem"; |
|
80 |
my $der_file_path = "/tmp/server.der"; |
|
74 | 81 |
|
82 |
# Signing certificate file name is based on the CN environment |
|
83 |
if ( $cnUrl && $tempDir ) { |
|
84 |
my @parts = split(/\//, $cnUrl); |
|
85 |
$cn = $parts[2]; |
|
86 |
$pem_file_path = $tempDir . "/" . $cn . ".pem"; |
|
87 |
$der_file_path = $tempDir . "/" . $cn . ".der"; |
|
88 |
|
|
89 |
} |
|
90 |
|
|
75 | 91 |
# url configuration |
76 | 92 |
my $server = $properties->splitToTree( qr/\./, 'server' ); |
77 | 93 |
my $protocol = 'http://'; |
... | ... | |
455 | 471 |
|
456 | 472 |
# Create a metacat object |
457 | 473 |
my $metacat = Metacat->new($metacatUrl); |
474 |
setAuthToken($metacat); |
|
458 | 475 |
|
459 | 476 |
if ( !$error ) { |
460 | 477 |
|
... | ... | |
1460 | 1477 |
my $input = shift; |
1461 | 1478 |
my ( $docid, $fileHash ) = datafileInfo($input); |
1462 | 1479 |
my $metacat = Metacat->new($metacatUrl); |
1480 |
setAuthToken($metacat); |
|
1463 | 1481 |
|
1464 | 1482 |
my ( $username, $password ) = getCredentials(); |
1465 | 1483 |
my $response = $metacat->login( $username, $password ); |
... | ... | |
2438 | 2456 |
|
2439 | 2457 |
# create metacat instance |
2440 | 2458 |
my $metacat = Metacat->new($metacatUrl); |
2441 |
my $httpMessage; |
|
2459 |
setAuthToken($metacat); |
|
2460 |
my $httpMessage; |
|
2442 | 2461 |
my $doc; |
2443 | 2462 |
my $xmldoc; |
2444 | 2463 |
my $findType; |
... | ... | |
3496 | 3515 |
|
3497 | 3516 |
# create metacat instance |
3498 | 3517 |
my $metacat = Metacat->new($metacatUrl); |
3518 |
setAuthToken($metacat); |
|
3499 | 3519 |
my $docid = $FORM::docid; |
3500 | 3520 |
|
3501 | 3521 |
# Login to metacat |
... | ... | |
3624 | 3644 |
my $password = $FORM::password; |
3625 | 3645 |
|
3626 | 3646 |
my $metacat = Metacat->new($metacatUrl); |
3647 |
setAuthToken($metacat); |
|
3627 | 3648 |
my $returnVal = $metacat->login( $username, $password ); |
3628 | 3649 |
debug( |
3629 | 3650 |
"Login was $returnVal for login attempt to $metacatUrl, with $username" |
... | ... | |
3758 | 3779 |
|
3759 | 3780 |
#debug("getting user info for session id: $sessionId"); |
3760 | 3781 |
my $metacat = Metacat->new($metacatUrl); |
3761 |
|
|
3782 |
setAuthToken($metacat); |
|
3783 |
|
|
3762 | 3784 |
my ( $username, $password ) = getCredentials(); |
3763 | 3785 |
$metacat->login( $username, $password ); |
3764 | 3786 |
|
... | ... | |
3872 | 3894 |
|
3873 | 3895 |
sub getReviewHistoryHTML { |
3874 | 3896 |
my $metacat = Metacat->new($metacatUrl); |
3897 |
setAuthToken($metacat); |
|
3875 | 3898 |
my ( $username, $password ) = getCredentials(); |
3876 | 3899 |
$metacat->login( $username, $password ); |
3877 | 3900 |
my $parser = XML::LibXML->new(); |
... | ... | |
3917 | 3940 |
|
3918 | 3941 |
my $errorMessage = ''; |
3919 | 3942 |
my $metacat = Metacat->new($metacatUrl); |
3943 |
setAuthToken($metacat); |
|
3920 | 3944 |
|
3921 | 3945 |
print "Content-type: text/html\n\n"; |
3922 | 3946 |
|
... | ... | |
4092 | 4116 |
my $errorMessage = ''; |
4093 | 4117 |
my $userDN = ''; |
4094 | 4118 |
my $metacat = Metacat->new($metacatUrl); |
4119 |
setAuthToken($metacat); |
|
4095 | 4120 |
my $docid = $FORM::docid; |
4096 | 4121 |
|
4097 | 4122 |
print "Content-type: text/html\n\n"; |
... | ... | |
4229 | 4254 |
sub handleModRevise() { |
4230 | 4255 |
my $errorMessage = ''; |
4231 | 4256 |
my $metacat = Metacat->new($metacatUrl); |
4257 |
setAuthToken($metacat); |
|
4232 | 4258 |
my $docid = $FORM::docid; |
4233 | 4259 |
|
4234 | 4260 |
print "Content-type: text/html\n\n"; |
... | ... | |
5441 | 5467 |
$projects[6] = \@row7; |
5442 | 5468 |
return \@projects; |
5443 | 5469 |
} |
5470 |
|
|
5471 |
################################################################################ |
|
5472 |
# |
|
5473 |
# Set the incoming HTTP Authorization header as an instance variable in the |
|
5474 |
# given Metacat object |
|
5475 |
# |
|
5476 |
################################################################################ |
|
5477 |
sub setAuthToken() { |
|
5478 |
my $metacat = shift; |
|
5479 |
|
|
5480 |
eval { $metacat->isa('Metacat'); }; |
|
5481 |
|
|
5482 |
if ( ! $@ ) { |
|
5483 |
# Set the auth_token_header if available |
|
5484 |
if ( $ENV{'HTTP_AUTHORIZATION'}) { |
|
5485 |
$metacat->set_options( |
|
5486 |
auth_token_header => $ENV{'HTTP_AUTHORIZATION'}); |
|
5487 |
} |
|
5488 |
|
|
5489 |
} else { |
|
5490 |
debug('Not an instance of Metacat.' . |
|
5491 |
'Pass a Metacat object only to setAuthToken()'); |
|
5492 |
} |
|
5493 |
} |
|
5494 |
|
|
5495 |
################################################################################ |
|
5496 |
# |
|
5497 |
# Downloads the server certificate used to sign tokens, and converts it from PEM |
|
5498 |
# format to DER format. Writes both to the Metacat temp directory if configured. |
|
5499 |
# |
|
5500 |
################################################################################ |
|
5501 |
sub getSigningCertificate() { |
|
5502 |
|
|
5503 |
open(my $pem_cert_file, ">", $pem_file_path) |
|
5504 |
or die "\nCould not open PEM certificate file: $!\n"; |
|
5505 |
|
|
5506 |
# Attempts to use IO::Socket::SSL->peer_certificate() |
|
5507 |
# and Net::SSLeay->get_peer_certificate() |
|
5508 |
# return an unparseable cert (it seems). |
|
5509 |
# Settle for the openssl command instead. |
|
5510 |
# my $client = IO::Socket::SSL->new('cn-stage.test.dataone.org:443') |
|
5511 |
# or die "error=$!, ssl_error=$SSL_ERROR"; |
|
5512 |
#$signing_cert = $client->peer_certificate(); |
|
5513 |
#print $signing_cert; |
|
5514 |
#$client->close(); |
|
5515 |
|
|
5516 |
my @lines = `openssl s_client -connect $cn:443 -showcerts 2>/dev/null`; |
|
5517 |
|
|
5518 |
my $count = 0; |
|
5519 |
my ($start_line_number, $end_line_number); |
|
5520 |
|
|
5521 |
# Find the start line of the first cert |
|
5522 |
for my $line (@lines) { |
|
5523 |
$count = $count + 1; |
|
5524 |
if ( $line =~ /BEGIN/) { |
|
5525 |
$start_line_number = $count; |
|
5526 |
last; |
|
5527 |
|
|
5528 |
} |
|
5529 |
} |
|
5530 |
|
|
5531 |
# Find the end line of the first cert |
|
5532 |
$count = 0; |
|
5533 |
for my $line (@lines) { |
|
5534 |
$count = $count + 1; |
|
5535 |
if ( $line =~ /END/) { |
|
5536 |
$end_line_number = $count; |
|
5537 |
last; |
|
5538 |
|
|
5539 |
} |
|
5540 |
} |
|
5541 |
|
|
5542 |
# print the cert to a PEM file |
|
5543 |
$count = 0; |
|
5544 |
for my $line (@lines) { |
|
5545 |
$count = $count + 1; |
|
5546 |
if ( $count >= $start_line_number && $count <= $end_line_number) { |
|
5547 |
print $pem_cert_file $line; |
|
5548 |
|
|
5549 |
} |
|
5550 |
} |
|
5551 |
|
|
5552 |
close($pem_cert_file); |
|
5553 |
|
|
5554 |
# Convert the PEM to DER |
|
5555 |
my @convert_der_args = ("openssl", "x509", |
|
5556 |
"-in", $pem_file_path, "-inform", "PEM", |
|
5557 |
"-out", $der_file_path, "-outform", "DER"); |
|
5558 |
system(@convert_der_args); |
|
5559 |
|
|
5560 |
} |
|
5561 |
|
|
5562 |
################################################################################ |
|
5563 |
# |
|
5564 |
# Returns details about the parsed token |
|
5565 |
# |
|
5566 |
################################################################################ |
|
5567 |
sub getTokenInfo() { |
|
5568 |
# Initialize the token info hash |
|
5569 |
my $token_info = { |
|
5570 |
userId => '', |
|
5571 |
issuedAt => '', |
|
5572 |
iat => '', |
|
5573 |
sub => '', |
|
5574 |
consumerKey => '', |
|
5575 |
exp => '', |
|
5576 |
ttl => '', |
|
5577 |
fullName => '', |
|
5578 |
isValid => 0 |
|
5579 |
}; |
|
5580 |
|
|
5581 |
my $der_cert_file; |
|
5582 |
my $signing_cert; |
|
5583 |
|
|
5584 |
# If we don't already have the CN signing cert, get it |
|
5585 |
if ( ! -e $der_file_path ) { |
|
5586 |
getSigningCertificate(); |
|
5587 |
|
|
5588 |
} |
|
5589 |
|
|
5590 |
# Read the DER-encoded certificate |
|
5591 |
open($der_cert_file, "<", $cn . ".der") |
|
5592 |
or die "\nCould not open DER certificate file: $!\n"; |
|
5593 |
binmode($der_cert_file); |
|
5594 |
read($der_cert_file, $signing_cert, 4096) |
|
5595 |
or die "Problem reading the DER-encoded server cert: $!\n" if $!; |
|
5596 |
close($der_cert_file); |
|
5597 |
|
|
5598 |
my $cert = Crypt::X509->new(cert=>$signing_cert); |
|
5599 |
|
|
5600 |
# Decode the token using Crypt::JWT |
|
5601 |
eval{ $token_info = decode_jwt(token=>$token, key=>$cert); }; |
|
5602 |
if ( ! $@ ) { |
|
5603 |
$$token_info{isValid} = 1; |
|
5604 |
} |
|
5605 |
|
|
5606 |
return $token_info; |
|
5607 |
|
|
5608 |
} |
|
5609 |
|
Also available in: Unified diff
Add a setAuthToken() method. when the HTTP_AUTHORIZATION environment variable is set, set the value as the `auth_token_header` instance variable in the Metacat instance passed in. This requires that the Apache installation includes an HTTP rewrite rule to pass the header on to an CGI processing the request. Call this method whenever we instantiate a Metacat object.
Also, add two methods that will be used for parsing the JWT authentication token: getSigningCertificate() and getTokenInfo(). The former tries to download the appropriate certificate used to sign the token coming in from the request, based on the Metacat D1Client.CN_URL property. With the appropriate PEM-encoded certificate converted to a DER-encode certificate, we use Crypt::JWT->decode_jwt() to decode the token. This is a finicky method in that it fails when the token has expired, rather than just decoding it and returning the token claims, expired or not. So, in getTokenInfo(), on failure, we just set the isValid field to 0 with everything else being empty. I know, kludgy.
refs https://github.nceas.ucsb.edu/KNB/arctic-data/issues/42