import tempfile
import traceback
import socket
+import random
from lxml import etree
from StringIO import StringIO
from types import StringTypes, ListType
from sfa.util.xmlrpcprotocol import ServerException
import sfa.util.xmlrpcprotocol as xmlrpcprotocol
from sfa.util.config import Config
+import zlib
# utility methods here
# display methods
-def display_rspec(rspec, format = 'rspec'):
+def display_rspec(rspec, format='rspec'):
if format in ['dns']:
tree = etree.parse(StringIO(rspec))
root = tree.getroot()
print result
-def display_records(recordList, dump = False):
+def display_records(recordList, dump=False):
''' Print all fields in the record'''
for record in recordList:
display_record(record, dump)
-def display_record(record, dump = False):
+def display_record(record, dump=False):
if dump:
record.dump()
else:
def save_records_to_file(filename, recordList):
index = 0
for record in recordList:
- if index>0:
+ if index > 0:
save_record_to_file(filename + "." + str(index), record)
else:
save_record_to_file(filename, record)
def save_record_to_file(filename, record):
if record['type'] in ['user']:
- record = UserRecord(dict = record)
+ record = UserRecord(dict=record)
elif record['type'] in ['slice']:
- record = SliceRecord(dict = record)
+ record = SliceRecord(dict=record)
elif record['type'] in ['node']:
- record = NodeRecord(dict = record)
+ record = NodeRecord(dict=record)
elif record['type'] in ['authority', 'ma', 'sa']:
- record = AuthorityRecord(dict = record)
+ record = AuthorityRecord(dict=record)
else:
- record = SfaRecord(dict = record)
+ record = SfaRecord(dict=record)
str = record.save_to_string()
file(filename, "w").write(str)
return
class Sfi:
-
+
+ geni_am = None
slicemgr = None
registry = None
user = None
options = None
hashrequest = False
- def create_cmd_parser(self,command, additional_cmdargs = None):
+ def create_cmd_parser(self, command, additional_cmdargs=None):
cmdargs = {"gid": "",
"list": "name",
"show": "name",
"create": "name rspec",
"get_trusted_certs": "cred",
"get_ticket": "name rspec",
- "redeem_ticket": "ticket",
+ "redeem_ticket": "ticket",
"delete": "name",
"reset": "name",
"start": "name",
"stop": "name",
- "delegate": "name"
+ "delegate": "name",
+ "GetVersion": "name",
+ "ListResources": "name",
+ "CreateSliver": "name",
+ "get_geni_aggregates": "name",
+ "DeleteSliver": "name",
+ "SliverStatus": "name",
+ "RenewSliver": "name",
+ "Shutdown": "name"
}
if additional_cmdargs:
print "Invalid command\n"
print "Commands: ",
for key in cmdargs.keys():
- print key+",",
+ print key + ",",
print ""
sys.exit(2)
% (command, cmdargs[command]))
if command in ("resources"):
- parser.add_option("-f", "--format", dest="format",type="choice",
- help="display format ([xml]|dns|ip)",default="xml",
- choices=("xml","dns","ip"))
+ parser.add_option("-f", "--format", dest="format", type="choice",
+ help="display format ([xml]|dns|ip)", default="xml",
+ choices=("xml", "dns", "ip"))
parser.add_option("-a", "--aggregate", dest="aggregate",
default=None, help="aggregate hrn")
if command in ("create", "get_ticket"):
- parser.add_option("-a", "--aggregate", dest="aggregate",default=None,
+ parser.add_option("-a", "--aggregate", dest="aggregate", default=None,
help="aggregate hrn")
if command in ("start", "stop", "reset", "delete", "slices"):
- parser.add_option("-c", "--component", dest="component",default=None,
+ parser.add_option("-c", "--component", dest="component", default=None,
help="component hrn")
if command in ("list", "show", "remove"):
- parser.add_option("-t", "--type", dest="type",type="choice",
+ parser.add_option("-t", "--type", dest="type", type="choice",
help="type filter ([all]|user|slice|sa|ma|node|aggregate)",
- choices=("all","user","slice","sa","ma","node","aggregate"),
+ choices=("all", "user", "slice", "sa", "ma", "node", "aggregate"),
default="all")
if command in ("resources", "show", "list"):
if command in ("show", "list"):
parser.add_option("-f", "--format", dest="format", type="choice",
- help="display format ([text]|xml)",default="text",
- choices=("text","xml"))
+ help="display format ([text]|xml)", default="text",
+ choices=("text", "xml"))
if command in ("delegate"):
parser.add_option("-u", "--user",
help="delegate user credential")
parser.add_option("-s", "--slice", dest="delegate_slice",
help="delegate slice credential", metavar="HRN", default=None)
+
return parser
# Generate command line parser
parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
description="Commands: gid,list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
+ parser.add_option("-g", "--geni_am", dest="geni_am",
+ help="geni am", metavar="URL", default=None)
parser.add_option("-r", "--registry", dest="registry",
help="root registry", metavar="URL", default=None)
parser.add_option("-s", "--slicemgr", dest="sm",
help="slice manager", metavar="URL", default=None)
- default_sfi_dir=os.path.expanduser("~/.sfi/")
+ default_sfi_dir = os.path.expanduser("~/.sfi/")
parser.add_option("-d", "--dir", dest="sfi_dir",
help="config & working directory - default is " + default_sfi_dir,
- metavar="PATH", default = default_sfi_dir)
+ metavar="PATH", default=default_sfi_dir)
parser.add_option("-u", "--user", dest="user",
help="user name", metavar="HRN", default=None)
parser.add_option("-a", "--auth", dest="auth",
try:
config = Config (config_file)
except:
- print "Failed to read configuration file",config_file
+ print "Failed to read configuration file", config_file
print "Make sure to remove the export clauses and to add quotes"
if not self.options.verbose:
print "Re-run with -v for more details"
traceback.print_exc()
sys.exit(1)
- errors=0
+ errors = 0
# Set SliceMgr URL
if (self.options.sm is not None):
sm_url = self.options.sm
- elif hasattr(config,"SFI_SM"):
+ elif hasattr(config, "SFI_SM"):
sm_url = config.SFI_SM
else:
- print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s"%config_file
- errors +=1
+ print "You need to set e.g. SFI_SM='http://your.slicemanager.url:12347/' in %s" % config_file
+ errors += 1
# Set Registry URL
if (self.options.registry is not None):
reg_url = self.options.registry
- elif hasattr(config,"SFI_REGISTRY"):
+ elif hasattr(config, "SFI_REGISTRY"):
reg_url = config.SFI_REGISTRY
else:
- print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s"%config_file
- errors +=1
-
+ print "You need to set e.g. SFI_REGISTRY='http://your.registry.url:12345/' in %s" % config_file
+ errors += 1
+
+
+ if (self.options.geni_am is not None):
+ geni_am_url = self.options.geni_am
+ elif hasattr(config, "SFI_GENI_AM"):
+ geni_am_url = config.SFI_GENI_AM
+
# Set user HRN
if (self.options.user is not None):
self.user = self.options.user
- elif hasattr(config,"SFI_USER"):
+ elif hasattr(config, "SFI_USER"):
self.user = config.SFI_USER
else:
- print "You need to set e.g. SFI_USER='plc.princeton.username' in %s"%config_file
- errors +=1
+ print "You need to set e.g. SFI_USER='plc.princeton.username' in %s" % config_file
+ errors += 1
# Set authority HRN
if (self.options.auth is not None):
self.authority = self.options.auth
- elif hasattr(config,"SFI_AUTH"):
+ elif hasattr(config, "SFI_AUTH"):
self.authority = config.SFI_AUTH
else:
- print "You need to set e.g. SFI_AUTH='plc.princeton' in %s"%config_file
- errors +=1
+ print "You need to set e.g. SFI_AUTH='plc.princeton' in %s" % config_file
+ errors += 1
if errors:
sys.exit(1)
self.cert = Certificate(filename=cert_file)
# Establish connection to server(s)
self.registry = xmlrpcprotocol.get_server(reg_url, key_file, cert_file, self.options.debug)
- self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
+ self.slicemgr = xmlrpcprotocol.get_server(sm_url, key_file, cert_file, self.options.debug)
+ self.geni_am = xmlrpcprotocol.get_server(geni_am_url, key_file, cert_file, self.options.debug)
+
return
#
def get_key_file(self):
- file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
+ file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".pkey")
#file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".pkey")
if (os.path.isfile(file)):
return file
sys.exit(-1)
return
- def get_cert_file(self,key_file):
+ def get_cert_file(self, key_file):
#file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cert")
- file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
+ file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cert")
if (os.path.isfile(file)):
return file
else:
- k = Keypair(filename = key_file)
+ k = Keypair(filename=key_file)
cert = Certificate(subject=self.user)
cert.set_pubkey(k)
cert.set_issuer(k, self.user)
def get_gid(self):
#file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".gid")
- file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".gid")
+ file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".gid")
if (os.path.isfile(file)):
gid = GID(filename=file)
return gid
def get_user_cred(self):
#file = os.path.join(self.options.sfi_dir, get_leaf(self.user) + ".cred")
- file=os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
+ file = os.path.join(self.options.sfi_dir, self.user.replace(self.authority + '.', '') + ".cred")
if (os.path.isfile(file)):
user_cred = Credential(filename=file)
return user_cred
else:
# bootstrap user credential
cert_string = self.cert.save_to_string(save_parents=True)
- user_name=self.user.replace(self.authority+".", '')
+ user_name = self.user.replace(self.authority + ".", '')
if user_name.count(".") > 0:
user_name = user_name.replace(".", '_')
- self.user=self.authority + "." + user_name
+ self.user = self.authority + "." + user_name
user_cred = self.registry.get_self_credential(cert_string, "user", self.user)
if user_cred:
print "no authority specified. Use -a or set SF_AUTH"
sys.exit(-1)
- file = os.path.join(self.options.sfi_dir, get_leaf("authority") +".cred")
+ file = os.path.join(self.options.sfi_dir, get_leaf("authority") + ".cred")
if (os.path.isfile(file)):
auth_cred = Credential(filename=file)
return auth_cred
print "Failed to get authority credential"
sys.exit(-1)
- def get_slice_cred(self,name):
+ def get_slice_cred(self, name):
file = os.path.join(self.options.sfi_dir, "slice_" + get_leaf(name) + ".cred")
if (os.path.isfile(file)):
slice_cred = Credential(filename=file)
print "Failed to get slice credential"
sys.exit(-1)
- def delegate_cred(self,cred, hrn, type = 'authority'):
+ def delegate_cred(self, cred, hrn, type='authority'):
# the gid and hrn of the object we are delegating
user_cred = Credential(string=cred)
object_gid = user_cred.get_gid_object()
delegee_hrn = delegee_gid.get_hrn()
# the key and hrn of the user who will be delegating
- user_key = Keypair(filename = self.get_key_file())
+ user_key = Keypair(filename=self.get_key_file())
user_hrn = user_cred.get_gid_caller().get_hrn()
dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn)
dcred.set_gid_caller(delegee_gid)
dcred.set_gid_object(object_gid)
dcred.set_privileges(user_cred.get_privileges())
- dcred.set_delegate(True)
- dcred.set_pubkey(object_gid.get_pubkey())
- dcred.set_issuer(user_key, user_hrn)
+ dcred.get_privileges().delegate_all_privileges(True)
+
+
+ # Save the issuer's gid to a file
+ fname = self.options.sfi_dir + os.sep + "gid_%d" % random.randint(0, 999999999)
+ f = open(fname, "w")
+ f.write(user_cred.get_gid_caller().save_to_string())
+ f.close()
+ dcred.set_issuer_keys(self.get_key_file(), fname)
+ os.remove(fname)
+
dcred.set_parent(user_cred)
dcred.encode()
dcred.sign()
return dcred.save_to_string(save_parents=True)
- def get_rspec_file(self,rspec):
+ def get_rspec_file(self, rspec):
if (os.path.isabs(rspec)):
file = rspec
else:
print "No such rspec file", rspec
sys.exit(1)
- def get_record_file(self,record):
+ def get_record_file(self, record):
if (os.path.isabs(record)):
file = record
else:
print "No such registry record file", record
sys.exit(1)
- def load_publickey_string(self,fn):
- f = file(fn,"r")
+ def load_publickey_string(self, fn):
+ f = file(fn, "r")
key_string = f.read()
# if the filename is a private key file, then extract the public key
# Registry-related commands
#
- def dispatch(self,command, cmd_opts, cmd_args):
- getattr(self,command)(cmd_opts, cmd_args)
+ def dispatch(self, command, cmd_opts, cmd_args):
+ getattr(self, command)(cmd_opts, cmd_args)
def gid(self, opts, args):
gid = self.get_gid()
return
# list entires in named authority registry
- def list(self,opts, args):
+ def list(self, opts, args):
user_cred = self.get_user_cred().save_to_string(save_parents=True)
hrn = args[0]
try:
return
# show named registry record
- def show(self,opts, args):
+ def show(self, opts, args):
user_cred = self.get_user_cred().save_to_string(save_parents=True)
hrn = args[0]
records = self.registry.resolve(user_cred, hrn)
print "No record of type", opts.type
for record in records:
if record['type'] in ['user']:
- record = UserRecord(dict = record)
+ record = UserRecord(dict=record)
elif record['type'] in ['slice']:
- record = SliceRecord(dict = record)
+ record = SliceRecord(dict=record)
elif record['type'] in ['node']:
- record = NodeRecord(dict = record)
+ record = NodeRecord(dict=record)
elif record['type'] in ['authority', 'ma', 'sa']:
- record = AuthorityRecord(dict = record)
+ record = AuthorityRecord(dict=record)
else:
- record = SfaRecord(dict = record)
- if (opts.format=="text"):
+ record = SfaRecord(dict=record)
+ if (opts.format == "text"):
record.dump()
else:
print record.save_to_string()
save_records_to_file(file, records)
return
- def delegate(self,opts, args):
+ def delegate(self, opts, args):
user_cred = self.get_user_cred()
if opts.delegate_user:
object_cred = user_cred
object_gid = object_cred.get_gid_object()
object_hrn = object_gid.get_hrn()
- if not object_cred.get_delegate():
+ if not object_cred.get_privileges().get_all_delegate():
print "Error: Object credential", object_hrn, "does not have delegate bit set"
return
print "Error: Didn't find a user record for", args[0]
return
- # the gid of the user who will be delegated too
+ # the gid of the user who will be delegated to
delegee_gid = GID(string=records[0]['gid'])
delegee_hrn = delegee_gid.get_hrn()
# the key and hrn of the user who will be delegating
- user_key = Keypair(filename = self.get_key_file())
+ user_key = Keypair(filename=self.get_key_file())
user_hrn = user_cred.get_gid_caller().get_hrn()
subject_string = "%s delegated to %s" % (object_hrn, delegee_hrn)
dcred = Credential(subject=subject_string)
dcred.set_gid_caller(delegee_gid)
dcred.set_gid_object(object_gid)
+ privs = object_cred.get_privileges()
dcred.set_privileges(object_cred.get_privileges())
- dcred.set_delegate(True)
+ dcred.get_privileges().delegate_all_privileges(True)
dcred.set_pubkey(object_gid.get_pubkey())
dcred.set_issuer(user_key, user_hrn)
dcred.set_parent(object_cred)
dest_fn = os.path_join(self.options.sfi_dir, get_leaf(delegee_hrn) + "_slice_"
+ get_leaf(object_hrn) + ".cred")
- dcred.save_to_file(dest_fn, save_parents = True)
+ dcred.save_to_file(dest_fn, save_parents=True)
print "delegated credential for", object_hrn, "to", delegee_hrn, "and wrote to", dest_fn
# removed named registry record
# - have to first retrieve the record to be removed
- def remove(self,opts, args):
+ def remove(self, opts, args):
auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
hrn = args[0]
type = opts.type
return self.registry.remove(auth_cred, type, hrn)
# add named registry record
- def add(self,opts, args):
+ def add(self, opts, args):
auth_cred = self.get_auth_cred().save_to_string(save_parents=True)
record_filepath = args[0]
rec_file = self.get_record_file(record_filepath)
return self.registry.register(auth_cred, record)
# update named registry entry
- def update(self,opts, args):
+ def update(self, opts, args):
user_cred = self.get_user_cred()
rec_file = self.get_record_file(args[0])
record = load_record_from_file(rec_file)
"""
user_cred = self.get_user_cred().save_to_string(save_parents=True)
hrn = None
- if args:
+ if args:
hrn = args[0]
+
result = self.registry.get_aggregates(user_cred, hrn)
display_list(result)
return
+ def get_geni_aggregates(self, opts, args):
+ """
+ return a list of details about known aggregates
+ """
+ user_cred = self.get_user_cred().save_to_string(save_parents=True)
+ hrn = None
+ if args:
+ hrn = args[0]
+
+ result = self.registry.get_geni_aggregates(user_cred, hrn)
+ display_list(result)
+ return
+
+
def registries(self, opts, args):
"""
return a list of details about known registries
# list available nodes -- use 'resources' w/ no argument instead
# list instantiated slices
- def slices(self,opts, args):
+ def slices(self, opts, args):
user_cred = self.get_user_cred().save_to_string(save_parents=True)
server = self.slicemgr
# direct connection to the nodes component manager interface
return
# show rspec for named slice
- def resources(self,opts, args):
+ def resources(self, opts, args):
user_cred = self.get_user_cred().save_to_string(save_parents=True)
server = self.slicemgr
if opts.aggregate:
return
# created named slice with given rspec
- def create(self,opts, args):
+ def create(self, opts, args):
slice_hrn = args[0]
user_cred = self.get_user_cred()
slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
rspec_file = self.get_rspec_file(args[1])
- rspec=open(rspec_file).read()
+ rspec = open(rspec_file).read()
server = self.slicemgr
if opts.aggregate:
aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
user_cred = self.get_user_cred()
slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
rspec_file = self.get_rspec_file(rspec_path)
- rspec=open(rspec_file).read()
+ rspec = open(rspec_file).read()
server = self.slicemgr
if opts.aggregate:
aggregates = self.registry.get_aggregates(user_cred, opts.aggregate)
# use this to get the right slice credential
ticket = SfaTicket(filename=ticket_file)
ticket.decode()
- slice_hrn=ticket.gidObject.get_hrn()
+ slice_hrn = ticket.gidObject.get_hrn()
#slice_hrn = ticket.attributes['slivers'][0]['hrn']
user_cred = self.get_user_cred()
slice_cred = self.get_slice_cred(slice_hrn).save_to_string(save_parents=True)
try:
cm_port = "12346"
url = "https://%(hostname)s:%(cm_port)s" % locals()
- print "Calling redeem_ticket at %(url)s " % locals(),
+ print "Calling redeem_ticket at %(url)s " % locals(),
cm = xmlrpcprotocol.get_server(url, self.key_file, self.cert_file, self.options.debug)
cm.redeem_ticket(slice_cred, ticket.save_to_string(save_parents=True))
print "Success"
return
# delete named slice
- def delete(self,opts, args):
+ def delete(self, opts, args):
slice_hrn = args[0]
server = self.slicemgr
# direct connection to the nodes component manager interface
return server.delete_slice(slice_cred, slice_hrn)
# start named slice
- def start(self,opts, args):
+ def start(self, opts, args):
slice_hrn = args[0]
server = self.slicemgr
# direct connection to the nodes component manager interface
return server.start_slice(slice_cred, slice_hrn)
# stop named slice
- def stop(self,opts, args):
+ def stop(self, opts, args):
slice_hrn = args[0]
server = self.slicemgr
# direct connection to the nodes component manager interface
return server.stop_slice(slice_cred, slice_hrn)
# reset named slice
- def reset(self,opts, args):
+ def reset(self, opts, args):
slice_hrn = args[0]
server = self.slicemgr
# direct connection to the nodes component manager interface
server = self.get_component_server_from_hrn(opts.component)
slice_cred = self.get_slice_cred(args[0]).save_to_string(save_parents=True)
return server.reset_slice(slice_cred, slice_hrn)
+
+
+ # GENI AM related calls
+
+ def GetVersion(self, opts, args):
+ server = self.geni_am
+ print server.GetVersion()
+
+ def ListResources(self, opts, args):
+ user_cred = self.get_user_cred().save_to_string(save_parents=True)
+ server = self.geni_am
+ call_options = {'geni_compressed': True}
+ xrn = None
+ cred = user_cred
+ if args:
+ xrn = args[0]
+ cred = self.get_slice_cred(xrn).save_to_string(save_parents=True)
+
+ if xrn:
+ call_options['geni_slice_urn'] = xrn
+
+ rspec = server.ListResources([cred], call_options)
+ rspec = zlib.decompress(rspec.decode('base64'))
+ print rspec
+
+ def CreateSliver(self, opts, args):
+ slice_xrn = args[0]
+ slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
+ rspec_file = self.get_rspec_file(args[1])
+ rspec = open(rspec_file).read()
+ server = self.geni_am
+ return server.CreateSliver(slice_xrn, [slice_cred], rspec, [])
+
+ def DeleteSliver(self, opts, args):
+ slice_xrn = args[0]
+ slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
+ server = self.geni_am
+ return server.DeleteSliver(slice_xrn, [slice_cred])
+
+ def SliverStatus(self, opts, args):
+ slice_xrn = args[0]
+ slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
+ server = self.geni_am
+ print server.SliverStatus(slice_xrn, [slice_cred])
+
+ def RenewSliver(self, opts, args):
+ slice_xrn = args[0]
+ slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
+ time = args[1]
+ server = self.geni_am
+ return server.RenewSliver(slice_xrn, [slice_cred], time)
+
+ def Shutdown(self, opts, args):
+ slice_xrn = args[0]
+ slice_cred = self.get_slice_cred(slice_xrn).save_to_string(save_parents=True)
+ server = self.geni_am
+ return server.Shutdown(slice_xrn, [slice_cred])
#
# Main: parse arguments and dispatch to command
self.options = options
if options.hashrequest:
- self.hashrequest=True
+ self.hashrequest = True
if len(args) <= 0:
print "No command given. Use -h for help."
- return -1
+ return - 1
command = args[0]
(cmd_opts, cmd_args) = self.create_cmd_parser(command).parse_args(args[1:])
print "Registry %s, sm %s, dir %s, user %s, auth %s" % (options.registry, options.sm,
options.sfi_dir, options.user,
options.auth)
- print "Command %s" %command
+ print "Command %s" % command
if command in ("resources"):
- print "resources cmd_opts %s" %cmd_opts.format
- elif command in ("list","show","remove"):
- print "cmd_opts.type %s" %cmd_opts.type
- print "cmd_args %s" %cmd_args
+ print "resources cmd_opts %s" % cmd_opts.format
+ elif command in ("list", "show", "remove"):
+ print "cmd_opts.type %s" % cmd_opts.type
+ print "cmd_args %s" % cmd_args
self.set_servers()
return
-if __name__=="__main__":
+if __name__ == "__main__":
Sfi().main()
action "SFA SliceMgr" daemon /usr/bin/sfa-server.py -s -d $OPTIONS
fi
+ if [ "$SFA_GENI_AGGREGATE_ENABLED" ]; then
+ action $"SFA GENI Aggregate" daemon /usr/bin/sfa-server.py -g -d $OPTIONS
+ fi
+
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/sfa
hostnames.append(node.hostname)
return hostnames
-def create_slice(api, xrn, xml):
+def create_slice(api, xrn, xml, reg_objects=None):
"""
Verify HRN and initialize the slice record in PLC if necessary.
"""
registry = api.registries[api.hrn]
credential = api.getCredential()
site_id, remote_site_id = slices.verify_site(registry, credential, hrn,
- peer, sfa_peer)
+ peer, sfa_peer, reg_objects)
+
slice = slices.verify_slice(registry, credential, hrn, site_id,
- remote_site_id, peer, sfa_peer)
+ remote_site_id, peer, sfa_peer, reg_objects)
network = Network(api)
current = __get_hostnames(slice.get_nodes())
network.addRSpec(xml, api.config.SFA_AGGREGATE_RSPEC_SCHEMA)
-
request = __get_hostnames(network.nodesWithSlivers())
# remove nodes not in rspec
# add nodes from rspec
added_nodes = list(set(request).difference(current))
+
+
if peer:
api.plshell.UnBindObjectFromPeer(api.plauth, 'slice', slice.id, peer)
raise RecordNotFound(hrn)
slice_id = slices[0]
attributes = api.plshell.GetSliceTags(api.plauth, {'slice_id': slice_id, 'name': 'enabled'}, ['slice_attribute_id'])
- attribute_id = attreibutes[0]['slice_attribute_id']
+ attribute_id = attributes[0]['slice_attribute_id']
api.plshell.UpdateSliceTag(api.plauth, attribute_id, "1" )
return 1
from sfa.trust.certificate import *
from sfa.util.faults import *
+
+
def get_credential(api, xrn, type, is_self=False):
# convert xrn to hrn
if type:
hrn = urn_to_hrn(xrn)[0]
else:
hrn, type = urn_to_hrn(xrn)
+
# Is this a root or sub authority
auth_hrn = api.auth.get_authority(hrn)
if not auth_hrn or hrn == api.config.SFA_INTERFACE_HRN:
new_cred = Credential(subject = object_gid.get_subject())
new_cred.set_gid_caller(caller_gid)
new_cred.set_gid_object(object_gid)
- new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
- new_cred.set_pubkey(object_gid.get_pubkey())
+ new_cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename())
+ #new_cred.set_pubkey(object_gid.get_pubkey())
new_cred.set_privileges(rights)
- new_cred.set_delegate(True)
+ new_cred.get_privileges().delegate_all_privileges(True)
auth_kind = "authority,ma,sa"
- new_cred.set_parent(api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
+ # Parent not necessary, verify with certs
+ #new_cred.set_parent(api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
new_cred.encode()
new_cred.sign()
return new_cred.save_to_string(save_parents=True)
+
+# The GENI GetVersion call
+def GetVersion():
+ version = {}
+ version['geni_api'] = 1
+ return version
+
+
+
+# The GENI resolve call
+def Resolve(api, xrn, creds):
+ records = resolve(api, xrn)
+
+ if len(records) == 0:
+ return {}
+
+ record = records[0]
+ if record.type == 'slice':
+ return {'geni_urn': xrn, 'geni_creator': " ".join(record.PI)}
+ if record.type == 'user':
+ return {'geni_urn': xrn, 'geni_certificate': record.gid}
+
+
+
def resolve(api, xrns, type=None, origin_hrn=None, full=True):
# load all know registry names into a prefix tree and attempt to find
def register(api, record):
hrn, type = record['hrn'], record['type']
-
+ urn = hrn_to_urn(hrn,type)
# validate the type
if type not in ['authority', 'slice', 'node', 'user']:
raise UnknownSfaType(type)
pub_key = record['key']
pkey = convert_public_key(pub_key)
- gid_object = api.auth.hierarchy.create_gid(hrn, uuid, pkey)
+ gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
gid = gid_object.save_to_string(save_parents=True)
record['gid'] = gid
record.set_gid(gid)
if type in ["authority"]:
# update the tree
if not api.auth.hierarchy.auth_exists(hrn):
- api.auth.hierarchy.create_auth(hrn)
+ api.auth.hierarchy.create_auth(hrn_to_urn(hrn,'authority'))
# get the GID from the newly created authority
gid = auth_info.get_gid_object()
new_record = SfaRecord(dict = record_dict)
type = new_record['type']
hrn = new_record['hrn']
+ urn = hrn_to_urn(hrn,type)
api.auth.verify_object_permission(hrn)
table = SfaTable()
# make sure the record exists
# update the openssl key and gid
pkey = convert_public_key(new_key)
uuid = create_uuid()
- gid_object = api.auth.hierarchy.create_gid(hrn, uuid, pkey)
+ gid_object = api.auth.hierarchy.create_gid(urn, uuid, pkey)
gid = gid_object.save_to_string(save_parents=True)
record['gid'] = gid
record = SfaRecord(dict=record)
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+from sfatables.runtime import SFATablesRules
+import sys
+from sfa.trust.credential import Credential
+from sfa.util.sfalogging import logger
+
+class CreateSliver(Method):
+ """
+ Allocate resources to a slice. This operation is expected to
+ start the allocated resources asynchornously after the operation
+ has successfully completed. Callers can check on the status of
+ the resources using SliverStatus.
+
+ @param slice_urn (string) URN of slice to allocate to
+ @param credentials ([string]) of credentials
+ @param rspec (string) rspec to allocate
+
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(str, "Slice URN"),
+ Parameter(type([str]), "List of credentials"),
+ Parameter(str, "RSpec"),
+ Parameter(type([]), "List of user information")
+ ]
+ returns = Parameter(str, "Allocated RSpec")
+
+ def __run_sfatables(self, manager, rules, hrn, origin_hrn, rspec):
+ if rules.sorted_rule_list:
+ contexts = rules.contexts
+ request_context = manager.fetch_context(hrn, origin_hrn, contexts)
+ rules.set_context(request_context)
+ newrspec = rules.apply(rspec)
+ else:
+ newrspec = rspec
+ return newrspec
+
+
+ def call(self, slice_xrn, creds, rspec, users):
+ hrn, type = urn_to_hrn(slice_xrn)
+
+ self.api.logger.info("interface: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, hrn, self.name))
+
+ # Find the valid credentials
+ ValidCreds = self.api.auth.checkCredentials(creds, 'createsliver', hrn)
+ origin_hrn = Credential(string=ValidCreds[0]).get_gid_caller().get_hrn()
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ rspec = self.__run_sfatables(manager, SFATablesRules('INCOMING'),
+ hrn, origin_hrn, rspec)
+
+ return manager.CreateSliver(self.api, slice_xrn, ValidCreds, rspec, users)
+ return ''
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+
+class DeleteSliver(Method):
+ """
+ Delete sliver from a slice. Callers can check on the status of
+ the resources using SliverStatus.
+
+ @param slice_urn (string) URN of slice to allocate to
+ @param credentials ([string]) of credentials
+
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(str, "Slice URN"),
+ Parameter(type([str]), "List of credentials"),
+ ]
+ returns = Parameter(bool, "Success or Failure")
+
+ def call(self, slice_xrn, creds):
+ hrn, type = urn_to_hrn(slice_xrn)
+ self.api.logger.info("interface: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, hrn, self.name))
+
+ # Find the valid credentials
+ ValidCreds = self.api.auth.checkCredentials(creds, 'deletesliver', hrn)
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.DeleteSliver(self.api, slice_xrn, ValidCreds)
+
+ return ''
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+
+
+class GetVersion(Method):
+ """
+ Returns this GENI Aggregate Manager's Version Information
+ @return version
+ """
+ interfaces = ['geni_am','registry']
+ accepts = []
+ returns = Parameter(dict, "Version information")
+
+ def call(self):
+ self.api.logger.info("interface: %s\tmethod-name: %s" % (self.api.interface, self.name))
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.GetVersion()
+ if self.api.interface in ['registry']:
+ mgr_type = self.api.config.SFA_REGISTRY_TYPE
+ manager_module = manager_base + ".slice_manager_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.GetVersion()
+
+ return {}
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter, Mixed
+from sfa.trust.credential import Credential
+from sfatables.runtime import SFATablesRules
+import sys
+import zlib
+
+class ListResources(Method):
+ """
+ Returns information about available resources or resources allocated to this slice
+ @param credential list
+ @param options dictionary
+ @return string
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(type([str]), "List of credentials"),
+ Parameter(dict, "Options")
+ ]
+ returns = Parameter(str, "List of resources")
+
+ def call(self, creds, options):
+ self.api.logger.info("interface: %s\tmethod-name: %s" % (self.api.interface, self.name))
+
+ # Find the valid credentials
+ hrn = None
+ if options.has_key('geni_slice_urn'):
+ xrn = options['geni_slice_urn']
+ hrn, _ = urn_to_hrn(xrn)
+
+ ValidCreds = self.api.auth.checkCredentials(creds, '', hrn)
+ origin_hrn = Credential(string=ValidCreds[0]).get_gid_caller().get_hrn()
+
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ rspec = manager.ListResources(self.api, ValidCreds, options)
+ outgoing_rules = SFATablesRules('OUTGOING')
+
+
+ filtered_rspec = rspec
+ if outgoing_rules.sorted_rule_list:
+ context = {'sfa':{'user':{'hrn':origin_hrn}, 'slice':{'hrn':None}}}
+ outgoing_rules.set_context(context)
+ filtered_rspec = outgoing_rules.apply(rspec)
+
+ if options.has_key('geni_compressed') and options['geni_compressed'] == True:
+ filtered_rspec = zlib.compress(rspec).encode('base64')
+
+
+ return filtered_rspec
+
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+from sfa.trust.credential import Credential
+from dateutil.parser import parse
+
+class RenewSliver(Method):
+ """
+ Renews the resources in a sliver, extending the lifetime of the slice.
+ @param slice_urn (string) URN of slice to renew
+ @param credentials ([string]) of credentials
+ @param expiration_time (string) requested time of expiration
+
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(str, "Slice URN"),
+ Parameter(type([str]), "List of credentials"),
+ Parameter(str, "Expiration time in RFC 3339 format")
+ ]
+ returns = Parameter(bool, "Success or Failure")
+
+ def call(self, slice_xrn, creds, expiration_time):
+ hrn, type = urn_to_hrn(slice_xrn)
+
+ self.api.logger.info("interface: %s\ttarget-hrn: %s\tcaller-creds: %s\tmethod-name: %s"%(self.api.interface, hrn, creds, self.name))
+
+ # Find the valid credentials
+ ValidCreds = self.api.auth.checkCredentials(creds, 'renewsliver', hrn)
+
+ # Validate that the time does not go beyond the credential's expiration time
+ requested_time = parse(expiration_time)
+ if requested_time > Credential(string=ValidCreds[0]).get_lifetime():
+ raise InsufficientRights('SliverStatus: Credential expires before requested expiration time')
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.RenewSliver(self.api, slice_xrn, ValidCreds, expiration_time)
+
+ return ''
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+from sfa.trust.credential import Credential
+
+class ResolveGENI(Method):
+ """
+ Lookup a URN and return information about the corresponding object.
+ @param urn
+
+ """
+ interfaces = ['registry']
+ accepts = [
+ Parameter(str, "URN"),
+ Parameter(type([str]), "List of credentials"),
+ ]
+ returns = Parameter(bool, "Success or Failure")
+
+ def call(self, xrn):
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['registry']:
+ mgr_type = self.api.config.SFA_REGISTRY_TYPE
+ manager_module = manager_base + ".registry_manager_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.Resolve(self.api, xrn, '')
+
+ return {}
\ No newline at end of file
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+
+
+class Shutdown(Method):
+ """
+ Perform an emergency shut down of a sliver. This operation is intended for administrative use.
+ The sliver is shut down but remains available for further forensics.
+
+ @param slice_urn (string) URN of slice to renew
+ @param credentials ([string]) of credentials
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(str, "Slice URN"),
+ Parameter(type([str]), "List of credentials"),
+ ]
+ returns = Parameter(bool, "Success or Failure")
+
+ def call(self, slice_xrn, creds):
+ hrn, type = urn_to_hrn(slice_xrn)
+
+ self.api.logger.info("interface: %s\ttarget-hrn: %s\tcaller-creds: %s\tmethod-name: %s"%(self.api.interface, hrn, creds, self.name))
+
+ # Find the valid credentials
+ ValidCreds = self.api.auth.checkCredentials(creds, 'shutdown', hrn)
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.Shutdown(self.api, slice_xrn, ValidCreds)
+
+ return ''
+
--- /dev/null
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter
+
+class SliverStatus(Method):
+ """
+ Get the status of a sliver
+
+ @param slice_urn (string) URN of slice to allocate to
+
+ """
+ interfaces = ['geni_am']
+ accepts = [
+ Parameter(str, "Slice URN"),
+ ]
+ returns = Parameter(bool, "Success or Failure")
+
+ def call(self, slice_xrn, creds):
+ hrn, type = urn_to_hrn(slice_xrn)
+
+ ValidCreds = self.api.auth.checkCredentials(creds, 'sliverstatus', hrn)
+
+ self.api.logger.info("interface: %s\ttarget-hrn: %s\tmethod-name: %s"%(self.api.interface, hrn, self.name))
+
+ manager_base = 'sfa.managers'
+
+ if self.api.interface in ['geni_am']:
+ mgr_type = self.api.config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ manager = __import__(manager_module, fromlist=[manager_base])
+ return manager.SliverStatus(self.api, slice_xrn, ValidCreds)
+
+ return ''
+
--- /dev/null
+### $Id: get_slices.py 14387 2009-07-08 18:19:11Z faiyaza $
+### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/methods/get_aggregates.py $
+from types import StringTypes
+from sfa.util.faults import *
+from sfa.util.namespace import *
+from sfa.util.method import Method
+from sfa.util.parameter import Parameter, Mixed
+from sfa.trust.auth import Auth
+from sfa.server.aggregate import Aggregates
+
+class get_geni_aggregates(Method):
+ """
+ Get a list of connection information for all known GENI aggregates.
+
+ @param cred credential string specifying the rights of the caller
+ @param a Human readable name (hrn or urn), or list of hrns or None
+ @return list of dictionaries with aggregate information.
+ """
+
+ interfaces = ['registry', 'aggregate', 'slicemgr']
+
+ accepts = [
+ Parameter(str, "Credential string"),
+ Mixed(Parameter(str, "Human readable name (hrn or urn)"),
+ Parameter(None, "hrn not specified"))
+ ]
+
+
+ returns = [Parameter(dict, "Aggregate interface information")]
+
+ def call(self, cred, xrn = None):
+ hrn, type = urn_to_hrn(xrn)
+ self.api.auth.check(cred, 'list')
+
+ geni_aggs = Aggregates(self.api, '/etc/sfa/geni_aggregates.xml')
+
+ geni_aggs = geni_aggs.interfaces.values()
+
+ hrn_list = []
+ if hrn:
+ if isinstance(hrn, StringTypes):
+ hrn_list = [hrn]
+ elif isinstance(hrn, list):
+ hrn_list = hrn
+
+ if not hrn_list:
+ interfaces = geni_aggs
+ else:
+ interfaces = [interface for interface in geni_aggs if interface['hrn'] in hrn_list]
+
+
+ # Remove Aggregate's default sfa-aggregate
+ interfaces = interfaces[:-1]
+
+
+ # Add urns
+ for interface in interfaces:
+ interface['urn'] = hrn_to_urn(interface['hrn'], 'authority')
+
+ return interfaces
--- /dev/null
+#
+# SFA XML-RPC and SOAP interfaces
+#
+### $Id: api.py 17793 2010-04-26 21:40:57Z tmack $
+### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/plc/api.py $
+#
+
+import sys
+import os
+import traceback
+import string
+import xmlrpclib
+from sfa.trust.auth import Auth
+from sfa.util.config import *
+from sfa.util.faults import *
+from sfa.util.debug import *
+from sfa.trust.rights import *
+from sfa.trust.credential import *
+from sfa.trust.certificate import *
+from sfa.util.namespace import *
+from sfa.util.api import *
+from sfa.util.nodemanager import NodeManager
+from sfa.util.sfalogging import *
+from collections import defaultdict
+
+
+class RecordInfo():
+
+ shell = None
+ auth = None
+
+ # pl records
+ sites = {}
+ slices = {}
+ persons = {}
+ nodes = {}
+ keys = {}
+
+ # sfa records
+ sfa_authorities = {}
+ sfa_slices = {}
+ sfa_users = {}
+ sfa_nodes = {}
+
+ records = []
+
+ def __init__(self, api, records):
+ self.api = api
+ self.shell = api.plshell
+ self.auth = api.plauth
+
+ site_ids = []
+ slice_ids = []
+ person_ids = []
+ node_ids = []
+
+ # put records into groups based on types
+ for record in records:
+ pointer = record['pointer']
+ if record['type'] == 'authority':
+ self.sfa_authorities[pointer] = record
+ self.records.append(record)
+ site_ids.append(record['pointer'])
+ elif record['type'] == 'slice':
+ self.sfa_slices[pointer] = record
+ self.records.append(record)
+ slice_ids.append(record['pointer'])
+ elif record['type'] == 'user':
+ self.sfa_users[pointer] = record
+ self.records.append(record)
+ person_ids.append(record['pointer'])
+ elif record['type'] == 'node':
+ self.sfa_nodes[pointer] = record
+ self.records.append(record)
+ node_ids.append(record['pointer'])
+
+ # get pl info for these records
+ self.update_pl_sites(site_ids)
+ self.update_pl_slices(slice_ids)
+ self.update_pl_persons(person_ids)
+ self.update_pl_nodes(node_ids)
+
+ site_ids = []
+ slice_ids = []
+ person_ids = []
+ node_ids = []
+ # now get pl records for all ids associated with
+ # these records
+ for record in records:
+ if 'site_id' in record:
+ site_ids.append(record['site_id'])
+ if 'site_ids' in records:
+ site_ids.extend(record['site_ids'])
+ if 'person_ids' in record:
+ person_ids.extend(record['person_ids'])
+ if 'slice_ids' in record:
+ slice_ids.extend(record['slice_ids'])
+ if 'node_ids' in record:
+ node_ids.extend(record['node_ids'])
+
+ # get pl info for these records
+ self.update_pl_sites(site_ids)
+ self.update_pl_slices(slice_ids)
+ self.update_pl_persons(person_ids)
+ self.update_pl_nodes(node_ids)
+
+ # convert pl ids to hrns
+ self.update_hrns()
+
+ # update sfa info
+ self.update_sfa_info(person_ids)
+
+ def update_pl_sites(self, site_ids):
+ """
+ Update site records with PL info
+ """
+ if not site_ids:
+ return
+ sites = self.shell.GetSites(self.auth, site_ids)
+ for site in sites:
+ site_id = site['site_id']
+ self.sites[site_id] = site
+ if site_id in self.sfa_authorities:
+ self.sfa_authorities[site_id].update(site)
+
+ def update_pl_slices(self, slice_ids):
+ """
+ Update slice records with PL info
+ """
+ if not slice_ids:
+ return
+ slices = self.shell.GetSlices(self.auth, slice_ids)
+ for slice in slices:
+ slice_id = slice['slice_id']
+ self.slices[slice_id] = slice
+ if slice_id in self.sfa_slices:
+ self.sfa_slices[slice_id].update(slice)
+
+ def update_pl_persons(self, person_ids):
+ """
+ Update person records with PL info
+ """
+ key_ids = []
+ if not person_ids:
+ return
+ persons = self.shell.GetPersons(self.auth, person_ids)
+ for person in persons:
+ person_id = person['person_id']
+ self.persons[person_id] = person
+ key_ids.extend(person['key_ids'])
+ if person_id in self.sfa_users:
+ self.sfa_users[person_id].update(person)
+ self.update_pl_keys(key_ids)
+
+ def update_pl_keys(self, key_ids):
+ """
+ Update user records with PL public key info
+ """
+ if not key_ids:
+ return
+ keys = self.shell.GetKeys(self.auth, key_ids)
+ for key in keys:
+ person_id = key['person_id']
+ self.keys[key['key_id']] = key
+ if person_id in self.sfa_users:
+ person = self.sfa_users[person_id]
+ if not 'keys' in person:
+ person['keys'] = [key['key']]
+ else:
+ person['keys'].append(key['key'])
+
+ def update_pl_nodes(self, node_ids):
+ """
+ Update node records with PL info
+ """
+ if not node_ids:
+ return
+ nodes = self.shell.GetNodes(self.auth, node_ids)
+ for node in nodes:
+ node_id = node['node_id']
+ self.nodes[node['node_id']] = node
+ if node_id in self.sfa_nodes:
+ self.sfa_nodes[node_id].update(node)
+
+
+ def update_hrns(self):
+ """
+ Convert pl ids to hrns
+ """
+ for record in self.records:
+ # get all necessary data
+ type = record['type']
+ pointer = record['pointer']
+ auth_hrn = self.api.hrn
+ login_base = ''
+ if pointer == -1:
+ continue
+
+ if 'site_id' in record:
+ site = self.sites[record['site_id']]
+ login_base = site['login_base']
+ record['site'] = ".".join([auth_hrn, login_base])
+ if 'person_ids' in record:
+ emails = [self.persons[person_id]['email'] for person_id in record['person_ids'] \
+ if person_id in self.persons]
+ usernames = [email.split('@')[0] for email in emails]
+ person_hrns = [".".join([auth_hrn, login_base, username]) for username in usernames]
+ record['persons'] = person_hrns
+ if 'slice_ids' in record:
+ slicenames = [self.slices[slice_id]['name'] for slice_id in record['slice_ids'] \
+ if slice_id in self.slices]
+ slice_hrns = [slicename_to_hrn(auth_hrn, slicename) for slicename in slicenames]
+ record['slices'] = slice_hrns
+ if 'node_ids' in record:
+ hostnames = [self.nodes[node_id]['hostname'] for node_id in record['node_ids'] \
+ if node_id in self.nodes]
+ node_hrns = [hostname_to_hrn(auth_hrn, login_base, hostname) for hostname in hostnames]
+ record['nodes'] = node_hrns
+ if 'site_ids' in record:
+ login_bases = [self.sites[site_id]['login_base'] for site_id in record['site_ids'] \
+ if site_id in self.sites]
+ site_hrns = [".".join([auth_hrn, lbase]) for lbase in login_bases]
+ record['sites'] = site_hrns
+
+ def update_sfa_info(self, person_ids):
+ from sfa.util.table import SfaTable
+ table = SfaTable()
+ persons = table.find({'type': 'user', 'pointer': person_ids})
+ # create a hrns keyed on the sfa record's pointer.
+ # Its possible for multiple records to have the same pointer so
+ # the dict's value will be a list of hrns.
+ person_dict = defaultdict(list)
+ for person in persons:
+ person_dict[person['pointer']].append(person['hrn'])
+
+ def startswith(prefix, values):
+ return [value for value in values if value.startswith(prefix)]
+
+ for record in self.records:
+ authority = record['authority']
+ if record['pointer'] == -1:
+ continue
+
+ if record['type'] == 'slice':
+ # all slice users are researchers
+ record['PI'] = []
+ record['researchers'] = []
+ for person_id in record['person_ids']:
+ record['researchers'].extend(person_dict[person_id])
+ # also add the pis at the slice's site
+ site = self.sites[record['site_id']]
+ for person_id in site['person_ids']:
+ person = self.persons[person_id]
+ if 'pi' in person['roles']:
+ # PLCAPI doesn't support per site roles
+ # (a pi has the pi role at every site he belongs to).
+ # We shouldnt allow this in SFA
+ record['PI'].extend(startswith(authority, person_dict[person_id]))
+
+ elif record['type'] == 'authority':
+ record['PI'] = []
+ record['operator'] = []
+ record['owner'] = []
+ for person_id in record['person_ids']:
+ person = self.persons[person_id]
+ if 'pi' in person['roles']:
+ # only get PI's at this site
+ record['PI'].extend(startswith(record['hrn'], person_dict[person_id]))
+ if 'tech' in person['roles']:
+ # only get PI's at this site
+ record['operator'].extend(startswith(record['hrn'], person_dict[person_id]))
+ if 'admin' in person['roles']:
+ record['owner'].extend(startswith(record['hrn'], person_dict[person_id]))
+
+ elif record['type'] == 'node':
+ record['dns'] = record['hostname']
+
+ elif record['type'] == 'user':
+ record['email'] = record['email']
+
+
+
+
+
+ def get_records(self):
+ return self.records
+
+
+class SfaAPI(BaseAPI):
+
+ # flat list of method names
+ import sfa.methods
+ methods = sfa.methods.all
+
+ def __init__(self, config = "/etc/sfa/sfa_config.py", encoding = "utf-8",
+ methods='sfa.methods', peer_cert = None, interface = None,
+ key_file = None, cert_file = None, cache = None):
+ BaseAPI.__init__(self, config=config, encoding=encoding, methods=methods, \
+ peer_cert=peer_cert, interface=interface, key_file=key_file, \
+ cert_file=cert_file, cache=cache)
+
+ self.encoding = encoding
+
+ from sfa.util.table import SfaTable
+ self.SfaTable = SfaTable
+ # Better just be documenting the API
+ if config is None:
+ return
+
+ # Load configuration
+ self.config = Config(config)
+ self.auth = Auth(peer_cert)
+ self.interface = interface
+ self.key_file = key_file
+ self.key = Keypair(filename=self.key_file)
+ self.cert_file = cert_file
+ self.cert = Certificate(filename=self.cert_file)
+ self.credential = None
+ # Initialize the PLC shell only if SFA wraps a myPLC
+ rspec_type = self.config.get_aggregate_type()
+ if (rspec_type == 'pl' or rspec_type == 'vini'):
+ self.plshell = self.getPLCShell()
+ self.plshell_version = "4.3"
+
+ self.hrn = self.config.SFA_INTERFACE_HRN
+ self.time_format = "%Y-%m-%d %H:%M:%S"
+ self.logger=get_sfa_logger()
+
+ def getPLCShell(self):
+ self.plauth = {'Username': self.config.SFA_PLC_USER,
+ 'AuthMethod': 'password',
+ 'AuthString': self.config.SFA_PLC_PASSWORD}
+
+ self.plshell_type = 'xmlrpc'
+ # connect via xmlrpc
+ url = self.config.SFA_PLC_URL
+ shell = xmlrpclib.Server(url, verbose = 0, allow_none = True)
+ return shell
+
+ def getCredential(self):
+ if self.interface in ['registry']:
+ return self.getCredentialFromLocalRegistry()
+ else:
+ return self.getCredentialFromRegistry()
+
+ def getCredentialFromRegistry(self):
+ """
+ Get our credential from a remote registry
+ """
+ type = 'authority'
+ path = self.config.SFA_DATA_DIR
+ filename = ".".join([self.interface, self.hrn, type, "cred"])
+ cred_filename = path + os.sep + filename
+ try:
+ credential = Credential(filename = cred_filename)
+ return credential.save_to_string(save_parents=True)
+ except IOError:
+ from sfa.server.registry import Registries
+ registries = Registries(self)
+ registry = registries[self.hrn]
+ cert_string=self.cert.save_to_string(save_parents=True)
+ # get self credential
+ self_cred = registry.get_self_credential(cert_string, type, self.hrn)
+ # get credential
+ cred = registry.get_credential(self_cred, type, self.hrn)
+
+ # save cred to file
+ Credential(string=cred).save_to_file(cred_filename, save_parents=True)
+ return cred
+
+ def getCredentialFromLocalRegistry(self):
+ """
+ Get our current credential directly from the local registry.
+ """
+
+ hrn = self.hrn
+ auth_hrn = self.auth.get_authority(hrn)
+
+ # is this a root or sub authority
+ if not auth_hrn or hrn == self.config.SFA_INTERFACE_HRN:
+ auth_hrn = hrn
+ auth_info = self.auth.get_auth_info(auth_hrn)
+ table = self.SfaTable()
+ records = table.findObjects(hrn)
+ if not records:
+ raise RecordNotFound
+ record = records[0]
+ type = record['type']
+ object_gid = record.get_gid_object()
+ new_cred = Credential(subject = object_gid.get_subject())
+ new_cred.set_gid_caller(object_gid)
+ new_cred.set_gid_object(object_gid)
+ new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
+ new_cred.set_pubkey(object_gid.get_pubkey())
+ r1 = determine_rights(type, hrn)
+ new_cred.set_privileges(r1)
+
+ auth_kind = "authority,ma,sa"
+
+ new_cred.set_parent(self.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind))
+
+ new_cred.encode()
+ new_cred.sign()
+
+ return new_cred.save_to_string(save_parents=True)
+
+
+ def loadCredential (self):
+ """
+ Attempt to load credential from file if it exists. If it doesnt get
+ credential from registry.
+ """
+
+ # see if this file exists
+ # XX This is really the aggregate's credential. Using this is easier than getting
+ # the registry's credential from iteslf (ssl errors).
+ ma_cred_filename = self.config.SFA_DATA_DIR + os.sep + self.interface + self.hrn + ".ma.cred"
+ try:
+ self.credential = Credential(filename = ma_cred_filename)
+ except IOError:
+ self.credential = self.getCredentialFromRegistry()
+
+ ##
+ # Convert SFA fields to PLC fields for use when registering up updating
+ # registry record in the PLC database
+ #
+ # @param type type of record (user, slice, ...)
+ # @param hrn human readable name
+ # @param sfa_fields dictionary of SFA fields
+ # @param pl_fields dictionary of PLC fields (output)
+
+ def sfa_fields_to_pl_fields(self, type, hrn, record):
+
+ def convert_ints(tmpdict, int_fields):
+ for field in int_fields:
+ if field in tmpdict:
+ tmpdict[field] = int(tmpdict[field])
+
+ pl_record = {}
+ #for field in record:
+ # pl_record[field] = record[field]
+
+ if type == "slice":
+ if not "instantiation" in pl_record:
+ pl_record["instantiation"] = "plc-instantiated"
+ pl_record["name"] = hrn_to_pl_slicename(hrn)
+ if "url" in record:
+ pl_record["url"] = record["url"]
+ if "description" in record:
+ pl_record["description"] = record["description"]
+ if "expires" in record:
+ pl_record["expires"] = int(record["expires"])
+
+ elif type == "node":
+ if not "hostname" in pl_record:
+ if not "hostname" in record:
+ raise MissingSfaInfo("hostname")
+ pl_record["hostname"] = record["hostname"]
+ if not "model" in pl_record:
+ pl_record["model"] = "geni"
+
+ elif type == "authority":
+ pl_record["login_base"] = hrn_to_pl_login_base(hrn)
+
+ if not "name" in pl_record:
+ pl_record["name"] = hrn
+
+ if not "abbreviated_name" in pl_record:
+ pl_record["abbreviated_name"] = hrn
+
+ if not "enabled" in pl_record:
+ pl_record["enabled"] = True
+
+ if not "is_public" in pl_record:
+ pl_record["is_public"] = True
+
+ return pl_record
+
+
+ def fill_record_info(self, records):
+ """
+ Given a SFA record, fill in the PLC specific and SFA specific
+ fields in the record.
+ """
+ if not isinstance(records, list):
+ records = [records]
+
+ record_info = RecordInfo(self, records)
+ return record_info.get_records()
+
+ def update_membership_list(self, oldRecord, record, listName, addFunc, delFunc):
+ # get a list of the HRNs tht are members of the old and new records
+ if oldRecord:
+ oldList = oldRecord.get(listName, [])
+ else:
+ oldList = []
+ newList = record.get(listName, [])
+
+ # if the lists are the same, then we don't have to update anything
+ if (oldList == newList):
+ return
+
+ # build a list of the new person ids, by looking up each person to get
+ # their pointer
+ newIdList = []
+ table = self.SfaTable()
+ records = table.find({'type': 'user', 'hrn': newList})
+ for rec in records:
+ newIdList.append(rec['pointer'])
+
+ # build a list of the old person ids from the person_ids field
+ if oldRecord:
+ oldIdList = oldRecord.get("person_ids", [])
+ containerId = oldRecord.get_pointer()
+ else:
+ # if oldRecord==None, then we are doing a Register, instead of an
+ # update.
+ oldIdList = []
+ containerId = record.get_pointer()
+
+ # add people who are in the new list, but not the oldList
+ for personId in newIdList:
+ if not (personId in oldIdList):
+ addFunc(self.plauth, personId, containerId)
+
+ # remove people who are in the old list, but not the new list
+ for personId in oldIdList:
+ if not (personId in newIdList):
+ delFunc(self.plauth, personId, containerId)
+
+ def update_membership(self, oldRecord, record):
+ if record.type == "slice":
+ self.update_membership_list(oldRecord, record, 'researcher',
+ self.plshell.AddPersonToSlice,
+ self.plshell.DeletePersonFromSlice)
+ elif record.type == "authority":
+ # xxx TODO
+ pass
+
+
+
+class ComponentAPI(BaseAPI):
+
+ def __init__(self, config = "/etc/sfa/sfa_config.py", encoding = "utf-8", methods='sfa.methods',
+ peer_cert = None, interface = None, key_file = None, cert_file = None):
+
+ BaseAPI.__init__(self, config=config, encoding=encoding, methods=methods, peer_cert=peer_cert,
+ interface=interface, key_file=key_file, cert_file=cert_file)
+ self.encoding = encoding
+
+ # Better just be documenting the API
+ if config is None:
+ return
+
+ self.nodemanager = NodeManager(self.config)
+
+ def sliver_exists(self):
+ sliver_dict = self.nodemanager.GetXIDs()
+ if slicename in sliver_dict.keys():
+ return True
+ else:
+ return False
'AuthMethod': 'password',
'AuthString': self.config.SFA_PLC_PASSWORD}
+
self.plshell_type = 'xmlrpc'
# connect via xmlrpc
url = self.config.SFA_PLC_URL
new_cred = Credential(subject = object_gid.get_subject())
new_cred.set_gid_caller(object_gid)
new_cred.set_gid_object(object_gid)
- new_cred.set_issuer(key=auth_info.get_pkey_object(), subject=auth_hrn)
- new_cred.set_pubkey(object_gid.get_pubkey())
+ new_cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename())
+
r1 = determine_rights(type, hrn)
new_cred.set_privileges(r1)
AuthHierarchy = sfaImporter.AuthHierarchy
TrustedRoots = sfaImporter.TrustedRoots
table = SfaTable()
+
if not table.exists():
- table.create()
+ table.create()
# create root authority
sfaImporter.create_top_level_auth_records(root_auth)
slices_dict = {}
for slice in slices:
slices_dict[slice['slice_id']] = slice
-
# start importing
for site in sites:
site_hrn = interface_hrn + "." + site['login_base']
+ print "Importing site: %s" % site_hrn
+
# import if hrn is not in list of existing hrns or if the hrn exists
# but its not a site record
if site_hrn not in existing_hrns or \
plc_auth = self.plc_auth
sitename = site['login_base']
sitename = cleanup_string(sitename)
+ print 'importing site %s' % sitename
hrn = parent_hrn + "." + sitename
urn = hrn_to_urn(hrn, 'authority')
# Hardcode 'internet2' into the hrn for sites hosting
return sfa_peer
- def verify_site(self, registry, credential, slice_hrn, peer, sfa_peer):
+ def verify_site(self, registry, credential, slice_hrn, peer, sfa_peer, reg_objects=None):
authority = get_authority(slice_hrn)
authority_urn = hrn_to_urn(authority, 'authority')
- site_records = registry.resolve(credential, authority_urn)
+
+ if reg_objects:
+ site = reg_objects['site']
+ else:
+ site_records = registry.resolve(credential, authority_urn)
+ site = {}
+ for site_record in site_records:
+ if site_record['type'] == 'authority':
+ site = site_record
+ if not site:
+ raise RecordNotFound(authority)
- site = {}
- for site_record in site_records:
- if site_record['type'] == 'authority':
- site = site_record
- if not site:
- raise RecordNotFound(authority)
remote_site_id = site.pop('site_id')
login_base = get_leaf(authority)
sites = self.api.plshell.GetSites(self.api.plauth, login_base)
+
if not sites:
site_id = self.api.plshell.AddSite(self.api.plauth, site)
if peer:
self.api.plshell.BindObjectToPeer(self.api.plauth, 'site', site_id, peer, remote_site_id)
# mark this site as an sfa peer record
- if sfa_peer:
+ if sfa_peer and not reg_objects:
peer_dict = {'type': 'authority', 'hrn': authority, 'peer_authority': sfa_peer, 'pointer': site_id}
registry.register_peer_object(credential, peer_dict)
else:
site_id = sites[0]['site_id']
remote_site_id = sites[0]['peer_site_id']
+
old_site = sites[0]
- #the site is alredy on the remote agg. Let us update(e.g. max_slices field) it with the latest info.
- self.sync_site(old_site, site, peer)
+ #the site is already on the remote agg. Let us update(e.g. max_slices field) it with the latest info.
+ self.sync_site(old_site, site, peer)
return (site_id, remote_site_id)
- def verify_slice(self, registry, credential, slice_hrn, site_id, remote_site_id, peer, sfa_peer):
+ def verify_slice(self, registry, credential, slice_hrn, site_id, remote_site_id, peer, sfa_peer, reg_objects=None):
slice = {}
slice_record = None
authority = get_authority(slice_hrn)
- slice_records = registry.resolve(credential, slice_hrn)
- for record in slice_records:
- if record['type'] in ['slice']:
- slice_record = record
- if not slice_record:
- raise RecordNotFound(hrn)
+ if reg_objects:
+ slice_record = reg_objects['slice_record']
+ else:
+ slice_records = registry.resolve(credential, slice_hrn)
+
+ for record in slice_records:
+ if record['type'] in ['slice']:
+ slice_record = record
+ if not slice_record:
+ raise RecordNotFound(hrn)
+
+
slicename = hrn_to_pl_slicename(slice_hrn)
parts = slicename.split("_")
login_base = parts[0]
self.sync_slice(slice, slice_record, peer)
slice['peer_slice_id'] = slice_record['pointer']
- self.verify_persons(registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer)
+ self.verify_persons(registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer, reg_objects)
return slice
- def verify_persons(self, registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer):
+ def verify_persons(self, registry, credential, slice_record, site_id, remote_site_id, peer, sfa_peer, reg_objects=None):
# get the list of valid slice users from the registry and make
# sure they are added to the slice
slicename = hrn_to_pl_slicename(slice_record['hrn'])
- researchers = slice_record.get('researcher', [])
+ if reg_objects:
+ researchers = reg_objects['users'].keys()
+ else:
+ researchers = slice_record.get('researcher', [])
for researcher in researchers:
- person_record = {}
- person_records = registry.resolve(credential, researcher)
- for record in person_records:
- if record['type'] in ['user'] and record['enabled']:
- person_record = record
- if not person_record:
- return 1
- person_dict = person_record
+ if reg_objects:
+ person_dict = reg_objects['users'][researcher]
+ else:
+ person_records = registry.resolve(credential, researcher)
+ for record in person_records:
+ if record['type'] in ['user'] and record['enabled']:
+ person_record = record
+ if not person_record:
+ return 1
+ person_dict = person_record
+
local_person=False
if peer:
peer_id = self.api.plshell.GetPeers(self.api.plauth, {'shortname': peer}, ['peer_id'])[0]['peer_id']
persons = self.api.plshell.GetPersons(self.api.plauth, {'email': [person_dict['email']], 'peer_id': peer_id}, ['person_id', 'key_ids'])
- if not persons:
- persons = self.api.plshell.GetPersons(self.api.plauth, [person_dict['email']], ['person_id', 'key_ids'])
- if persons:
- local_person=True
-
+ if not persons:
+ persons = self.api.plshell.GetPersons(self.api.plauth, [person_dict['email']], ['person_id', 'key_ids'])
+ if persons:
+ local_person=True
+
else:
persons = self.api.plshell.GetPersons(self.api.plauth, [person_dict['email']], ['person_id', 'key_ids'])
import sfa.util.xmlrpcprotocol as xmlrpcprotocol
import sfa.util.soapprotocol as soapprotocol
-
+
# GeniLight client support is optional
try:
from egeni.geniLight_client import *
return peer_gids
trusted_certs_dir = self.api.config.get_trustedroots_dir()
for new_hrn in new_hrns:
+ if not new_hrn:
+ continue
# the gid for this interface should already be installed
if new_hrn == self.api.config.SFA_INTERFACE_HRN:
continue
# make sure the required fields are present and not null
if not all([interface.get(key) for key in required_fields]):
continue
-
+
hrn, address, port = interface['hrn'], interface['addr'], interface['port']
url = 'http://%(address)s:%(port)s' % locals()
+
# check which client we should use
# sfa.util.xmlrpcprotocol is default
client_type = 'xmlrpcprotocol'
BaseApi.__init__(self, encoding)
if trustedRootsDir:
self.trusted_cert_list = TrustedRootList(trustedRootsDir).get_list()
+ self.trusted_cert_file_list = TrustedRootList(trustedRootsDir).get_file_list()
else:
self.trusted_cert_list = None
def validateCred(self, cred):
if self.trusted_cert_list:
- cred.verify_chain(self.trusted_cert_list)
- caller_gid = cred.get_gid_caller()
- object_gid = cred.get_gid_object()
- if caller_gid:
- caller_gid.verify_chain(self.trusted_cert_list)
- if object_gid:
- object_gid.verify_chain(self.trusted_cert_list)
+ cred.verify(self.trusted_cert_file_list)
def authenticateGid(self, gidStr, argList, requestHash):
gid = GID(string = gidStr)
aggregate_port=12346
slicemgr_port=12347
component_port=12346
-
+geni_am_port=12348
import os, os.path
import sys
from optparse import OptionParser
try: manager = __import__(manager_module, fromlist=[manager_base])
except: manager = None
if manager and hasattr(manager, 'init_server'):
- manager.init_server()
+ manager.init_server()
+ if options.gam:
+ mgr_type = config.SFA_GENI_AGGREGATE_TYPE
+ manager_module = manager_base + ".geni_am_%s" % mgr_type
+ try: manager = __import__(manager_module, fromlist=[manager_base])
+ except: manager = None
+ if manager and hasattr(manager, 'init_server'):
+ manager.init_server()
def sync_interfaces(server_key_file, server_cert_file):
help="run aggregate manager", default=False)
parser.add_option("-c", "--component", dest="cm", action="store_true",
help="run component server", default=False)
+ parser.add_option("-g", "--geniam", dest="gam", action="store_true",
+ help="run GENI aggregate manager", default=False)
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
help="verbose mode", default=False)
parser.add_option("-d", "--daemon", dest="daemon", action="store_true",
c = Component("", component_port, server_key_file, server_cert_file)
c.start()
+ # start GENI aggregate manager
+ if (options.gam):
+ from sfa.server.geni_aggregate import GENIAggregate
+ g = GENIAggregate("", geni_am_port, server_key_file, server_cert_file)
+ g.start()
+
if __name__ == "__main__":
main()
### $URL$
#
-import time
from sfa.trust.credential import Credential
from sfa.trust.trustedroot import TrustedRootList
-from sfa.trust.rights import RightList
from sfa.util.faults import *
from sfa.trust.hierarchy import Hierarchy
from sfa.util.config import *
from sfa.util.namespace import *
-from sfa.trust.gid import GID
from sfa.util.sfaticket import *
+from sfa.util.sfalogging import logger
+
+import sys
class Auth:
"""
def load_trusted_certs(self):
self.trusted_cert_list = TrustedRootList(self.config.get_trustedroots_dir()).get_list()
+ self.trusted_cert_file_list = TrustedRootList(self.config.get_trustedroots_dir()).get_file_list()
+
+
+
+ def checkCredentials(self, creds, operation, hrn = None):
+ valid = []
+ for cred in creds:
+ try:
+ self.check(cred, operation, hrn)
+ valid.append(cred)
+ except:
+ error = sys.exc_info()[:2]
+ continue
+
+ if not len(valid):
+ raise InsufficientRights('Access denied: %s -- %s' % (error[0],error[1]))
+
+ return valid
+
def check(self, cred, operation, hrn = None):
"""
raise InsufficientRights(operation)
if self.trusted_cert_list:
- self.client_cred.verify_chain(self.trusted_cert_list)
- if self.client_gid:
- self.client_gid.verify_chain(self.trusted_cert_list)
- if self.object_gid:
- self.object_gid.verify_chain(self.trusted_cert_list)
+ self.client_cred.verify(self.trusted_cert_file_list)
else:
raise MissingTrustedRoots(self.config.get_trustedroots_dir())
-
+
# Make sure the credential's target matches the specified hrn.
# This check does not apply to trusted peers
trusted_peers = [gid.get_hrn() for gid in self.trusted_cert_list]
def validateCred(self, cred):
if self.trusted_cert_list:
- cred.verify_chain(self.trusted_cert_list)
- caller_gid = cred.get_gid_caller()
- object_gid = cred.get_gid_object()
- if caller_gid:
- caller_gid.verify_chain(self.trusted_cert_list)
- if object_gid:
- object_gid.verify_chain(self.trusted_cert_list)
+ cred.verify(self.trusted_cert_file_list)
def authenticateGid(self, gidStr, argList, requestHash=None):
gid = GID(string = gidStr)
rl = RightList()
type = record['type']
+
if type=="slice":
researchers = record.get("researcher", [])
pis = record.get("PI", [])
pis = record.get("PI", [])
operators = record.get("operator", [])
if (caller_hrn == self.config.SFA_INTERFACE_HRN):
- rl.add("authority,sa,ma",)
+ rl.add("authority")
+ rl.add("sa")
+ rl.add("ma")
if (caller_hrn in pis):
- rl.add("authority,sa")
+ rl.add("authority")
+ rl.add("sa")
if (caller_hrn in operators):
- rl.add("authority,ma")
+ rl.add("authority")
+ rl.add("ma")
elif type == "user":
rl.add("refresh")
from OpenSSL import crypto
import M2Crypto
from M2Crypto import X509
-from M2Crypto import EVP
-
+from tempfile import mkstemp
+from sfa.util.sfalogging import logger
+from sfa.util.namespace import urn_to_hrn
from sfa.util.faults import *
def convert_public_key(key):
if not os.path.isfile(keyconvert_path):
raise IOError, "Could not find keyconvert in %s" % keyconvert_path
- # we can only convert rsa keys
+ # we can only convert rsa keys
if "ssh-dss" in key:
return None
-
+
(ssh_f, ssh_fn) = tempfile.mkstemp()
ssl_fn = tempfile.mktemp()
os.write(ssh_f, key)
cmd = keyconvert_path + " " + ssh_fn + " " + ssl_fn
os.system(cmd)
-
+
# this check leaves the temporary file containing the public key so
# that it can be expected to see why it failed.
# TODO: for production, cleanup the temporary files
if not os.path.exists(ssl_fn):
return None
-
+
k = Keypair()
try:
k.load_pubkey_from_file(ssl_fn)
# may represent only a public key (this usage is consistent with OpenSSL).
class Keypair:
- key = None # public/private keypair
- m2key = None # public key (m2crypto format)
-
- ##
- # Creates a Keypair object
- # @param create If create==True, creates a new public/private key and
- # stores it in the object
- # @param string If string!=None, load the keypair from the string (PEM)
- # @param filename If filename!=None, load the keypair from the file
-
- def __init__(self, create=False, string=None, filename=None):
- if create:
- self.create()
- if string:
- self.load_from_string(string)
- if filename:
- self.load_from_file(filename)
-
- ##
- # Create a RSA public/private key pair and store it inside the keypair object
-
- def create(self):
- self.key = crypto.PKey()
- self.key.generate_key(crypto.TYPE_RSA, 1024)
-
- ##
- # Save the private key to a file
- # @param filename name of file to store the keypair in
-
- def save_to_file(self, filename):
- open(filename, 'w').write(self.as_pem())
-
- ##
- # Load the private key from a file. Implicity the private key includes the public key.
-
- def load_from_file(self, filename):
- buffer = open(filename, 'r').read()
- self.load_from_string(buffer)
-
- ##
- # Load the private key from a string. Implicitly the private key includes the public key.
-
- def load_from_string(self, string):
- self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, string)
- self.m2key = M2Crypto.EVP.load_key_string(string)
-
- ##
- # Load the public key from a string. No private key is loaded.
-
- def load_pubkey_from_file(self, filename):
- # load the m2 public key
- m2rsakey = M2Crypto.RSA.load_pub_key(filename)
- self.m2key = M2Crypto.EVP.PKey()
- self.m2key.assign_rsa(m2rsakey)
-
- # create an m2 x509 cert
- m2name = M2Crypto.X509.X509_Name()
- m2name.add_entry_by_txt(field="CN", type=0x1001, entry="junk", len=-1, loc=-1, set=0)
- m2x509 = M2Crypto.X509.X509()
- m2x509.set_pubkey(self.m2key)
- m2x509.set_serial_number(0)
- m2x509.set_issuer_name(m2name)
- m2x509.set_subject_name(m2name)
- ASN1 = M2Crypto.ASN1.ASN1_UTCTIME()
- ASN1.set_time(500)
- m2x509.set_not_before(ASN1)
- m2x509.set_not_after(ASN1)
- junk_key = Keypair(create=True)
- m2x509.sign(pkey=junk_key.get_m2_pkey(), md="sha1")
-
- # convert the m2 x509 cert to a pyopenssl x509
- m2pem = m2x509.as_pem()
- pyx509 = crypto.load_certificate(crypto.FILETYPE_PEM, m2pem)
-
- # get the pyopenssl pkey from the pyopenssl x509
- self.key = pyx509.get_pubkey()
-
- ##
- # Load the public key from a string. No private key is loaded.
-
- def load_pubkey_from_string(self, string):
- (f, fn) = tempfile.mkstemp()
- os.write(f, string)
- os.close(f)
- self.load_pubkey_from_file(fn)
- os.remove(fn)
-
- ##
- # Return the private key in PEM format.
-
- def as_pem(self):
- return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.key)
-
- ##
- # Return an M2Crypto key object
-
- def get_m2_pkey(self):
- if not self.m2key:
- self.m2key = M2Crypto.EVP.load_key_string(self.as_pem())
- return self.m2key
-
- ##
- # Returns a string containing the public key represented by this object.
-
- def get_pubkey_string(self):
- m2pkey = self.get_m2_pkey()
- return base64.b64encode(m2pkey.as_der())
-
- ##
- # Return an OpenSSL pkey object
-
- def get_openssl_pkey(self):
- return self.key
-
- ##
- # Given another Keypair object, return TRUE if the two keys are the same.
+ key = None # public/private keypair
+ m2key = None # public key (m2crypto format)
+
+ ##
+ # Creates a Keypair object
+ # @param create If create==True, creates a new public/private key and
+ # stores it in the object
+ # @param string If string!=None, load the keypair from the string (PEM)
+ # @param filename If filename!=None, load the keypair from the file
+
+ def __init__(self, create=False, string=None, filename=None):
+ if create:
+ self.create()
+ if string:
+ self.load_from_string(string)
+ if filename:
+ self.load_from_file(filename)
+
+ ##
+ # Create a RSA public/private key pair and store it inside the keypair object
+
+ def create(self):
+ self.key = crypto.PKey()
+ self.key.generate_key(crypto.TYPE_RSA, 1024)
+
+ ##
+ # Save the private key to a file
+ # @param filename name of file to store the keypair in
+
+ def save_to_file(self, filename):
+ open(filename, 'w').write(self.as_pem())
+
+ ##
+ # Load the private key from a file. Implicity the private key includes the public key.
+
+ def load_from_file(self, filename):
+ buffer = open(filename, 'r').read()
+ self.load_from_string(buffer)
- def is_same(self, pkey):
- return self.as_pem() == pkey.as_pem()
-
- def sign_string(self, data):
- k = self.get_m2_pkey()
- k.sign_init()
- k.sign_update(data)
- return base64.b64encode(k.sign_final())
-
- def verify_string(self, data, sig):
- k = self.get_m2_pkey()
- k.verify_init()
- k.verify_update(data)
- return M2Crypto.m2.verify_final(k.ctx, base64.b64decode(sig), k.pkey)
-
- def compute_hash(self, value):
- return self.sign_string(str(value))
+ ##
+ # Load the private key from a string. Implicitly the private key includes the public key.
+
+ def load_from_string(self, string):
+ self.key = crypto.load_privatekey(crypto.FILETYPE_PEM, string)
+ self.m2key = M2Crypto.EVP.load_key_string(string)
+
+ ##
+ # Load the public key from a string. No private key is loaded.
+
+ def load_pubkey_from_file(self, filename):
+ # load the m2 public key
+ m2rsakey = M2Crypto.RSA.load_pub_key(filename)
+ self.m2key = M2Crypto.EVP.PKey()
+ self.m2key.assign_rsa(m2rsakey)
+
+ # create an m2 x509 cert
+ m2name = M2Crypto.X509.X509_Name()
+ m2name.add_entry_by_txt(field="CN", type=0x1001, entry="junk", len=-1, loc=-1, set=0)
+ m2x509 = M2Crypto.X509.X509()
+ m2x509.set_pubkey(self.m2key)
+ m2x509.set_serial_number(0)
+ m2x509.set_issuer_name(m2name)
+ m2x509.set_subject_name(m2name)
+ ASN1 = M2Crypto.ASN1.ASN1_UTCTIME()
+ ASN1.set_time(500)
+ m2x509.set_not_before(ASN1)
+ m2x509.set_not_after(ASN1)
+ junk_key = Keypair(create=True)
+ m2x509.sign(pkey=junk_key.get_m2_pkey(), md="sha1")
+
+ # convert the m2 x509 cert to a pyopenssl x509
+ m2pem = m2x509.as_pem()
+ pyx509 = crypto.load_certificate(crypto.FILETYPE_PEM, m2pem)
+
+ # get the pyopenssl pkey from the pyopenssl x509
+ self.key = pyx509.get_pubkey()
+
+ ##
+ # Load the public key from a string. No private key is loaded.
+
+ def load_pubkey_from_string(self, string):
+ (f, fn) = tempfile.mkstemp()
+ os.write(f, string)
+ os.close(f)
+ self.load_pubkey_from_file(fn)
+ os.remove(fn)
+
+ ##
+ # Return the private key in PEM format.
+
+ def as_pem(self):
+ return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.key)
+
+ ##
+ # Return an M2Crypto key object
+
+ def get_m2_pkey(self):
+ if not self.m2key:
+ self.m2key = M2Crypto.EVP.load_key_string(self.as_pem())
+ return self.m2key
+
+ ##
+ # Returns a string containing the public key represented by this object.
+
+ def get_pubkey_string(self):
+ m2pkey = self.get_m2_pkey()
+ return base64.b64encode(m2pkey.as_der())
+
+ ##
+ # Return an OpenSSL pkey object
+
+ def get_openssl_pkey(self):
+ return self.key
+
+
+ ##
+ # Given another Keypair object, return TRUE if the two keys are the same.
+
+ def is_same(self, pkey):
+ return self.as_pem() == pkey.as_pem()
+
+ def sign_string(self, data):
+ k = self.get_m2_pkey()
+ k.sign_init()
+ k.sign_update(data)
+ return base64.b64encode(k.sign_final())
+
+ def verify_string(self, data, sig):
+ k = self.get_m2_pkey()
+ k.verify_init()
+ k.verify_update(data)
+ return M2Crypto.m2.verify_final(k.ctx, base64.b64decode(sig), k.pkey)
+
+ def compute_hash(self, value):
+ return self.sign_string(str(value))
##
# The certificate class implements a general purpose X509 certificate, making
# whether to save the parent certificates as well.
class Certificate:
- digest = "md5"
-
- data = None
- cert = None
- issuerKey = None
- issuerSubject = None
- parent = None
-
- separator="-----parent-----"
-
- ##
- # Create a certificate object.
- #
- # @param create If create==True, then also create a blank X509 certificate.
- # @param subject If subject!=None, then create a blank certificate and set
- # it's subject name.
- # @param string If string!=None, load the certficate from the string.
- # @param filename If filename!=None, load the certficiate from the file.
-
- def __init__(self, create=False, subject=None, string=None, filename=None):
- if create or subject:
- self.create()
- if subject:
- self.set_subject(subject)
- if string:
- self.load_from_string(string)
- if filename:
- self.load_from_file(filename)
-
- ##
- # Create a blank X509 certificate and store it in this object.
-
- def create(self):
- self.cert = crypto.X509()
- self.cert.set_serial_number(1)
- self.cert.gmtime_adj_notBefore(0)
- self.cert.gmtime_adj_notAfter(60*60*24*365*5) # five years
-
- ##
- # Given a pyOpenSSL X509 object, store that object inside of this
- # certificate object.
-
- def load_from_pyopenssl_x509(self, x509):
- self.cert = x509
-
- ##
- # Load the certificate from a string
-
- def load_from_string(self, string):
- # if it is a chain of multiple certs, then split off the first one and
- # load it
- parts = string.split(Certificate.separator, 1)
- self.cert = crypto.load_certificate(crypto.FILETYPE_PEM, parts[0])
-
- # if there are more certs, then create a parent and let the parent load
- # itself from the remainder of the string
- if len(parts) > 1:
- self.parent = self.__class__()
- self.parent.load_from_string(parts[1])
-
- ##
- # Load the certificate from a file
-
- def load_from_file(self, filename):
- file = open(filename)
- string = file.read()
- self.load_from_string(string)
-
- ##
- # Save the certificate to a string.
- #
- # @param save_parents If save_parents==True, then also save the parent certificates.
-
- def save_to_string(self, save_parents=False):
- string = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert)
- if save_parents and self.parent:
- string = string + Certificate.separator + self.parent.save_to_string(save_parents)
- return string
-
- ##
- # Save the certificate to a file.
- # @param save_parents If save_parents==True, then also save the parent certificates.
-
- def save_to_file(self, filename, save_parents=False):
- string = self.save_to_string(save_parents=save_parents)
- open(filename, 'w').write(string)
-
- ##
- # Sets the issuer private key and name
- # @param key Keypair object containing the private key of the issuer
- # @param subject String containing the name of the issuer
- # @param cert (optional) Certificate object containing the name of the issuer
-
- def set_issuer(self, key, subject=None, cert=None):
- self.issuerKey = key
- if subject:
- # it's a mistake to use subject and cert params at the same time
- assert(not cert)
- if isinstance(subject, dict) or isinstance(subject, str):
- req = crypto.X509Req()
- reqSubject = req.get_subject()
- if (isinstance(subject, dict)):
- for key in reqSubject.keys():
- setattr(reqSubject, key, name[key])
- else:
- setattr(reqSubject, "CN", subject)
- subject = reqSubject
- # subject is not valid once req is out of scope, so save req
- self.issuerReq = req
- if cert:
- # if a cert was supplied, then get the subject from the cert
- subject = cert.cert.get_subject()
- assert(subject)
- self.issuerSubject = subject
-
- ##
- # Get the issuer name
-
- def get_issuer(self, which="CN"):
- x = self.cert.get_issuer()
- return getattr(x, which)
-
- ##
- # Set the subject name of the certificate
-
- def set_subject(self, name):
- req = crypto.X509Req()
- subj = req.get_subject()
- if (isinstance(name, dict)):
- for key in name.keys():
- setattr(subj, key, name[key])
- else:
- setattr(subj, "CN", name)
- self.cert.set_subject(subj)
- ##
- # Get the subject name of the certificate
-
- def get_subject(self, which="CN"):
- x = self.cert.get_subject()
- return getattr(x, which)
-
- ##
- # Get the public key of the certificate.
- #
- # @param key Keypair object containing the public key
-
- def set_pubkey(self, key):
- assert(isinstance(key, Keypair))
- self.cert.set_pubkey(key.get_openssl_pkey())
-
- ##
- # Get the public key of the certificate.
- # It is returned in the form of a Keypair object.
-
- def get_pubkey(self):
- m2x509 = X509.load_cert_string(self.save_to_string())
- pkey = Keypair()
- pkey.key = self.cert.get_pubkey()
- pkey.m2key = m2x509.get_pubkey()
- return pkey
-
- ##
- # Add an X509 extension to the certificate. Add_extension can only be called
- # once for a particular extension name, due to limitations in the underlying
- # library.
- #
- # @param name string containing name of extension
- # @param value string containing value of the extension
-
- def add_extension(self, name, critical, value):
- ext = crypto.X509Extension (name, critical, value)
- self.cert.add_extensions([ext])
-
- ##
- # Get an X509 extension from the certificate
-
- def get_extension(self, name):
- # pyOpenSSL does not have a way to get extensions
- m2x509 = X509.load_cert_string(self.save_to_string())
- value = m2x509.get_ext(name).get_value()
- return value
-
- ##
- # Set_data is a wrapper around add_extension. It stores the parameter str in
- # the X509 subject_alt_name extension. Set_data can only be called once, due
- # to limitations in the underlying library.
-
- def set_data(self, str):
- # pyOpenSSL only allows us to add extensions, so if we try to set the
- # same extension more than once, it will not work
- if self.data != None:
- raise "cannot set subjectAltName more than once"
- self.data = str
- self.add_extension("subjectAltName", 0, "URI:http://" + str)
-
- ##
- # Return the data string that was previously set with set_data
-
- def get_data(self):
- if self.data:
- return self.data
-
- try:
- uri = self.get_extension("subjectAltName")
- except LookupError:
- self.data = None
- return self.data
-
- if not uri.startswith("URI:http://"):
- raise "bad encoding in subjectAltName"
- self.data = uri[11:]
- return self.data
-
- ##
- # Sign the certificate using the issuer private key and issuer subject previous set with set_issuer().
-
- def sign(self):
- assert self.cert != None
- assert self.issuerSubject != None
- assert self.issuerKey != None
- self.cert.set_issuer(self.issuerSubject)
- self.cert.sign(self.issuerKey.get_openssl_pkey(), self.digest)
+ digest = "md5"
+
+ cert = None
+ issuerKey = None
+ issuerSubject = None
+ parent = None
+
+ separator="-----parent-----"
+
+ ##
+ # Create a certificate object.
+ #
+ # @param create If create==True, then also create a blank X509 certificate.
+ # @param subject If subject!=None, then create a blank certificate and set
+ # it's subject name.
+ # @param string If string!=None, load the certficate from the string.
+ # @param filename If filename!=None, load the certficiate from the file.
+
+ def __init__(self, create=False, subject=None, string=None, filename=None, intermediate=None):
+ self.data = {}
+ if create or subject:
+ self.create()
+ if subject:
+ self.set_subject(subject)
+ if string:
+ self.load_from_string(string)
+ if filename:
+ self.load_from_file(filename)
+
+ if intermediate:
+ self.set_intermediate_ca(intermediate)
+
+ ##
+ # Create a blank X509 certificate and store it in this object.
+
+ def create(self):
+ self.cert = crypto.X509()
+ self.cert.set_serial_number(3)
+ self.cert.gmtime_adj_notBefore(0)
+ self.cert.gmtime_adj_notAfter(60*60*24*365*5) # five years
+
+ ##
+ # Given a pyOpenSSL X509 object, store that object inside of this
+ # certificate object.
+
+ def load_from_pyopenssl_x509(self, x509):
+ self.cert = x509
+
+ ##
+ # Load the certificate from a string
+
+ def load_from_string(self, string):
+ # if it is a chain of multiple certs, then split off the first one and
+ # load it (support for the ---parent--- tag as well as normal chained certs)
+
+ string = string.strip()
+
+
+ if not string.startswith('-----'):
+ string = '-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----' % string
+
+ parts = []
+
+ if string.count('-----BEGIN CERTIFICATE-----') > 1 and \
+ string.count(Certificate.separator) == 0:
+ parts = string.split('-----END CERTIFICATE-----',1)
+ parts[0] += '-----END CERTIFICATE-----'
+ else:
+ parts = string.split(Certificate.separator, 1)
+
+ self.cert = crypto.load_certificate(crypto.FILETYPE_PEM, parts[0])
+
+ # if there are more certs, then create a parent and let the parent load
+ # itself from the remainder of the string
+ if len(parts) > 1 and parts[1] != '':
+ self.parent = self.__class__()
+ self.parent.load_from_string(parts[1])
+
+ ##
+ # Load the certificate from a file
+
+ def load_from_file(self, filename):
+ file = open(filename)
+ string = file.read()
+ self.load_from_string(string)
+
+ ##
+ # Save the certificate to a string.
+ #
+ # @param save_parents If save_parents==True, then also save the parent certificates.
+
+ def save_to_string(self, save_parents=True):
+ string = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert)
+ if save_parents and self.parent:
+ string = string + self.parent.save_to_string(save_parents)
+ return string
+
+ ##
+ # Save the certificate to a file.
+ # @param save_parents If save_parents==True, then also save the parent certificates.
+
+ def save_to_file(self, filename, save_parents=True, filep=None):
+ string = self.save_to_string(save_parents=save_parents)
+ if filep:
+ f = filep
+ else:
+ f = open(filename, 'w')
+ f.write(string)
+ f.close()
+
+ ##
+ # Save the certificate to a random file in /tmp/
+ # @param save_parents If save_parents==True, then also save the parent certificates.
+ def save_to_random_tmp_file(self, save_parents=True):
+ fp, filename = mkstemp(suffix='cert', text=True)
+ fp = os.fdopen(fp, "w")
+ self.save_to_file(filename, save_parents=True, filep=fp)
+ return filename
+
+ ##
+ # Sets the issuer private key and name
+ # @param key Keypair object containing the private key of the issuer
+ # @param subject String containing the name of the issuer
+ # @param cert (optional) Certificate object containing the name of the issuer
+
+ def set_issuer(self, key, subject=None, cert=None):
+ self.issuerKey = key
+ if subject:
+ # it's a mistake to use subject and cert params at the same time
+ assert(not cert)
+ if isinstance(subject, dict) or isinstance(subject, str):
+ req = crypto.X509Req()
+ reqSubject = req.get_subject()
+ if (isinstance(subject, dict)):
+ for key in reqSubject.keys():
+ setattr(reqSubject, key, subject[key])
+ else:
+ setattr(reqSubject, "CN", subject)
+ subject = reqSubject
+ # subject is not valid once req is out of scope, so save req
+ self.issuerReq = req
+ if cert:
+ # if a cert was supplied, then get the subject from the cert
+ subject = cert.cert.get_subject()
+ assert(subject)
+ self.issuerSubject = subject
+
+ ##
+ # Get the issuer name
+
+ def get_issuer(self, which="CN"):
+ x = self.cert.get_issuer()
+ return getattr(x, which)
+
+ ##
+ # Set the subject name of the certificate
+
+ def set_subject(self, name):
+ req = crypto.X509Req()
+ subj = req.get_subject()
+ if (isinstance(name, dict)):
+ for key in name.keys():
+ setattr(subj, key, name[key])
+ else:
+ setattr(subj, "CN", name)
+ self.cert.set_subject(subj)
+ ##
+ # Get the subject name of the certificate
+
+ def get_subject(self, which="CN"):
+ x = self.cert.get_subject()
+ return getattr(x, which)
+
+ ##
+ # Get the public key of the certificate.
+ #
+ # @param key Keypair object containing the public key
+
+ def set_pubkey(self, key):
+ assert(isinstance(key, Keypair))
+ self.cert.set_pubkey(key.get_openssl_pkey())
+
+ ##
+ # Get the public key of the certificate.
+ # It is returned in the form of a Keypair object.
+
+ def get_pubkey(self):
+ m2x509 = X509.load_cert_string(self.save_to_string())
+ pkey = Keypair()
+ pkey.key = self.cert.get_pubkey()
+ pkey.m2key = m2x509.get_pubkey()
+ return pkey
+
+ def set_intermediate_ca(self, val):
+ self.intermediate = val
+ if val:
+ self.add_extension('basicConstraints', 1, 'CA:TRUE')
+
+
+
+ ##
+ # Add an X509 extension to the certificate. Add_extension can only be called
+ # once for a particular extension name, due to limitations in the underlying
+ # library.
+ #
+ # @param name string containing name of extension
+ # @param value string containing value of the extension
+
+ def add_extension(self, name, critical, value):
+ ext = crypto.X509Extension (name, critical, value)
+ self.cert.add_extensions([ext])
+
+ ##
+ # Get an X509 extension from the certificate
+
+ def get_extension(self, name):
+ # pyOpenSSL does not have a way to get extensions
+ m2x509 = X509.load_cert_string(self.save_to_string())
+ value = m2x509.get_ext(name).get_value()
+ return value
+
+ ##
+ # Set_data is a wrapper around add_extension. It stores the parameter str in
+ # the X509 subject_alt_name extension. Set_data can only be called once, due
+ # to limitations in the underlying library.
+
+ def set_data(self, str, field='subjectAltName'):
+ # pyOpenSSL only allows us to add extensions, so if we try to set the
+ # same extension more than once, it will not work
+ if self.data.has_key(field):
+ raise "cannot set ", field, " more than once"
+ self.data[field] = str
+ self.add_extension(field, 0, str)
+
+ ##
+ # Return the data string that was previously set with set_data
+
+ def get_data(self, field='subjectAltName'):
+ if self.data.has_key(field):
+ return self.data[field]
+
+ try:
+ uri = self.get_extension(field)
+ self.data[field] = uri
+ except LookupError:
+ return None
+
+ return self.data[field]
+
+ ##
+ # Sign the certificate using the issuer private key and issuer subject previous set with set_issuer().
+
+ def sign(self):
+ assert self.cert != None
+ assert self.issuerSubject != None
+ assert self.issuerKey != None
+ self.cert.set_issuer(self.issuerSubject)
+ self.cert.sign(self.issuerKey.get_openssl_pkey(), self.digest)
##
# Verify the authenticity of a certificate.
# @param pkey is a Keypair object representing a public key. If Pkey
# did not sign the certificate, then an exception will be thrown.
- def verify(self, pkey):
- # pyOpenSSL does not have a way to verify signatures
- m2x509 = X509.load_cert_string(self.save_to_string())
- m2pkey = pkey.get_m2_pkey()
- # verify it
- return m2x509.verify(m2pkey)
-
- # XXX alternatively, if openssl has been patched, do the much simpler:
- # try:
- # self.cert.verify(pkey.get_openssl_key())
- # return 1
- # except:
- # return 0
-
- ##
- # Return True if pkey is identical to the public key that is contained in the certificate.
- # @param pkey Keypair object
-
- def is_pubkey(self, pkey):
- return self.get_pubkey().is_same(pkey)
-
- ##
- # Given a certificate cert, verify that this certificate was signed by the
- # public key contained in cert. Throw an exception otherwise.
- #
- # @param cert certificate object
-
- def is_signed_by_cert(self, cert):
- k = cert.get_pubkey()
- result = self.verify(k)
- return result
-
- ##
- # Set the parent certficiate.
- #
- # @param p certificate object.
-
- def set_parent(self, p):
+ def verify(self, pkey):
+ # pyOpenSSL does not have a way to verify signatures
+ m2x509 = X509.load_cert_string(self.save_to_string())
+ m2pkey = pkey.get_m2_pkey()
+ # verify it
+ return m2x509.verify(m2pkey)
+
+ # XXX alternatively, if openssl has been patched, do the much simpler:
+ # try:
+ # self.cert.verify(pkey.get_openssl_key())
+ # return 1
+ # except:
+ # return 0
+
+ ##
+ # Return True if pkey is identical to the public key that is contained in the certificate.
+ # @param pkey Keypair object
+
+ def is_pubkey(self, pkey):
+ return self.get_pubkey().is_same(pkey)
+
+ ##
+ # Given a certificate cert, verify that this certificate was signed by the
+ # public key contained in cert. Throw an exception otherwise.
+ #
+ # @param cert certificate object
+
+ def is_signed_by_cert(self, cert):
+ k = cert.get_pubkey()
+ result = self.verify(k)
+ return result
+
+ ##
+ # Set the parent certficiate.
+ #
+ # @param p certificate object.
+
+ def set_parent(self, p):
self.parent = p
- ##
- # Return the certificate object of the parent of this certificate.
+ ##
+ # Return the certificate object of the parent of this certificate.
- def get_parent(self):
+ def get_parent(self):
return self.parent
- ##
- # Verification examines a chain of certificates to ensure that each parent
- # signs the child, and that some certificate in the chain is signed by a
- # trusted certificate.
- #
- # Verification is a basic recursion: <pre>
- # if this_certificate was signed by trusted_certs:
- # return
- # else
- # return verify_chain(parent, trusted_certs)
- # </pre>
- #
- # At each recursion, the parent is tested to ensure that it did sign the
- # child. If a parent did not sign a child, then an exception is thrown. If
- # the bottom of the recursion is reached and the certificate does not match
- # a trusted root, then an exception is thrown.
- #
- # @param Trusted_certs is a list of certificates that are trusted.
- #
-
- def verify_chain(self, trusted_certs = None):
+ ##
+ # Verification examines a chain of certificates to ensure that each parent
+ # signs the child, and that some certificate in the chain is signed by a
+ # trusted certificate.
+ #
+ # Verification is a basic recursion: <pre>
+ # if this_certificate was signed by trusted_certs:
+ # return
+ # else
+ # return verify_chain(parent, trusted_certs)
+ # </pre>
+ #
+ # At each recursion, the parent is tested to ensure that it did sign the
+ # child. If a parent did not sign a child, then an exception is thrown. If
+ # the bottom of the recursion is reached and the certificate does not match
+ # a trusted root, then an exception is thrown.
+ #
+ # @param Trusted_certs is a list of certificates that are trusted.
+ #
+
+ def verify_chain(self, trusted_certs = None):
# Verify a chain of certificates. Each certificate must be signed by
# the public key contained in it's parent. The chain is recursed
# until a certificate is found that is signed by a trusted root.
#print "TRUSTED CERT", trusted_cert.dump()
#print "Client is signed by Trusted?", self.is_signed_by_cert(trusted_cert)
if self.is_signed_by_cert(trusted_cert):
- # make sure sure the trusted cert's hrn is a prefix of the
- # signed cert's hrn
- if not self.get_subject().startswith(trusted_cert.get_subject()):
- raise GidParentHrn(trusted_cert.get_subject())
- #print self.get_subject(), "is signed by a root"
- return
+ return trusted_cert
# if there is no parent, then no way to verify the chain
if not self.parent:
##
# Implements SFA Credentials
#
-# Credentials are layered on top of certificates, and are essentially a
-# certificate that stores a tuple of parameters.
+# Credentials are signed XML files that assign a subject gid privileges to an object gid
##
### $Id$
### $URL$
-import xmlrpclib
+import os
+import datetime
+from xml.dom.minidom import Document, parseString
+from tempfile import mkstemp
-from sfa.trust.certificate import Certificate
+from sfa.trust.credential_legacy import CredentialLegacy
from sfa.trust.rights import *
from sfa.trust.gid import *
from sfa.util.faults import *
+from sfa.util.sfalogging import logger
+from dateutil.parser import parse
+
+
+
+# Two years, in seconds
+DEFAULT_CREDENTIAL_LIFETIME = 60 * 60 * 24 * 365 * 2
+
+
+# TODO:
+# . make privs match between PG and PL
+# . Need to add support for other types of credentials, e.g. tickets
+
+
+
+signature_template = \
+'''
+<Signature xml:id="Sig_%s" xmlns="http://www.w3.org/2000/09/xmldsig#">
+ <SignedInfo>
+ <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
+ <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
+ <Reference URI="#%s">
+ <Transforms>
+ <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
+ </Transforms>
+ <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
+ <DigestValue></DigestValue>
+ </Reference>
+ </SignedInfo>
+ <SignatureValue />
+ <KeyInfo>
+ <X509Data>
+ <X509SubjectName/>
+ <X509IssuerSerial/>
+ <X509Certificate/>
+ </X509Data>
+ <KeyValue />
+ </KeyInfo>
+ </Signature>
+'''
+
+##
+# Convert a string into a bool
+
+def str2bool(str):
+ if str.lower() in ['yes','true','1']:
+ return True
+ return False
+
+
+
+##
+# Utility function to get the text of an XML element
+
+def getTextNode(element, subele):
+ sub = element.getElementsByTagName(subele)[0]
+ if len(sub.childNodes) > 0:
+ return sub.childNodes[0].nodeValue
+ else:
+ return None
+
+##
+# Utility function to set the text of an XML element
+# It creates the element, adds the text to it,
+# and then appends it to the parent.
+
+def append_sub(doc, parent, element, text):
+ ele = doc.createElement(element)
+ ele.appendChild(doc.createTextNode(text))
+ parent.appendChild(ele)
+
+##
+# Signature contains information about an xmlsec1 signature
+# for a signed-credential
+#
+
+class Signature(object):
+
+
+ def __init__(self, string=None):
+ self.refid = None
+ self.issuer_gid = None
+ self.xml = None
+ if string:
+ self.xml = string
+ self.decode()
+
+
+
+ def get_refid(self):
+ if not self.refid:
+ self.decode()
+ return self.refid
+
+ def get_xml(self):
+ if not self.xml:
+ self.encode()
+ return self.xml
+
+ def set_refid(self, id):
+ self.refid = id
+
+ def get_issuer_gid(self):
+ if not self.gid:
+ self.decode()
+ return self.gid
+
+ def set_issuer_gid(self, gid):
+ self.gid = gid
+
+ def decode(self):
+ doc = parseString(self.xml)
+ sig = doc.getElementsByTagName("Signature")[0]
+ self.set_refid(sig.getAttribute("xml:id").strip("Sig_"))
+ keyinfo = sig.getElementsByTagName("X509Data")[0]
+ szgid = getTextNode(keyinfo, "X509Certificate")
+ szgid = "-----BEGIN CERTIFICATE-----\n%s\n-----END CERTIFICATE-----" % szgid
+ self.set_issuer_gid(GID(string=szgid))
+
+ def encode(self):
+ self.xml = signature_template % (self.get_refid(), self.get_refid())
+
+
##
-# Credential is a tuple:
-# (GIDCaller, GIDObject, LifeTime, Privileges, Delegate)
+# A credential provides a caller gid with privileges to an object gid.
+# A signed credential is signed by the object's authority.
+#
+# Credentials are encoded in one of two ways. The legacy style places
+# it in the subjectAltName of an X509 certificate. The new credentials
+# are placed in signed XML.
#
-# These fields are encoded using xmlrpc into the subjectAltName field of the
-# x509 certificate. Note: Call encode() once the fields have been filled in
-# to perform this encoding.
+# WARNING:
+# In general, a signed credential obtained externally should
+# not be changed else the signature is no longer valid. So, once
+# you have loaded an existing signed credential, do not call encode() or sign() on it.
+
+
+class Credential(object):
-class Credential(Certificate):
- gidCaller = None
- gidObject = None
- lifeTime = None
- privileges = None
- delegate = False
##
# Create a Credential object
# @param filename If filename!=None, load the credential from the file
def __init__(self, create=False, subject=None, string=None, filename=None):
- Certificate.__init__(self, create, subject, string, filename)
+ self.gidCaller = None
+ self.gidObject = None
+ self.expiration = None
+ self.privileges = None
+ self.issuer_privkey = None
+ self.issuer_gid = None
+ self.issuer_pubkey = None
+ self.parent = None
+ self.signature = None
+ self.xml = None
+ self.refid = None
+ self.legacy = None
+
+
+
+
+ # Check if this is a legacy credential, translate it if so
+ if string or filename:
+ if string:
+ str = string
+ elif filename:
+ str = file(filename).read()
+
+ if str.strip().startswith("-----"):
+ self.legacy = CredentialLegacy(False,string=str)
+ self.translate_legacy(str)
+ else:
+ self.xml = str
+ self.decode()
+
+ # Find an xmlsec1 path
+ self.xmlsec_path = ''
+ paths = ['/usr/bin','/usr/local/bin','/bin','/opt/bin','/opt/local/bin']
+ for path in paths:
+ if os.path.isfile(path + '/' + 'xmlsec1'):
+ self.xmlsec_path = path + '/' + 'xmlsec1'
+ break
+
+
+ def get_signature(self):
+ if not self.signature:
+ self.decode()
+ return self.signature
+
+ def set_signature(self, sig):
+ self.signature = sig
+
+
+ ##
+ # Translate a legacy credential into a new one
+ #
+ # @param String of the legacy credential
+
+ def translate_legacy(self, str):
+ legacy = CredentialLegacy(False,string=str)
+ self.gidCaller = legacy.get_gid_caller()
+ self.gidObject = legacy.get_gid_object()
+ lifetime = legacy.get_lifetime()
+ if not lifetime:
+ # Default to two years
+ self.set_lifetime(DEFAULT_CREDENTIAL_LIFETIME)
+ else:
+ self.set_lifetime(int(lifetime))
+ self.lifeTime = legacy.get_lifetime()
+ self.set_privileges(legacy.get_privileges())
+ self.get_privileges().delegate_all_privileges(legacy.get_delegate())
+
+ ##
+ # Need the issuer's private key and name
+ # @param key Keypair object containing the private key of the issuer
+ # @param gid GID of the issuing authority
+
+ def set_issuer_keys(self, privkey, gid):
+ self.issuer_privkey = privkey
+ self.issuer_gid = gid
+
+
+ ##
+ # Set this credential's parent
+ def set_parent(self, cred):
+ self.parent = cred
+ self.updateRefID()
##
# set the GID of the caller
# set the lifetime of this credential
#
# @param lifetime lifetime of credential
+ # . if lifeTime is a datetime object, it is used for the expiration time
+ # . if lifeTime is an integer value, it is considered the number of seconds
+ # remaining before expiration
def set_lifetime(self, lifeTime):
- self.lifeTime = lifeTime
+ if isinstance(lifeTime, int):
+ self.expiration = datetime.timedelta(seconds=lifeTime) + datetime.datetime.utcnow()
+ else:
+ self.expiration = lifeTime
##
- # get the lifetime of the credential
+ # get the lifetime of the credential (in datetime format)
def get_lifetime(self):
- if not self.lifeTime:
- self.decode()
- return self.lifeTime
-
- ##
- # set the delegate bit
- #
- # @param delegate boolean (True or False)
-
- def set_delegate(self, delegate):
- self.delegate = delegate
-
- ##
- # get the delegate bit
-
- def get_delegate(self):
- if not self.delegate:
+ if not self.expiration:
self.decode()
- return self.delegate
+ return self.expiration
+
##
# set the privileges
#
self.privileges = RightList(string = privs)
else:
self.privileges = privs
+
##
# return the privileges as a RightList object
def can_perform(self, op_name):
rights = self.get_privileges()
+
if not rights:
return False
+
return rights.can_perform(op_name)
+
##
- # Encode the attributes of the credential into a string and store that
- # string in the alt-subject-name field of the X509 object. This should be
- # done immediately before signing the credential.
+ # Encode the attributes of the credential into an XML string
+ # This should be done immediately before signing the credential.
+ # WARNING:
+ # In general, a signed credential obtained externally should
+ # not be changed else the signature is no longer valid. So, once
+ # you have loaded an existing signed credential, do not call encode() or sign() on it.
def encode(self):
- dict = {"gidCaller": None,
- "gidObject": None,
- "lifeTime": self.lifeTime,
- "privileges": None,
- "delegate": self.delegate}
- if self.gidCaller:
- dict["gidCaller"] = self.gidCaller.save_to_string(save_parents=True)
- if self.gidObject:
- dict["gidObject"] = self.gidObject.save_to_string(save_parents=True)
+ # Create the XML document
+ doc = Document()
+ signed_cred = doc.createElement("signed-credential")
+ doc.appendChild(signed_cred)
+
+ # Fill in the <credential> bit
+ cred = doc.createElement("credential")
+ cred.setAttribute("xml:id", self.get_refid())
+ signed_cred.appendChild(cred)
+ append_sub(doc, cred, "type", "privilege")
+ append_sub(doc, cred, "serial", "8")
+ append_sub(doc, cred, "owner_gid", self.gidCaller.save_to_string())
+ append_sub(doc, cred, "owner_urn", self.gidCaller.get_urn())
+ append_sub(doc, cred, "target_gid", self.gidObject.save_to_string())
+ append_sub(doc, cred, "target_urn", self.gidObject.get_urn())
+ append_sub(doc, cred, "uuid", "")
+ if not self.expiration:
+ self.set_lifetime(DEFAULT_CREDENTIAL_LIFETIME)
+ self.expiration = self.expiration.replace(microsecond=0)
+ append_sub(doc, cred, "expires", self.expiration.isoformat())
+ privileges = doc.createElement("privileges")
+ cred.appendChild(privileges)
+
if self.privileges:
- dict["privileges"] = self.privileges.save_to_string()
- str = xmlrpclib.dumps((dict,), allow_none=True)
- self.set_data(str)
+ rights = self.get_privileges()
+ for right in rights.rights:
+ priv = doc.createElement("privilege")
+ append_sub(doc, priv, "name", right.kind)
+ append_sub(doc, priv, "can_delegate", str(right.delegate).lower())
+ privileges.appendChild(priv)
+
+ # Add the parent credential if it exists
+ if self.parent:
+ sdoc = parseString(self.parent.get_xml())
+ p_cred = doc.importNode(sdoc.getElementsByTagName("credential")[0], True)
+ p = doc.createElement("parent")
+ p.appendChild(p_cred)
+ cred.appendChild(p)
- ##
- # Retrieve the attributes of the credential from the alt-subject-name field
- # of the X509 certificate. This is automatically done by the various
- # get_* methods of this class and should not need to be called explicitly.
- def decode(self):
- data = self.get_data()
- if data:
- dict = xmlrpclib.loads(self.get_data())[0][0]
+ # Create the <signatures> tag
+ signatures = doc.createElement("signatures")
+ signed_cred.appendChild(signatures)
+
+ # Add any parent signatures
+ if self.parent:
+ for cur_cred in self.get_credential_list()[1:]:
+ sdoc = parseString(cur_cred.get_signature().get_xml())
+ ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
+ signatures.appendChild(ele)
+
+ # Get the finished product
+ self.xml = doc.toxml()
+
+
+ def save_to_random_tmp_file(self):
+ fp, filename = mkstemp(suffix='cred', text=True)
+ fp = os.fdopen(fp, "w")
+ self.save_to_file(filename, save_parents=True, filep=fp)
+ return filename
+
+ def save_to_file(self, filename, save_parents=True, filep=None):
+ if not self.xml:
+ self.encode()
+ if filep:
+ f = filep
else:
- dict = {}
+ f = open(filename, "w")
+ f.write(self.xml)
+ f.close()
- self.lifeTime = dict.get("lifeTime", None)
- self.delegate = dict.get("delegate", None)
+ def save_to_string(self, save_parents=True):
+ if not self.xml:
+ self.encode()
+ return self.xml
- privStr = dict.get("privileges", None)
- if privStr:
- self.privileges = RightList(string = privStr)
- else:
- self.privileges = None
+ def get_refid(self):
+ if not self.refid:
+ self.refid = 'ref0'
+ return self.refid
- gidCallerStr = dict.get("gidCaller", None)
- if gidCallerStr:
- self.gidCaller = GID(string=gidCallerStr)
- else:
- self.gidCaller = None
+ def set_refid(self, rid):
+ self.refid = rid
- gidObjectStr = dict.get("gidObject", None)
- if gidObjectStr:
- self.gidObject = GID(string=gidObjectStr)
- else:
- self.gidObject = None
+ ##
+ # Figure out what refids exist, and update this credential's id
+ # so that it doesn't clobber the others. Returns the refids of
+ # the parents.
+
+ def updateRefID(self):
+ if not self.parent:
+ self.set_refid('ref0')
+ return []
+
+ refs = []
+
+ next_cred = self.parent
+ while next_cred:
+ refs.append(next_cred.get_refid())
+ if next_cred.parent:
+ next_cred = next_cred.parent
+ else:
+ next_cred = None
+
+
+ # Find a unique refid for this credential
+ rid = self.get_refid()
+ while rid in refs:
+ val = int(rid[3:])
+ rid = "ref%d" % (val + 1)
+
+ # Set the new refid
+ self.set_refid(rid)
+
+ # Return the set of parent credential ref ids
+ return refs
+
+ def get_xml(self):
+ if not self.xml:
+ self.encode()
+ return self.xml
##
- # Verify that a chain of credentials is valid (see cert.py:verify). In
- # addition to the checks for ordinary certificates, verification also
- # ensures that the delegate bit was set by each parent in the chain. If
- # a delegate bit was not set, then an exception is thrown.
+ # Sign the XML file created by encode()
#
- # Each credential must be a subset of the rights of the parent.
+ # WARNING:
+ # In general, a signed credential obtained externally should
+ # not be changed else the signature is no longer valid. So, once
+ # you have loaded an existing signed credential, do not call encode() or sign() on it.
+
+ def sign(self):
+ if not self.issuer_privkey or not self.issuer_gid:
+ return
+ doc = parseString(self.get_xml())
+ sigs = doc.getElementsByTagName("signatures")[0]
+
+ # Create the signature template to be signed
+ signature = Signature()
+ signature.set_refid(self.get_refid())
+ sdoc = parseString(signature.get_xml())
+ sig_ele = doc.importNode(sdoc.getElementsByTagName("Signature")[0], True)
+ sigs.appendChild(sig_ele)
+
+ self.xml = doc.toxml()
+
+
+ # Split the issuer GID into multiple certificates if it's a chain
+ chain = GID(filename=self.issuer_gid)
+ gid_files = []
+ while chain:
+ gid_files.append(chain.save_to_random_tmp_file(False))
+ if chain.get_parent():
+ chain = chain.get_parent()
+ else:
+ chain = None
+
+
+ # Call out to xmlsec1 to sign it
+ ref = 'Sig_%s' % self.get_refid()
+ filename = self.save_to_random_tmp_file()
+ signed = os.popen('%s --sign --node-id "%s" --privkey-pem %s,%s %s' \
+ % (self.xmlsec_path, ref, self.issuer_privkey, ",".join(gid_files), filename)).read()
+ os.remove(filename)
+
+ for gid_file in gid_files:
+ os.remove(gid_file)
+
+ self.xml = signed
+
+ # This is no longer a legacy credential
+ if self.legacy:
+ self.legacy = None
+
+ # Update signatures
+ self.decode()
- def verify_chain(self, trusted_certs = None):
- # do the normal certificate verification stuff
- Certificate.verify_chain(self, trusted_certs)
+
+
+ ##
+ # Retrieve the attributes of the credential from the XML.
+ # This is automatically called by the various get_* methods of
+ # this class and should not need to be called explicitly.
+
+ def decode(self):
+ if not self.xml:
+ return
+ doc = parseString(self.xml)
+ sigs = []
+ signed_cred = doc.getElementsByTagName("signed-credential")
+
+ # Is this a signed-cred or just a cred?
+ if len(signed_cred) > 0:
+ cred = signed_cred[0].getElementsByTagName("credential")[0]
+ signatures = signed_cred[0].getElementsByTagName("signatures")
+ if len(signatures) > 0:
+ sigs = signatures[0].getElementsByTagName("Signature")
+ else:
+ cred = doc.getElementsByTagName("credential")[0]
+
+
+
+ self.set_refid(cred.getAttribute("xml:id"))
+ self.set_lifetime(parse(getTextNode(cred, "expires")))
+ self.gidCaller = GID(string=getTextNode(cred, "owner_gid"))
+ self.gidObject = GID(string=getTextNode(cred, "target_gid"))
+
+
+ # Process privileges
+ privs = cred.getElementsByTagName("privileges")[0]
+ rlist = RightList()
+ for priv in privs.getElementsByTagName("privilege"):
+ kind = getTextNode(priv, "name")
+ deleg = str2bool(getTextNode(priv, "can_delegate"))
+ if kind == '*':
+ # Convert * into the default privileges for the credential's type
+ _ , type = urn_to_hrn(self.gidObject.get_urn())
+ rl = rlist.determine_rights(type, self.gidObject.get_urn())
+ for r in rl.rights:
+ rlist.add(r)
+ else:
+ rlist.add(Right(kind.strip(), deleg))
+ self.set_privileges(rlist)
+
+
+ # Is there a parent?
+ parent = cred.getElementsByTagName("parent")
+ if len(parent) > 0:
+ parent_doc = parent[0].getElementsByTagName("credential")[0]
+ parent_xml = parent_doc.toxml()
+ self.parent = Credential(string=parent_xml)
+ self.updateRefID()
+
+ # Assign the signatures to the credentials
+ for sig in sigs:
+ Sig = Signature(string=sig.toxml())
+
+ for cur_cred in self.get_credential_list():
+ if cur_cred.get_refid() == Sig.get_refid():
+ cur_cred.set_signature(Sig)
+
+
+ ##
+ # Verify
+ # trusted_certs: A list of trusted GID filenames (not GID objects!)
+ # Chaining is not supported within the GIDs by xmlsec1.
+ #
+ # Verify that:
+ # . All of the signatures are valid and that the issuers trace back
+ # to trusted roots (performed by xmlsec1)
+ # . The XML matches the credential schema
+ # . That the issuer of the credential is the authority in the target's urn
+ # . In the case of a delegated credential, this must be true of the root
+ # . That all of the gids presented in the credential are valid
+ # . The credential is not expired
+ #
+ # -- For Delegates (credentials with parents)
+ # . The privileges must be a subset of the parent credentials
+ # . The privileges must have "can_delegate" set for each delegated privilege
+ # . The target gid must be the same between child and parents
+ # . The expiry time on the child must be no later than the parent
+ # . The signer of the child must be the owner of the parent
+ #
+ # -- Verify does *NOT*
+ # . ensure that an xmlrpc client's gid matches a credential gid, that
+ # must be done elsewhere
+ #
+ # @param trusted_certs: The certificates of trusted CA certificates
+
+ def verify(self, trusted_certs):
+ if not self.xml:
+ self.decode()
+ trusted_cert_objects = [GID(filename=f) for f in trusted_certs]
+
+ # Use legacy verification if this is a legacy credential
+ if self.legacy:
+ self.legacy.verify_chain(trusted_cert_objects)
+ if self.legacy.client_gid:
+ self.legacy.client_gid.verify_chain(trusted_cert_objects)
+ if self.legacy.object_gid:
+ self.legacy.object_gid.verify_chain(trusted_cert_objects)
+ return True
+
+ # make sure it is not expired
+ if self.get_lifetime() < datetime.datetime.utcnow():
+ raise CredentialNotVerifiable("credential is expired")
+
+ # Verify the signatures
+ filename = self.save_to_random_tmp_file()
+ cert_args = " ".join(['--trusted-pem %s' % x for x in trusted_certs])
+
+ # Verify the gids of this cred and of its parents
+
+
+
+ for cur_cred in self.get_credential_list():
+ cur_cred.get_gid_object().verify_chain(trusted_cert_objects)
+ cur_cred.get_gid_caller().verify_chain(trusted_cert_objects)
+
+
+ refs = []
+ refs.append("Sig_%s" % self.get_refid())
+
+ parentRefs = self.updateRefID()
+ for ref in parentRefs:
+ refs.append("Sig_%s" % ref)
+
+ for ref in refs:
+ verified = os.popen('%s --verify --node-id "%s" %s %s 2>&1' \
+ % (self.xmlsec_path, ref, cert_args, filename)).read()
+ if not verified.strip().startswith("OK"):
+ raise CredentialNotVerifiable("xmlsec1 error: " + verified)
+ os.remove(filename)
+
+ # Verify the parents (delegation)
if self.parent:
- # make sure the parent delegated rights to the child
- if not self.parent.get_delegate():
- raise MissingDelegateBit(self.parent.get_subject())
+ self.verify_parent(self.parent)
+
+ # Make sure the issuer is the target's authority
+ self.verify_issuer()
+ return True
- # make sure the rights given to the child are a subset of the
- # parents rights
- if not self.parent.get_privileges().is_superset(self.get_privileges()):
- raise ChildRightsNotSubsetOfParent(self.get_subject()
- + " " + self.parent.get_privileges().save_to_string()
- + " " + self.get_privileges().save_to_string())
+ ##
+ # Creates a list of the credential and its parents, with the root
+ # (original delegated credential) as the last item in the list
+ def get_credential_list(self):
+ cur_cred = self
+ list = []
+ while cur_cred:
+ list.append(cur_cred)
+ if cur_cred.parent:
+ cur_cred = cur_cred.parent
+ else:
+ cur_cred = None
+ return list
+
+ ##
+ # Make sure the credential's target gid was signed by (or is the same) as the entity that signed
+ # the original credential.
+ def verify_issuer(self):
+ root_cred = self.get_credential_list()[-1]
+ root_target_gid = root_cred.get_gid_object()
+ root_cred_signer = root_cred.get_signature().get_issuer_gid()
+
+ if root_target_gid.is_signed_by_cert(root_cred_signer) or \
+ root_target_gid.save_to_string() == root_cred_signer.save_to_string():
+ pass
+ else:
+ raise CredentialNotVerifiable("Could not verify credential signer")
+
- return
+ ##
+ # -- For Delegates (credentials with parents) verify that:
+ # . The privileges must be a subset of the parent credentials
+ # . The privileges must have "can_delegate" set for each delegated privilege
+ # . The target gid must be the same between child and parents
+ # . The expiry time on the child must be no later than the parent
+ # . The signer of the child must be the owner of the parent
+
+ def verify_parent(self, parent_cred):
+ # make sure the rights given to the child are a subset of the
+ # parents rights (and check delegate bits)
+ if not parent_cred.get_privileges().is_superset(self.get_privileges()):
+ raise ChildRightsNotSubsetOfParent(
+ self.parent.get_privileges().save_to_string() + " " +
+ self.get_privileges().save_to_string())
+
+ # make sure my target gid is the same as the parent's
+ if not parent_cred.get_gid_object().save_to_string() == \
+ self.get_gid_object().save_to_string():
+ raise CredentialNotVerifiable("target gid not equal between parent and child")
+
+ # make sure my expiry time is <= my parent's
+ if not parent_cred.get_lifetime() >= self.get_lifetime():
+ raise CredentialNotVerifiable("delegated credential expires after parent")
+
+ # make sure my signer is the parent's caller
+ if not parent_cred.get_gid_caller().save_to_string(False) == \
+ self.get_signature().get_issuer_gid().save_to_string(False):
+ raise CredentialNotVerifiable("delegated credential not signed by parent caller")
+
+ if parent_cred.parent:
+ parent_cred.verify_parent(parent_cred.parent)
##
# Dump the contents of a credential to stdout in human-readable format
if gidObject:
gidObject.dump(8, dump_parents)
- print " delegate:", self.get_delegate()
if self.parent and dump_parents:
- print "PARENT",
- self.parent.dump(dump_parents)
+ print "PARENT",
+ self.parent.dump_parents()
--- /dev/null
+##
+# Implements SFA Credentials
+#
+# Credentials are layered on top of certificates, and are essentially a
+# certificate that stores a tuple of parameters.
+##
+
+### $Id: credential.py 17477 2010-03-25 16:49:34Z jkarlin $
+### $URL: svn+ssh://svn.planet-lab.org/svn/sfa/branches/geni-api/sfa/trust/credential.py $
+
+import xmlrpclib
+
+from sfa.trust.certificate import Certificate
+from sfa.trust.rights import *
+from sfa.trust.gid import *
+from sfa.util.faults import *
+from sfa.util.sfalogging import *
+
+##
+# Credential is a tuple:
+# (GIDCaller, GIDObject, LifeTime, Privileges, Delegate)
+#
+# These fields are encoded using xmlrpc into the subjectAltName field of the
+# x509 certificate. Note: Call encode() once the fields have been filled in
+# to perform this encoding.
+
+class CredentialLegacy(Certificate):
+ gidCaller = None
+ gidObject = None
+ lifeTime = None
+ privileges = None
+ delegate = False
+
+ ##
+ # Create a Credential object
+ #
+ # @param create If true, create a blank x509 certificate
+ # @param subject If subject!=None, create an x509 cert with the subject name
+ # @param string If string!=None, load the credential from the string
+ # @param filename If filename!=None, load the credential from the file
+
+ def __init__(self, create=False, subject=None, string=None, filename=None):
+ Certificate.__init__(self, create, subject, string, filename)
+
+ ##
+ # set the GID of the caller
+ #
+ # @param gid GID object of the caller
+
+ def set_gid_caller(self, gid):
+ self.gidCaller = gid
+ # gid origin caller is the caller's gid by default
+ self.gidOriginCaller = gid
+
+ ##
+ # get the GID of the object
+
+ def get_gid_caller(self):
+ if not self.gidCaller:
+ self.decode()
+ return self.gidCaller
+
+ ##
+ # set the GID of the object
+ #
+ # @param gid GID object of the object
+
+ def set_gid_object(self, gid):
+ self.gidObject = gid
+
+ ##
+ # get the GID of the object
+
+ def get_gid_object(self):
+ if not self.gidObject:
+ self.decode()
+ return self.gidObject
+
+ ##
+ # set the lifetime of this credential
+ #
+ # @param lifetime lifetime of credential
+
+ def set_lifetime(self, lifeTime):
+ self.lifeTime = lifeTime
+
+ ##
+ # get the lifetime of the credential
+
+ def get_lifetime(self):
+ if not self.lifeTime:
+ self.decode()
+ return self.lifeTime
+
+ ##
+ # set the delegate bit
+ #
+ # @param delegate boolean (True or False)
+
+ def set_delegate(self, delegate):
+ self.delegate = delegate
+
+ ##
+ # get the delegate bit
+
+ def get_delegate(self):
+ if not self.delegate:
+ self.decode()
+ return self.delegate
+
+ ##
+ # set the privileges
+ #
+ # @param privs either a comma-separated list of privileges of a RightList object
+
+ def set_privileges(self, privs):
+ if isinstance(privs, str):
+ self.privileges = RightList(string = privs)
+ else:
+ self.privileges = privs
+
+ ##
+ # return the privileges as a RightList object
+
+ def get_privileges(self):
+ if not self.privileges:
+ self.decode()
+ return self.privileges
+
+ ##
+ # determine whether the credential allows a particular operation to be
+ # performed
+ #
+ # @param op_name string specifying name of operation ("lookup", "update", etc)
+
+ def can_perform(self, op_name):
+ rights = self.get_privileges()
+ if not rights:
+ return False
+ return rights.can_perform(op_name)
+
+ ##
+ # Encode the attributes of the credential into a string and store that
+ # string in the alt-subject-name field of the X509 object. This should be
+ # done immediately before signing the credential.
+
+ def encode(self):
+ dict = {"gidCaller": None,
+ "gidObject": None,
+ "lifeTime": self.lifeTime,
+ "privileges": None,
+ "delegate": self.delegate}
+ if self.gidCaller:
+ dict["gidCaller"] = self.gidCaller.save_to_string(save_parents=True)
+ if self.gidObject:
+ dict["gidObject"] = self.gidObject.save_to_string(save_parents=True)
+ if self.privileges:
+ dict["privileges"] = self.privileges.save_to_string()
+ str = xmlrpclib.dumps((dict,), allow_none=True)
+ self.set_data('URI:http://' + str)
+
+ ##
+ # Retrieve the attributes of the credential from the alt-subject-name field
+ # of the X509 certificate. This is automatically done by the various
+ # get_* methods of this class and should not need to be called explicitly.
+
+ def decode(self):
+ data = self.get_data().lstrip('URI:http://')
+
+ if data:
+ dict = xmlrpclib.loads(data)[0][0]
+ else:
+ dict = {}
+
+ self.lifeTime = dict.get("lifeTime", None)
+ self.delegate = dict.get("delegate", None)
+
+ privStr = dict.get("privileges", None)
+ if privStr:
+ self.privileges = RightList(string = privStr)
+ else:
+ self.privileges = None
+
+ gidCallerStr = dict.get("gidCaller", None)
+ if gidCallerStr:
+ self.gidCaller = GID(string=gidCallerStr)
+ else:
+ self.gidCaller = None
+
+ gidObjectStr = dict.get("gidObject", None)
+ if gidObjectStr:
+ self.gidObject = GID(string=gidObjectStr)
+ else:
+ self.gidObject = None
+
+ ##
+ # Verify that a chain of credentials is valid (see cert.py:verify). In
+ # addition to the checks for ordinary certificates, verification also
+ # ensures that the delegate bit was set by each parent in the chain. If
+ # a delegate bit was not set, then an exception is thrown.
+ #
+ # Each credential must be a subset of the rights of the parent.
+
+ def verify_chain(self, trusted_certs = None):
+ # do the normal certificate verification stuff
+ Certificate.verify_chain(self, trusted_certs)
+
+ if self.parent:
+ # make sure the parent delegated rights to the child
+ if not self.parent.get_delegate():
+ raise MissingDelegateBit(self.parent.get_subject())
+
+ # make sure the rights given to the child are a subset of the
+ # parents rights
+ if not self.parent.get_privileges().is_superset(self.get_privileges()):
+ raise ChildRightsNotSubsetOfParent(self.get_subject()
+ + " " + self.parent.get_privileges().save_to_string()
+ + " " + self.get_privileges().save_to_string())
+
+ return
+
+ ##
+ # Dump the contents of a credential to stdout in human-readable format
+ #
+ # @param dump_parents If true, also dump the parent certificates
+
+ def dump(self, dump_parents=False):
+ print "CREDENTIAL", self.get_subject()
+
+ print " privs:", self.get_privileges().save_to_string()
+
+ print " gidCaller:"
+ gidCaller = self.get_gid_caller()
+ if gidCaller:
+ gidCaller.dump(8, dump_parents)
+
+ print " gidObject:"
+ gidObject = self.get_gid_object()
+ if gidObject:
+ gidObject.dump(8, dump_parents)
+
+ print " delegate:", self.get_delegate()
+
+ if self.parent and dump_parents:
+ print "PARENT",
+ self.parent.dump(dump_parents)
+
import xmlrpclib
import uuid
-
from sfa.trust.certificate import Certificate
from sfa.util.namespace import *
+from sfa.util.sfalogging import logger
+
##
# Create a new uuid. Returns the UUID as a string.
return str(uuid.uuid4().int)
##
-# GID is a tuplie:
-# (uuid, hrn, public_key)
+# GID is a tuple:
+# (uuid, urn, public_key)
#
# UUID is a unique identifier and is created by the python uuid module
# (or the utility function create_uuid() in gid.py).
def __init__(self, create=False, subject=None, string=None, filename=None, uuid=None, hrn=None, urn=None):
Certificate.__init__(self, create, subject, string, filename)
+ if subject:
+ logger.info("subject: %s" % subject)
if uuid:
- self.uuid = uuid
+ self.uuid = int(uuid)
if hrn:
self.hrn = hrn
+ self.urn = hrn_to_urn(hrn, 'unknown')
if urn:
self.urn = urn
self.hrn, type = urn_to_hrn(urn)
def set_uuid(self, uuid):
- self.uuid = uuid
+ if isinstance(uuid, str):
+ self.uuid = int(uuid)
+ else:
+ self.uuid = uuid
def get_uuid(self):
if not self.uuid:
self.decode()
return self.urn
+ def get_type(self):
+ if not self.urn:
+ self.decode()
+ _, t = urn_to_hrn(self.urn)
+ return t
+
##
# Encode the GID fields and package them into the subject-alt-name field
# of the X509 certificate. This must be called prior to signing the
urn = self.urn
else:
urn = hrn_to_urn(self.hrn, None)
-
- dict = {"uuid": self.uuid,
- "urn": self.urn}
- str = xmlrpclib.dumps((dict,))
- self.set_data(str)
+
+ str = "URI:" + urn
+
+ if self.uuid:
+ str += ", " + "URI:" + uuid.UUID(int=self.uuid).urn
+
+ self.set_data(str, 'subjectAltName')
+
+
+
##
# Decode the subject-alt-name field of the X509 certificate into the
# functions in this class.
def decode(self):
- data = self.get_data()
+ data = self.get_data('subjectAltName')
+ dict = {}
if data:
- dict = xmlrpclib.loads(self.get_data())[0][0]
- else:
- dict = {}
-
+ if data.lower().startswith('uri:http://<params>'):
+ dict = xmlrpclib.loads(data[11:])[0][0]
+ else:
+ spl = data.split(', ')
+ for val in spl:
+ if val.lower().startswith('uri:urn:uuid:'):
+ dict['uuid'] = uuid.UUID(val[4:]).int
+ elif val.lower().startswith('uri:urn:publicid:idn+'):
+ dict['urn'] = val[4:]
+
self.uuid = dict.get("uuid", None)
self.urn = dict.get("urn", None)
self.hrn = dict.get("hrn", None)
def verify_chain(self, trusted_certs = None):
# do the normal certificate verification stuff
- Certificate.verify_chain(self, trusted_certs)
-
+ trusted_root = Certificate.verify_chain(self, trusted_certs)
+
if self.parent:
# make sure the parent's hrn is a prefix of the child's hrn
if not self.get_hrn().startswith(self.parent.get_hrn()):
raise GidParentHrn(self.parent.get_subject())
+ else:
+ # make sure that the trusted root's hrn is a prefix of the child's
+ trusted_gid = GID(string=trusted_root.save_to_string())
+ trusted_hrn = trusted_gid.get_hrn()
+ cur_hrn = self.get_hrn()
+ if not self.get_hrn().startswith(trusted_hrn):
+ raise GidParentHrn(trusted_hrn + " " + self.get_hrn())
return
self.gid_filename = fn
self.gid_object = None
+ def get_privkey_filename(self):
+ return self.privkey_filename
+
+ def get_gid_filename(self):
+ return self.gid_filename
+
##
# Get the GID in the form of a GID object
# create the parent authority if necessary
parent_hrn = get_authority(hrn)
- if (parent_hrn) and (not self.auth_exists(parent_hrn)) and (create_parents):
- self.create_auth(parent_hrn, create_parents)
+ parent_urn = hrn_to_urn(parent_hrn, 'authority')
+ if (parent_hrn) and (not self.auth_exists(parent_urn)) and (create_parents):
+ self.create_auth(parent_urn, create_parents)
(directory, gid_filename, privkey_filename, dbinfo_filename) = \
self.get_auth_filenames(hrn)
cred.set_gid_caller(gid)
cred.set_gid_object(gid)
cred.set_privileges(kind)
- cred.set_delegate(True)
- cred.set_pubkey(auth_info.get_gid_object().get_pubkey())
+ cred.get_privileges().delegate_all_privileges(True)
+ #cred.set_pubkey(auth_info.get_gid_object().get_pubkey())
parent_hrn = get_authority(hrn)
if not parent_hrn or hrn == self.config.SFA_INTERFACE_HRN:
# if there is no parent hrn, then it must be self-signed. this
# is where we terminate the recursion
- cred.set_issuer(auth_info.get_pkey_object(), hrn)
+ cred.set_issuer_keys(auth_info.get_privkey_filename(), auth_info.get_gid_filename())
else:
# we need the parent's private key in order to sign this GID
parent_auth_info = self.get_auth_info(parent_hrn)
- cred.set_issuer(parent_auth_info.get_pkey_object(), parent_auth_info.hrn)
+ cred.set_issuer_keys(parent_auth_info.get_privkey_filename(), parent_auth_info.get_gid_filename())
+
+
cred.set_parent(self.get_auth_cred(parent_hrn, kind))
cred.encode()
# allows "listslices", "listcomponentresources", etc.
##
+
+
##
# privilege_table is a list of priviliges and what operations are allowed
# per privilege.
+# Note that "*" is a privilege granted by ProtoGENI slice authorities, and we
+# give it access to the GENI AM calls
privilege_table = {"authority": ["register", "remove", "update", "resolve", "list", "getcredential", "*"],
"refresh": ["remove", "update"],
"resolve": ["resolve", "list", "getcredential"],
- "sa": ["getticket", "redeemslice", "redeemticket", "createslice", "deleteslice", "updateslice",
- "getsliceresources", "getticket", "loanresources", "stopslice", "startslice",
- "deleteslice", "resetslice", "listslices", "listnodes", "getpolicy"],
- "embed": ["getticket", "redeemslice", "redeemticket", "createslice", "deleteslice", "updateslice", "getsliceresources"],
+ "sa": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "deleteslice", "deletesliver", "updateslice",
+ "getsliceresources", "getticket", "loanresources", "stopslice", "startslice", "renewsliver",
+ "deleteslice", "deletesliver", "resetslice", "listslices", "listnodes", "getpolicy", "sliverstatus"],
+ "embed": ["getticket", "redeemslice", "redeemticket", "createslice", "createsliver", "renewsliver", "deleteslice", "deletesliver", "updateslice", "sliverstatus", "getsliceresources", "shutdown"],
"bind": ["getticket", "loanresources", "redeemticket"],
- "control": ["updateslice", "createslice", "stopslice", "startslice", "deleteslice", "resetslice", "getsliceresources", "getgids"],
+ "control": ["updateslice", "createslice", "createsliver", "renewsliver", "sliverstatus", "stopslice", "startslice", "deleteslice", "deletesliver", "resetslice", "getsliceresources", "getgids"],
"info": ["listslices", "listnodes", "getpolicy"],
"ma": ["setbootstate", "getbootstate", "reboot", "getgids", "gettrustedcerts"],
- "operator": ["gettrustedcerts", "getgids"]}
+ "operator": ["gettrustedcerts", "getgids"],
+ "*": ["createsliver", "deletesliver", "sliverstatus", "renewsliver", "shutdown"]}
+
##
rl.add("resolve")
rl.add("info")
elif type == "sa":
- rl.add("authority,sa")
+ rl.add("authority")
+ rl.add("sa")
elif type == "ma":
- rl.add("authority,ma")
+ rl.add("authority")
+ rl.add("ma")
elif type == "authority":
- rl.add("authority,sa,ma")
+ rl.add("authority")
+ rl.add("sa")
+ rl.add("ma")
elif type == "slice":
rl.add("refresh")
rl.add("embed")
class Right:
- ##
- # Create a new right.
- #
- # @param kind is a string naming the right. For example "control"
+ ##
+ # Create a new right.
+ #
+ # @param kind is a string naming the right. For example "control"
+
+ def __init__(self, kind, delegate=False):
+ self.kind = kind
+ self.delegate = delegate
- def __init__(self, kind):
- self.kind = kind
+ ##
+ # Test to see if this right object is allowed to perform an operation.
+ # Returns True if the operation is allowed, False otherwise.
+ #
+ # @param op_name is a string naming the operation. For example "listslices".
- ##
- # Test to see if this right object is allowed to perform an operation.
- # Returns True if the operation is allowed, False otherwise.
- #
- # @param op_name is a string naming the operation. For example "listslices".
+ def can_perform(self, op_name):
+ allowed_ops = privilege_table.get(self.kind.lower(), None)
+ if not allowed_ops:
+ return False
- def can_perform(self, op_name):
- allowed_ops = privilege_table.get(self.kind.lower(), None)
- if not allowed_ops:
- return False
+ # if "*" is specified, then all ops are permitted
+ if "*" in allowed_ops:
+ return True
- # if "*" is specified, then all ops are permitted
- if "*" in allowed_ops:
- return True
+ return (op_name.lower() in allowed_ops)
- return (op_name.lower() in allowed_ops)
+ ##
+ # Test to see if this right is a superset of a child right. A right is a
+ # superset if every operating that is allowed by the child is also allowed
+ # by this object.
+ #
+ # @param child is a Right object describing the child right
- ##
- # Test to see if this right is a superset of a child right. A right is a
- # superset if every operating that is allowed by the child is also allowed
- # by this object.
- #
- # @param child is a Right object describing the child right
+ def is_superset(self, child):
+ my_allowed_ops = privilege_table.get(self.kind.lower(), None)
+ child_allowed_ops = privilege_table.get(child.kind.lower(), None)
- def is_superset(self, child):
- my_allowed_ops = privilege_table.get(self.kind.lower(), None)
- child_allowed_ops = privilege_table.get(child.kind.lower(), None)
+ if not self.delegate:
+ return False
- if "*" in my_allowed_ops:
- return True
+ if "*" in my_allowed_ops:
+ return True
- for right in child_allowed_ops:
- if not right in my_allowed_ops:
- return False
+ for right in child_allowed_ops:
+ if not right in my_allowed_ops:
+ return False
- return True
+ return True
##
# A RightList object represents a list of privileges.
#
# @param right is either a Right object or a string describing the right
- def add(self, right):
+ def add(self, right, delegate=False):
if isinstance(right, str):
- right = Right(kind = right)
+ right = Right(right, delegate)
self.rights.append(right)
##
parts = string.split(",")
for part in parts:
- self.rights.append(Right(part))
+ if ':' in part:
+ spl = part.split(':')
+ kind = spl[0].strip()
+ delegate = bool(int(spl[1]))
+ else:
+ kind = part.strip()
+ delegate = 0
+ self.rights.append(Right(kind, bool(delegate)))
##
# Save the rightlist object to a string. It is saved in the format of a
def save_to_string(self):
right_names = []
for right in self.rights:
- right_names.append(right.kind)
+ right_names.append('%s:%d' % (right.kind.strip(), right.delegate))
return ",".join(right_names)
##
- # Determine tje rights that an object should have. The rights are entirely
+ # set the delegate bit to 'delegate' on
+ # all privileges
+ #
+ # @param delegate boolean (True or False)
+
+ def delegate_all_privileges(self, delegate):
+ for right in self.rights:
+ right.delegate = delegate
+
+ ##
+ # true if all privileges have delegate bit set true
+ # false otherwise
+
+ def get_all_delegate(self):
+ for right in self.rights:
+ if not right.delegate:
+ return False
+ return True
+
+
+
+ ##
+ # Determine the rights that an object should have. The rights are entirely
# dependent on the type of the object. For example, users automatically
# get "refresh", "resolve", and "info".
#
rl.add("resolve")
rl.add("info")
elif type == "sa":
- rl.add("authority,sa")
+ rl.add("authority")
+ rl.add("sa")
elif type == "ma":
- rl.add("authority,ma")
+ rl.add("authority")
+ rl.add("ma")
elif type == "authority":
- rl.add("authority,sa,ma")
+ rl.add("authority")
+ rl.add("sa")
+ rl.add("ma")
elif type == "slice":
rl.add("refresh")
rl.add("embed")
return gid_list
+ def get_file_list(self):
+ gid_file_list = []
+
+ file_list = os.listdir(self.basedir)
+ for gid_file in file_list:
+ fn = os.path.join(self.basedir, gid_file)
+ if os.path.isfile(fn):
+ gid_file_list.append(fn)
+
+ return gid_file_list
Return a new instance of the specified method.
"""
# Look up method
+ print self.methods
if method not in self.methods:
raise SfaInvalidAPIMethod, method
self.source = source
return function(*args)
- def handle(self, source, data):
+
+ def handle(self, source, data, method_map):
"""
Handle an XML-RPC or SOAP request from the specified source.
"""
try:
interface = xmlrpclib
(args, method) = xmlrpclib.loads(data)
+ if method_map.has_key(method):
+ method = method_map[method]
methodresponse = True
+
except Exception, e:
if SOAPpy is not None:
interface = SOAPpy
SfaFault.__init__(self, 111, faultString, extra)
def __str__(self):
return repr(self.value)
-
+
+
class NonexistingCredType(SfaFault):
def __init__(self, value, extra = None):
self.value = value
return repr(self.value)
class NonexistingFile(SfaFault):
- def __init__(self, value):
+ def __init__(self, value, extra = None):
self.value = value
faultString = "Non existing file: %(value)s, " % locals()
SfaFault.__init__(self, 111, faultString, extra)
return repr(self.value)
class InvalidRPCParams(SfaFault):
- def __init__(self, value):
+ def __init__(self, value, extra = None):
self.value = value
faultString = "Invalid RPC Params: %(value)s, " % locals()
SfaFault.__init__(self, 102, faultString, extra)
SfaFault.__init__(self, 103, faultString, extra)
def __str__(self):
return repr(self.value)
-
+
+class GidParentHrn(SfaFault):
+ def __init__(self, value, extra = None):
+ self.value = value
+ faultString = "Cert URN is not an extension of its parent: %(value)s" % locals()
+ SfaFault.__init__(self, 103, faultString, extra)
+ def __str__(self):
+ return repr(self.value)
+
class GidInvalidParentHrn(SfaFault):
def __init__(self, value, extra = None):
self.value = value
return repr(self.value)
class BadRequestHash(xmlrpclib.Fault):
- def __init__(self, hash = None):
+ def __init__(self, hash = None, extra = None):
faultString = "bad request hash: " + str(hash)
xmlrpclib.Fault.__init__(self, 902, faultString)
def __str__(self):
return repr(self.value)
+class CredentialNotVerifiable(SfaFault):
+ def __init__(self, value, extra = None):
+ self.value = value
+ faultString = "Unable to verify credential: %(value)s, " %locals()
+ SfaFault.__init__(self, 115, faultString, extra)
+ def __str__(self):
+ return repr(self.value)
parts = hrn.split(".")
return ".".join(parts[-1:])
-def get_authority(hrn):
+def get_authority(xrn):
+ hrn, type = urn_to_hrn(xrn)
+ if type and type == 'authority':
+ return hrn
+
parts = hrn.split(".")
return ".".join(parts[:-1])
authority = get_authority(hrn)
name = get_leaf(hrn)
- urn = "+".join([unicode(part).replace('.', ':') \
- for part in ['',authority,type,name]])
-
+
+ if authority.startswith("plc"):
+ if type == None:
+ urn = "+".join(['',authority.replace('.',':'),name])
+ else:
+ urn = "+".join(['',authority.replace('.',':'),type,name])
+
+ else:
+ urn = "+".join(['',authority,type,name])
+
return URN_PREFIX + urn
# get arguments
request = self.rfile.read(int(self.headers["content-length"]))
remote_addr = (remote_ip, remote_port) = self.connection.getpeername()
- self.api.remote_addr = remote_addr
- response = self.api.handle(remote_addr, request)
+ self.api.remote_addr = remote_addr
+ response = self.api.handle(remote_addr, request, self.server.method_map)
except Exception, fault:
self.interface = None
self.key_file = key_file
self.cert_file = cert_file
+ self.method_map = {}
# add cache to the request handler
HandlerClass.cache = Cache()
#for compatibility with python 2.4 (centos53)
##
# Register functions that will be served by the XMLRPC server. This
- # function should be overrided by each descendant class.
+ # function should be overridden by each descendant class.
def register_functions(self):
self.server.register_function(self.noop)
import logging
+import os
#SFA access log initialization
-
+TMPDIR = os.getenv("TMPDIR", "/tmp")
+SFA_HTTPD_ACCESS_LOGFILE = TMPDIR + "/" + 'sfa_httpd_access.log'
SFA_ACCESS_LOGFILE='/var/log/sfa_access.log'
-SFA_HTTPD_ACCESS_LOGFILE='/tmp/sfa_httpd_access.log'
logger=logging.getLogger()
logger.setLevel(logging.INFO)
+
try:
- logfile=logging.FileHandler(SFA_ACCESS_LOGFILE)
+ logfile=logging.FileHandler(SFA_ACCESS_LOGFILE)
except IOError:
- # This is usually a permissions error becaue the file is
- # owned by root, but httpd is trying to access it.
- logfile=logging.FileHandler(SFA_HTTPD_ACCESS_LOGFILE)
+ # This is usually a permissions error becaue the file is
+ # owned by root, but httpd is trying to access it.
+ logfile=logging.FileHandler(SFA_HTTPD_ACCESS_LOGFILE)
+
formatter = logging.Formatter("%(asctime)s - %(message)s")
logfile.setFormatter(formatter)
logger.addHandler(logfile)
if record_filter:
records = self.find(record_filter)
- for record in reocrds:
+ for record in records:
self.append(record)
def exists(self):