Commit ceb61751 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint in case I need to install this into the main tree

parent c3f0111e
......@@ -11,7 +11,7 @@ SUBDIR = protogeni
include $(OBJDIR)/Makeconf
SUBDIRS = security xmlrpc lib
SUBDIRS = security xmlrpc lib scripts
all: all-subdirs
......@@ -21,6 +21,7 @@ install:
@$(MAKE) -C security install
@$(MAKE) -C xmlrpc install
@$(MAKE) -C lib install
@$(MAKE) -C scripts install
control-install:
......
......@@ -81,7 +81,8 @@ CREATE TABLE `geni_authorities` (
`type` enum('sa','ma','ch') NOT NULL default 'sa',
`url` tinytext,
PRIMARY KEY (`idx`),
UNIQUE KEY `uuid` (`uuid`)
UNIQUE KEY `uuid` (`uuid`),
UNIQUE KEY `uuid_prefix` (`uuid_prefix`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
......@@ -119,7 +120,7 @@ CREATE TABLE `geni_slivers` (
`idx` mediumint(8) unsigned NOT NULL default '0',
`uuid` varchar(40) NOT NULL default '',
`hrn` varchar(256) NOT NULL default '',
`name` varchar(256) NOT NULL default '',
`nickname` varchar(256) default NULL,
`slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '',
`resource_uuid` varchar(40) NOT NULL default '',
......@@ -142,14 +143,13 @@ DROP TABLE IF EXISTS `geni_aggregates`;
CREATE TABLE `geni_aggregates` (
`idx` mediumint(8) unsigned NOT NULL default '0',
`hrn` varchar(256) NOT NULL default '',
`name` varchar(256) NOT NULL default '',
`nickname` varchar(256) default NULL,
`uuid` varchar(40) NOT NULL default '',
`type` varchar(40) NOT NULL default '',
`slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`credential_idx` int(10) unsigned default NULL,
`ticket_idx` int(10) unsigned default NULL,
`component_idx` int(10) unsigned NOT NULL default '0',
`aggregate_idx` int(10) unsigned default NULL,
`status` enum('created','ready','broken') NOT NULL default 'created',
......@@ -176,7 +176,7 @@ CREATE TABLE `geni_tickets` (
PRIMARY KEY (`idx`),
INDEX `owner_uuid` (`owner_uuid`),
INDEX `slice_uuid` (`slice_uuid`),
UNIQUE KEY `compseqno` (`component_idx`, `seqno`)
UNIQUE KEY `compseqno` (`component_uuid`, `seqno`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
#
......@@ -206,6 +206,7 @@ CREATE TABLE `geni_certificates` (
`uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL,
`cert` text,
`DN` text,
`privkey` text,
`revoked` datetime default NULL,
PRIMARY KEY (`uuid`)
......
......@@ -125,16 +125,16 @@ sub Stringify($)
# for now. The client side does not actually know its an aggregate, at
# least not yet.
#
sub Create($$$$$)
sub Create($$$$$$)
{
my ($class, $slice, $owner, $aggregate_type, $hrn) = @_;
my ($class, $slice, $owner, $aggregate_type, $hrn, $nickname) = @_;
my @insert_data = ();
# Every aggregate gets a new unique index.
my $idx = TBGetUniqueIndex('next_aggregate', 1);
# Create a cert pair, which gives us a new uuid.
my $certificate = GeniCertificate->Create("aggregate");
my $certificate = GeniCertificate->Create("aggregate", $hrn, $TBOPS);
if (!defined($certificate)) {
print STDERR "Could not generate new certificate and UUID!\n";
return undef;
......@@ -147,6 +147,7 @@ sub Create($$$$$)
push(@insert_data, "created=now()");
push(@insert_data, "idx='$idx'");
push(@insert_data, "hrn=" . DBQuoteSpecial($hrn));
push(@insert_data, "nickname=" . DBQuoteSpecial($nickname));
push(@insert_data, "uuid='$uuid'");
push(@insert_data, "creator_uuid='$owner_uuid'");
push(@insert_data, "slice_uuid='$slice_uuid'");
......@@ -165,6 +166,7 @@ sub Create($$$$$)
sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'AGGREGATE'}->{$_[1]}); }
sub idx($) { return field($_[0], "idx"); }
sub uuid($) { return field($_[0], "uuid"); }
sub nickname($) { return field($_[0], "nickname"); }
sub type($) { return field($_[0], "type"); }
sub slice_uuid($) { return field($_[0], "slice_uuid"); }
sub creator_uuid($) { return field($_[0], "creator_uuid"); }
......@@ -232,7 +234,7 @@ sub hrn($)
if (defined($hrn) && $hrn ne "") {
return $hrn;
}
return $OURDOMAIN . ".aggregates." . $self->idx();
return "emulab.aggregate_" . $self->idx();
}
#
......@@ -441,6 +443,9 @@ sub NewCredential($$)
print STDERR "Could not create credential for $self, $owner\n";
return undef;
}
if (defined($self->nickname())) {
$credential->AddExtension("nickname", $self->nickname());
}
if ($credential->Sign($self->GetCertificate()) != 0) {
print STDERR "Could not sign credential for $self, $owner\n";
return undef;
......@@ -557,9 +562,14 @@ use Interface;
sub Create($$$)
{
my ($class, $slice, $owner, $hrn) = @_;
my ($class, $slice, $owner, $linkname) = @_;
#
# Form an hrn using the slicename and linkname
#
my $hrn = "emulab." . $slice->slicename() . "." . $linkname;
return GeniAggregate->Create($slice, $owner, "Link", $hrn);
return GeniAggregate->Create($slice, $owner, "Link", $hrn, $linkname);
}
#
......
......@@ -59,6 +59,12 @@ sub Lookup($$)
($idx) = $query_result->fetchrow_array();
}
elsif ($token =~ /^\d+$/) {
$idx = $token;
}
elsif ($token =~ /^P([\w]+)$/) {
return GeniAuthority->LookupByPrefix($1);
}
elsif ($token =~ /^[\w\.]*$/) {
$query_result =
DBQueryWarn("select idx from geni_authorities ".
......@@ -120,15 +126,15 @@ sub Stringify($)
#
sub Create($$$$$$)
{
my ($class, $uuid, $hrn, $url, $cert, $prefix, $type) = @_;
my ($class, $certificate, $url, $type) = @_;
my @insert_data = ();
my $idx = TBGetUniqueIndex('next_authority', 1);
my ($prefix) = ($certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-(\w+)$/);
my $safe_hrn = DBQuoteSpecial($hrn);
my $safe_hrn = DBQuoteSpecial($certificate->hrn());
my $safe_url = DBQuoteSpecial($url);
my $safe_uuid = DBQuoteSpecial($uuid);
my $safe_cert = DBQuoteSpecial($cert);
my $safe_uuid = DBQuoteSpecial($certificate->uuid());
my $safe_prefix = DBQuoteSpecial($prefix);
my $safe_type = DBQuoteSpecial($type);
......@@ -141,18 +147,16 @@ sub Create($$$$$$)
push(@insert_data, "uuid_prefix=$safe_prefix");
push(@insert_data, "type=$safe_type");
# Insert into DB.
DBQueryWarn("replace into geni_authorities set " .
join(",", @insert_data))
or return undef;
# Insert the certificate.
if (!DBQueryWarn("replace into geni_certificates set ".
" uuid=$safe_uuid, cert=$safe_cert")) {
DBQueryWarn("delete from geni_authorities where idx='$idx'");
if ($certificate->Store() != 0) {
print STDERR "Could not store certificate for new user.\n";
return undef;
}
# Insert into DB.
return undef
if (!DBQueryWarn("replace into geni_authorities set " .
join(",", @insert_data)));
return GeniAuthority->Lookup($idx);
}
# accessors
......@@ -166,6 +170,30 @@ sub type($) { return field($_[0], "type"); }
sub cert($) { return $_[0]->{'CERT'}->cert(); }
sub GetCertificate($) { return $_[0]->{'CERT'}; }
#
# Create authority from the ClearingHouse, by looking up the info.
#
sub CreateFromRegistry($$$)
{
my ($class, $type, $uuid) = @_;
my $blob;
return undef
if (GeniCHClient::Resolve($uuid, $type, \$blob) != 0);
my $certificate = GeniCertificate->LoadFromString($blob->{'gid'});
return undef
if (!defined($certificate));
my $authority = GeniAuthority->Create($certificate,
$blob->{'url'},
$blob->{'type'});
$certificate->Delete()
if (!defined($authority));
return $authority;
}
#
# Does the uuid prefix match.
#
......@@ -178,8 +206,6 @@ sub PrefixMatch($$)
my $uuid_prefix = $self->uuid_prefix();
print "$uuid, $uuid_prefix, $self\n";
if ($uuid =~ /^\w+\-\w+\-\w+\-\w+\-(\w+)$/) {
return 1
if ("$uuid_prefix" eq "$1");
......@@ -187,6 +213,38 @@ sub PrefixMatch($$)
return 0;
}
#
# Find an authority by looking for the prefix. This will eventually go
# away when we switch top chains.
#
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 no parse uuid for prefix\n";
return undef;
}
my $query_result =
DBQueryWarn("select idx from geni_authorities ".
"where uuid_prefix='$prefix'");
return undef
if (! $query_result || !$query_result->numrows);
my ($idx) = $query_result->fetchrow_array();
return GeniAuthority->Lookup($idx);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
This diff is collapsed.
......@@ -132,9 +132,9 @@ sub LookupSlice($$)
#
# Register a record at the clearing house.
#
sub Register($$$$)
sub Register($$$)
{
my ($hrn, $type, $cert, $info) = @_;
my ($type, $cert, $info) = @_;
SetCredential();
......@@ -142,7 +142,6 @@ sub Register($$$$)
Genixmlrpc::CallMethod($GENICENTRALURL, $MyContext, "Register",
{ "credential" => $Credential,
"type" => $type,
"hrn" => $hrn,
"cert" => $cert,
"info" => $info });
return -1
......@@ -155,29 +154,29 @@ sub Register($$$$)
# Register a local Emulab user at the Geni ClearingHouse (which in the
# prototype is Utah Emulab).
#
sub RegisterUser($$$$$)
sub RegisterUser($$$$)
{
my ($hrn, $name, $email, $cert, $keys) = @_;
my ($name, $email, $cert, $keys) = @_;
my $info = { "name" => $name,
"email" => $email };
$info->{"sliverkeys"} = $keys
if (defined($keys));
return Register($hrn, "User", $cert, $info);
return Register("User", $cert, $info);
}
#
# Register a slice at the Clearinghouse.
#
sub RegisterSlice($$$$)
sub RegisterSlice($$$)
{
my ($hrn, $creator_uuid, $cert, $bindings) = @_;
my ($creator_uuid, $cert, $bindings) = @_;
my $info = { "creator_uuid" => $creator_uuid,
"userbindings" => $bindings };
return Register($hrn, "Slice", $cert, $info);
return Register("Slice", $cert, $info);
}
#
......
This diff is collapsed.
......@@ -65,8 +65,9 @@ sub Lookup($$)
return undef
if (!$query_result || !$query_result->numrows);
my $self = {};
$self->{'CERT'} = $query_result->fetchrow_hashref();
my $self = {};
$self->{'CERT'} = $query_result->fetchrow_hashref();
$self->{'stored'} = 1;
bless($self, $class);
my $cert = $self->cert();
......@@ -93,20 +94,47 @@ sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'CERT'}->{$_[1]}); }
sub uuid($) { return field($_[0], "uuid"); }
sub created($) { return field($_[0], "created"); }
sub cert($) { return field($_[0], "cert"); }
sub DN($) { return field($_[0], "DN"); }
sub privkey($) { return field($_[0], "privkey"); }
sub revoked($) { return field($_[0], "revoked"); }
#
# The fields are buried inside the DN.
#
sub hrn($)
{
my ($self) = @_;
if ($self->DN() =~ /\/OU=([-\w\.]+)\//) {
return $1
if ($1 ne "");
}
print STDERR "Cannot find hrn inside DN: '" . $self->DN() . "'\n";
return "unknown";
}
sub email($)
{
my ($self) = @_;
if ($self->DN() =~ /\/emailAddress=(.*)/) {
return $1
if ($1 ne "");
}
print STDERR "Cannot find email inside DN: '" . $self->DN() . "'\n";
return "unknown";
}
#
# Create a certificate pair, which gives us a uuid to use for an object.
#
sub Create($$;$)
sub Create($$$$;$)
{
my ($class, $what, $uuid) = @_;
my ($class, $what, $hrn, $email, $uuid) = @_;
# Let mkcert generate a new one.
$uuid = ""
if (!defined($uuid));
if (! open(CERT, "$MKCERT $what $uuid |")) {
if (! open(CERT, "$MKCERT -e \"$email\" $hrn $uuid |")) {
print STDERR "Could not start $MKCERT\n";
return undef;
}
......@@ -148,19 +176,17 @@ sub Create($$;$)
print STDERR "Improper chars in certificate string\n";
return undef;
}
if (GeniCertificate->CertificateInfo($cert, \$uuid) != 0){
print STDERR "Could not find uuid in certificate: $cert\n";
return undef;
}
my $safe_cert = DBQuoteSpecial($cert);
my $safe_uuid = DBQuoteSpecial($uuid);
my $safe_key = DBQuoteSpecial($privkey);
my $certificate = GeniCertificate->LoadFromString($cert);
return undef
if (!DBQueryWarn("replace into geni_certificates set ".
" created=now(), uuid=$safe_uuid, ".
" cert=$safe_cert, privkey=$safe_key"));
if (!defined($certificate));
return GeniCertificate->Lookup($uuid);
$certificate->{'CERT'}->{'privkey'} = $privkey;
if ($certificate->Store() != 0) {
print STDERR "Could not write new certificate to DB\n";
return undef;
}
return $certificate;
}
#
......@@ -172,118 +198,140 @@ sub Delete($)
my $uuid = $self->uuid();
return -1
if (!DBQueryWarn("delete from geni_certificates where uuid='$uuid'"));
if ($self->{'stored'} &&
!DBQueryWarn("delete from geni_certificates where uuid='$uuid'"));
return 0;
}
#
# Store a public key for a uuid. This is for something that is hosted
# elsewhere and we just want to save the pubkey away in case we need it.
# Load a certificate from a string. This creates an object, but does
# not store it in the DB.
#
sub StorePublic($$)
sub LoadFromString($$)
{
my ($class, $cert) = @_;
my ($class, $string) = @_;
if (! ($cert =~ /^[\012\015\040-\176]*$/)) {
if (! ($string =~ /^[\012\015\040-\176]*$/)) {
print STDERR "Improper chars in certificate string\n";
return undef;
}
my $uuid;
if (GeniCertificate->CertificateInfo($cert, \$uuid) != 0){
print STDERR "Could not find uuid in certificate: $cert\n";
my ($tempfile, $filename) = tempfile(UNLINK => 1);
if (!$tempfile) {
print STDERR "Could not create tempfile for cert string\n";
return undef;
}
my $safe_cert = DBQuoteSpecial($cert);
my $safe_uuid = DBQuoteSpecial($uuid);
return undef
if (!DBQueryWarn("replace into geni_certificates set ".
" created=now(), uuid=$safe_uuid, cert=$safe_cert"));
return GeniCertificate->Lookup($uuid);
}
#
# Write a certificate and private key to a tempfile, as for signing with it.
#
sub WriteToFile($)
{
my ($self) = @_;
# We want this file to be passed back.
my ($tempfile, $filename) = tempfile(UNLINK => 1);
print $tempfile "-----BEGIN CERTIFICATE-----\n";
print $tempfile $self->cert();
print $tempfile $string;
print $tempfile "-----END CERTIFICATE-----\n";
print $tempfile "-----BEGIN RSA PRIVATE KEY-----\n";
print $tempfile $self->privkey();
print $tempfile "-----END RSA PRIVATE KEY-----\n";
return $filename;
my $certificate = GeniCertificate->LoadFromFile($filename);
unlink($filename);
return $certificate;
}
#
# Convert a certificate to its uuid.
# Load a certificate from a file. This creates an object, but does
# not store it in the DB.
#
sub CertificateInfo($$$)
sub LoadFromFile($$)
{
my ($class, $string, $pref) = @_;
my ($class, $filename) = @_;
# Deleted when scope is left.
my $tempfile = new File::Temp(UNLINK => 1);
my $filename = $tempfile->filename;
print $tempfile "-----BEGIN CERTIFICATE-----\n";
print $tempfile "$string";
print $tempfile "-----END CERTIFICATE-----\n";
my $dn = `$OPENSSL x509 -in $filename -noout -subject`;
if ($?) {
print STDERR "Failed to convert $filename to uuid!\n";
return -1;
if (! open(X509, "$OPENSSL x509 -in $filename -subject |")) {
print STDERR "Could not start $OPENSSL on $filename\n";
return undef;
}
my @certlines = ();
while (<X509>) {
push(@certlines, $_);
}
if (!close(X509) || !@certlines) {
print STDERR "Could not load certificate from $filename\n";
return undef;
}
#
# The first line is the DN (subject).
#
my $DN = shift(@certlines);
chomp($DN);
#
# Throw away first and last lines; the cert is rest.
#
shift(@certlines);
pop(@certlines);
my $cert = join("", @certlines);
if ($dn =~ /CN=([-\w]*)$/) {
$$pref = $1;
# Dig out the uuid.
my $uuid;
if ($DN =~ /\/CN=([-\w]*)/) {
$uuid = $1;
}
else {
return -1;
print STDERR "Could not find uuid in 'DN'\n";
return undef;
}
return 0;
my $self = {};
$self->{'CERT'} = {};
$self->{'stored'} = 0;
bless($self, $class);
$self->{'CERT'}->{'uuid'} = $uuid;
$self->{'CERT'}->{'cert'} = $cert;
$self->{'CERT'}->{'DN'} = $DN;
$self->{'CERT'}->{'privkey'} = undef;
$self->{'CERT'}->{'revoked'} = undef;
$self->{'CERT'}->{'created'} = undef;
return $self;
}
#
# Convert a certificate inside a pem file to its cert and uuid.
# Store a certificate that was loaded from a string/file.
#
sub CertificateInfoFromFile($$$$)
sub Store($)
{
my ($class, $filename, $pcert, $puuid) = @_;
my ($self) = @_;
my $dn = `$OPENSSL x509 -in $filename -noout -subject`;
if ($?) {
print STDERR "Failed to convert $filename to uuid!\n";
return -1;
}
if ($dn =~ /CN=([-\w]*)$/) {
$$puuid = $1;
}
else {
return -1;
}
return 0
if (!defined($pcert));
if ($self->{'stored'});
my @inserts = ();
push(@inserts, "created=now()");
push(@inserts, "uuid=" . DBQuoteSpecial($self->uuid()));
push(@inserts, "cert=" . DBQuoteSpecial($self->cert()));
push(@inserts, "DN=" . DBQuoteSpecial($self->DN()));
push(@inserts, "privkey=" . DBQuoteSpecial($self->privkey()))
if (defined($self->privkey()));
return -1
if (!DBQueryWarn("replace into geni_certificates set ".
join(",", @inserts)));
my $cert = `$OPENSSL x509 -in $filename`;
if ($?) {
print STDERR "Failed to convert $filename to cert!\n";
return -1;
}
$cert =~ s/^----.*----//mg;
$cert =~ s/^$//mg;
local $/ = "";
chomp($cert);
$$pcert = "$cert\n";
$self->{'stored'} = 1;
return 0;
}
#
# Write a certificate and private key to a tempfile, as for signing with it.
#
sub WriteToFile($)
{
my ($self) = @_;
# We want this file to be passed back.
my ($tempfile, $filename) = tempfile(UNLINK => 1);
print $tempfile "-----BEGIN CERTIFICATE-----\n";
print $tempfile $self->cert();
print $tempfile "-----END CERTIFICATE-----\n";
print $tempfile "-----BEGIN RSA PRIVATE KEY-----\n";
print $tempfile $self->privkey();
print $tempfile "-----END RSA PRIVATE KEY-----\n";
return $filename;
}
############################################################################
#
# Wrapper for local users.
......@@ -308,9 +356,11 @@ sub Create($$)
return undef
if (!defined($query_result) || !$query_result->numrows);
my $self = {};
$self->{'CERT'} = $query_result->fetchrow_hashref();
my $self = {};
$self->{'CERT'} = $query_result->fetchrow_hashref();
$self->{'stored'} = 1;
bless($self, $class);
return $self;
}
......@@ -321,5 +371,32 @@ sub cert($) { return field($_[0], "cert"); }
sub privkey($) { return field($_[0], "privkey"); }
sub revoked($) { return field($_[0], "revoked"); }
#
# Need to add DN to the emulab table.
#
sub DN($)
{
my ($self) = @_;
return $self->{'CERT'}->{'DN'}
if (exists($self->{'CERT'}->{'DN'}));
# Deleted when scope is left.
my $tempfile = new File::Temp(UNLINK => 1);
my $filename = $tempfile->filename;
print $tempfile "-----BEGIN CERTIFICATE-----\n";
print $tempfile "$self->cert()";
print $tempfile "-----END CERTIFICATE-----\n";
my $dn = `$OPENSSL x509 -in $filename -noout -subject`;
if ($?) {
print STDERR "Failed to convert $filename to uuid!\n";
return undef;
}
chomp($dn);
$self->{'CERT'}->{'DN'} = $dn;
return $dn;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -115,17 +115,16 @@ sub Stringify($)
#
# Create a Geni component in the DB.
#
sub Create($$$$$)
sub Create($$$)
{
my ($class, $uuid, $hrn, $url, $cert) = @_;
my ($class, $certificate, $url) = @_;
my @insert_data = ();
my $idx = TBGetUniqueIndex('next_component', 1);
my $safe_hrn = DBQuoteSpecial($hrn);
my $safe_hrn = DBQuoteSpecial($certificate