From 455f3a3cfa775a386a66db8ca0a040f7c5b33d29 Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Fri, 3 Oct 2008 00:33:50 +0000 Subject: [PATCH] check in latest updates to documentation --- util/cert.py | 13 +- util/config.py | 35 +- util/credential.py | 4 +- util/db.py | 81 ----- util/excep.pyc | Bin 3020 -> 12102 bytes util/geniclient.py | 205 ++++++++++- util/geniserver.py | 56 ++- util/gid.py | 84 ++++- util/hierarchy.py | 125 ++++++- util/misc.py | 7 +- util/pl_to_geni.py | 174 --------- util/record.py | 109 +++++- util/rights.py | 74 +++- util/sec/certgen.py | 111 ------ util/sec/certgen.pyc | Bin 4119 -> 0 bytes util/sec/certgen2.py | 368 ------------------- util/sec/certgen_m2crypto.py | 20 - util/sec/certs/den.py | 43 --- util/sec/certs/gen.py | 57 --- util/sec/certs/jp.cert | 11 - util/sec/certs/jp.pkey | 15 - util/sec/certs/planetlab.cert | 11 - util/sec/certs/planetlab.pkey | 15 - util/sec/certs/usersoner.cert | 11 - util/sec/sec.py | 663 ---------------------------------- util/sec/sec.pyc | Bin 18124 -> 0 bytes 26 files changed, 635 insertions(+), 1657 deletions(-) delete mode 100644 util/db.py delete mode 100644 util/pl_to_geni.py delete mode 100755 util/sec/certgen.py delete mode 100644 util/sec/certgen.pyc delete mode 100755 util/sec/certgen2.py delete mode 100755 util/sec/certgen_m2crypto.py delete mode 100644 util/sec/certs/den.py delete mode 100644 util/sec/certs/gen.py delete mode 100644 util/sec/certs/jp.cert delete mode 100644 util/sec/certs/jp.pkey delete mode 100644 util/sec/certs/planetlab.cert delete mode 100644 util/sec/certs/planetlab.pkey delete mode 100644 util/sec/certs/usersoner.cert delete mode 100644 util/sec/sec.py delete mode 100644 util/sec/sec.pyc diff --git a/util/cert.py b/util/cert.py index 1994af5e..5d4796e0 100644 --- a/util/cert.py +++ b/util/cert.py @@ -192,13 +192,6 @@ class Certificate: def load_from_pyopenssl_x509(self, x509): self.cert = x509 - ## - # Return another instance of the same class. - # XXX: probably will be deleted, can use cls() function instead - - def create_similar(self): - return Certificate() - ## # Load the certificate from a string @@ -211,7 +204,7 @@ class Certificate: # 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.create_similar() + self.parent = self.__class__() self.parent.load_from_string(parts[1]) ## @@ -429,7 +422,9 @@ class Certificate: return self.parent ## - # Verify a chain of certificates. + # 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:
    #     if this_certificate was signed by trusted_certs:
diff --git a/util/config.py b/util/config.py
index 08548098..562aee17 100644
--- a/util/config.py
+++ b/util/config.py
@@ -1,10 +1,18 @@
-# config.py
+##
+# Geniwrapper Configuration Info
 #
-# geniwrapper configuration info
+# This module holds configuration parameters for geniwrapper. There are two
+# main pieces of information that are used: the database connection and
+# the PLCAPI connection
+##
+
+##
+# Geniwrapper uses a MYSQL database to store records. This database may be
+# co-located with the PLC database, or it may be a separate database. The
+# following parameters define the connection to the database.
 #
-# this module holds configuration parameters for geniwrapper. The wrapper
-# needs an account to connect to PLC with and a database to store geni
-# tables
+# Note that Geniwrapper does not access any of the PLC databases directly via
+# a mysql connection; All PLC databases are accessed via PLCAPI.
 
 def get_default_dbinfo():
     dbinfo={}
@@ -16,4 +24,21 @@ def get_default_dbinfo():
 
     return dbinfo
 
+##
+# Geniwrapper uses a PLCAPI connection to perform operations on the registry,
+# such as creating and deleting slices. This connection requires an account
+# on the PLC server with full administrator access.
+#
+# The Url parameter controls whether the connection uses PLCAPI directly (i.e.
+# Geniwrapper is located on the same machine as PLC), or uses a XMLRPC connection
+# to the PLC machine. If you wish to use the API directly, then remove the Url
+# field from the dictionary. 
+
+def get_pl_auth():
+    pl_auth = {'Username': 'root@198.0.0.132',
+    'AuthMethod': 'password',
+    'AuthString':  'root',
+    "Url": "https://localhost:443/PLCAPI/"
+    }
 
+    return pl_auth
diff --git a/util/credential.py b/util/credential.py
index 0daaf422..697adf05 100644
--- a/util/credential.py
+++ b/util/credential.py
@@ -1,9 +1,9 @@
 ##
-#
 # Implements Geni Credentials
 #
 # Credentials are layered on top of certificates, and are essentially a
 # certificate that stores a tuple of parameters.
+##
 
 from cert import *
 from rights import *
@@ -189,6 +189,8 @@ class Credential(Certificate):
     # 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
diff --git a/util/db.py b/util/db.py
deleted file mode 100644
index 590a0020..00000000
--- a/util/db.py
+++ /dev/null
@@ -1,81 +0,0 @@
-import os
-from pg import DB
-from excep import *
-from tree import *
-from util import *
-
-#planetlab authentication structure
-pl_auth = {'Username': 'ssevinc@princeton.edu',        # User account
-'AuthMethod': 'password',        # Type of auth this is. Can be password, session ...
-'AuthString':  'Ss3928Ee' # the password for this account
-} 
-
-def get_plDB_conn():
-    dbname = 'plDB'
-    address = 'localhost'
-    port = 5433
-    user = 'postgres'
-    password = '111'
-    cnx = DB(dbname, address, port=port, user=user, passwd=password)
-    return cnx
-    
-#copy the pl db info to requester
-def get_plDB_info(dst):
-    dst.db_name = 'plDB'
-    dst.address = 'localhost'
-    dst.port = 5433
-    dst.user = 'postgres'
-    dst.password = '111'
-
-
-#determines the database info of a given hrn
-#if the hrn does not exist in the tree hierarchy None is returned
-def determine_dbinfo(hrn, tree):
-    info = tree.tree_lookup(hrn)
-    if info == None:
-        return None
-    else:
-        db_info = info.node_data['db_info']
-        cnx = DB(db_info.db_name, db_info.address, port = db_info.port, user = db_info.user, passwd = db_info.password)
-        tablename = db_info.table_name
-        return [cnx, tablename]
-
-#convert the parameter list to query string suitable for supplying to database queries
-#input: query type, table name and field-value pairs
-def generate_querystr(type, table, dict):
-    querystr = ""
-    if type == 'INSERT':
-        keys = dict.keys()
-        str1 = keys[0]
-        for i in range(1, len(keys)):
-            str1 = str1 + ','+ keys[i]
-        str2 = ""
-        for i in range(len(keys)-1):
-            if isinstance(dict[keys[i]],str):
-                str2 = str2 + "'" + dict[keys[i]] + "', " 
-            else:
-                str2 = str2 + str(dict[keys[i]]) + ", "
-        if isinstance(dict[keys[len(keys)-1]],str):
-            str2 = str2 + "'" + dict[keys[len(keys)-1]] + "'" 
-        else:
-            str2 = str2 + str(dict[keys[len(keys)-1]]) 
-        querystr = "INSERT INTO "+table+ "(" + str1 + ") VALUES(" + str2 + ")"
-    elif type == 'UPDATE':
-        str1 = ""
-        keys = dict.keys()
-        for i in range(len(keys)-1):
-            if keys[i] != 'hrn':
-                if isinstance(dict[keys[i]],str):
-                    str1 = str1 + keys[i] + " = '" + dict[keys[i]] + "', " 
-                else:
-                    str1 = str1 + keys[i] + " = " + dict[keys[i]] + ", " 
-        if keys[len(keys)-1] != 'hrn':
-            if isinstance(dict[keys[len(keys)-1]],str):
-                str1 = str1 + keys[len(keys)-1] + " = '" + dict[keys[len(keys)-1]] + "'" 
-            else:
-                str1 = str1 + keys[len(keys)-1] + " = '" + dict[keys[len(keys)-1]]
-        querystr = "UPDATE "+table+ " SET " + str1 + " WHERE hrn = '"+get_leaf(dict["hrn"])+"'"
-    elif type == 'DELETE':
-        querystr = "DELETE FROM "+table+" WHERE hrn = '"+get_leaf(dict["hrn"])+"'"
-    return querystr
-            
diff --git a/util/excep.pyc b/util/excep.pyc
index 3aa377e54ed3851881a5d7450ad1120da0234575..edb7e87d25158f251adddb80e54f919932fb4627 100644
GIT binary patch
literal 12102
zcmds-*>2lL6o!wy@4KD7O`0ZAS|CD!76rN?vAo1+>=>g2XdIvdtr^LTDN-dzb_As8
zMfyg)>2vh5kI^US`6+Qmy-Z;b2+AN${*uU_XFi=-|M+KqrupaJPa8CNjq?A;yd{5?
zh$N9BYL-Zr=y#&`M6ZtcWF%8ZjXFYdEK|pgI!baPQzwl&Msg}sr;R#Jawbz}jXFVc
zE>q`?I!SUNQx}aoMRF-qmyJ42awSt&jXFbeEmPNxI!kgRQ?D3xj^x!$y=K&TlGii!
zhEW$t-ptfnMqMQNQKo)u)FqO)Gxd&9mq~t-sdtUKLh{p0y=T-_lJ_(9fl=2;mNWIC
zQP)X+Mz!+iT()|hcl%z@jN-PEPvda=Z9{dmAB6@3E_~Vq2G@DV44~Kv*E-^oPGLA2
zB~dGn@Y@aSvaO0Q&GYVEiQW;_Q;2G1T<;*=>v29j^MbBQzpTgb1r;;}K2qkbze~3G
zsB#juRV8U3d#5U{bmHiZYUrfW3A|A0z&qxnMx~`f|2+0O9sY=pyWwf2tNoy&@Jx?7
zJw3%2s@MI{*Y!H+PGFTv4creKPK|5L#)lAwMOAo^($ToyQKJg50C{|gv_5M4ejX?f3DlPM))0`~?+4w%5t3!7zPna>WQ
zP`&jN?T0O)8c{48ET%8~bT)ar_{`#xi$y#E5d6?Y;*tv##Bla-$_0Ko3ou}E1sF76?d&k_f*XB&2Phi$rnp}wij~$!I$E&dg#SoJ1JPQcz_4a
zd)wlnHR&D;^g8atfWhJ_pH-tU~7(9?Q7>9(rBULX5RLpo342!R9#Pf^A*Vd$aEYP6%5(W$w0HxnOJ&5#9)D4T)
zP5su!JHJqTZ%w*~0-50(7%)%(lb7LX7@dc^JhWKA-pCUh@cdFywIv9oWYWcSc-h^Cw=eN6UY@Co@0+Gmv%w;^KJ>6J_Qz2W#+8{=~R~O#mpQr#JZuQ#p*;
z%A5dW%Cl^NF&p`XCo8Z=0 and alg_count>=0:
-        if alg_count == 0:
-            login_base = login_base+hrn_arr[j]
-        j = j-1
-        alg_count = alg_count-1
-    if len(login_base) > 20:
-        return login_base[0:20]
-    else:
-        return login_base
-        
-    
-#given an email or person_id (which are ids of a person in Planetlab), determined the last portion of hierarchical name of it in GENI
-def person_to_user(email, algorithm = 0):
-    hrn_suffix = ''
-    if algorithm == 0:
-        hrn_suffix = email.split('@')[0].replace('.','-')
-    elif algorithm == 1:
-        hrn_suffix = email.split('@')[0].replace('.','-')+'-'+email.split('@')[1].split('.')[0]
-    elif algorithm == 2:
-        hrn_suffix = email.replace('@','-')
-        hrn_suffix = hrn_suffix.replace('.','-')
-    return hrn_suffix
-    
-def plslice_to_slice(slice_name):
-    i = 0
-    while slice_name[i]!='_':
-        i = i+1
-    return slice_name[i+1:len(slice_name)]
-    
-def plnode_to_node(hostname, algorithm = 0):
-    hrn_suffix = ''
-    if algorithm == 0:
-        hrn_suffix = hostname.split('.')[0]
-    elif algorithm == 1:
-        hrn_suffix = hostname.split('.')[0]+'-'+hostname.split('.')[1]
-    elif algorithm == 2:
-        hrn_suffix = hrn_suffix.replace('.','-')
-    return hrn_suffix
-    
-def check_exists_pl(cnx, pointer, type):
-    exists = True
-    if type == 'SA' or type == 'MA':
-        res = cnx.query("SELECT deleted FROM sites WHERE site_id = "+str(pointer)).dictresult()
-        if len(res)==0 or res[0]['deleted'] == 't':
-            exists = False
-    elif type == 'slice':
-        res = cnx.query("SELECT is_deleted FROM slices WHERE slice_id = "+str(pointer)).dictresult()
-        if len(res)==0 or res[0]['is_deleted'] == 't':
-            exists = False
-    elif type == 'user':
-        res = cnx.query("SELECT deleted FROM persons WHERE person_id = "+str(pointer)).dictresult()
-        if len(res)==0 or res[0]['deleted'] == 't':
-            exists = False
-    elif type == 'node':
-        res = cnx.query("SELECT deleted FROM nodes WHERE node_id = "+str(pointer)).dictresult()
-        if len(res)==0 or res[0]['deleted'] == 't':
-            exists = False
-    return exists
-    
-def check_exists_geni(record, dbinfo):
-    cnx = dbinfo[0]
-    table = dbinfo[1] 
-    try:
-        #lookup in GENI tables
-        geni_res = cnx.query("SELECT * FROM "+table+" WHERE hrn = '"+get_leaf(record['g_params']["hrn"])+"' ").dictresult()
-        if geni_res:
-            return geni_res[0]
-        else:
-            return None
-    except:
-        return None
-        
-#fill the geni table with the records in PL database
-#login_base: indicates the site in PL
-#tablename: the GENI table name
-#type: 'slice' or 'component' indicating the registry type of the GENI table
-def populate_pl_data(login_base, tablename, type):
-    cnx = get_plDB_conn()
-    site_id = cnx.query("SELECT site_id FROM sites WHERE login_base='"+login_base+"';").dictresult()[0]['site_id']
-    
-    if type == 'slice': #slice registry
-        #populate user records
-        querystr = "SELECT p.person_id, p.email FROM persons as p, person_site as ps WHERE p.person_id = ps.person_id AND  ps.site_id = "+str(site_id)
-        users = cnx.query(querystr).dictresult()
-        for user in users:
-            new_hrn = person_to_user(user['email'])
-            existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ").dictresult()
-            if len(existing) > 0:
-                new_hrn = person_to_user(user['email'], 1)
-                existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ").dictresult()
-                if len(existing) > 0:
-                    new_hrn = person_to_user(user['email'], 2)
-            cnx.query("INSERT INTO "+tablename+"(hrn,type,wrapperurl,pointer) VALUES('"+new_hrn+"','user','local',"+str(user['person_id'])+")")
-        #populate slice records
-        querystr = "SELECT slice_id, name FROM slices WHERE site_id = "+str(site_id)
-        slices = cnx.query(querystr).dictresult()
-        for slice in slices:
-            slcname = slice['name'].split('_')
-            if slcname[len(slcname)-1] != 'deleted':
-                new_hrn = plslice_to_slice(slice['name'])
-                existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ").dictresult()
-                if len(existing) > 0:
-                    new_hrn = new_hrn+'-'+str(slice['slice_id'])
-                cnx.query("INSERT INTO "+tablename+"(hrn,type,wrapperurl,pointer) VALUES('"+new_hrn+"','slice','local',"+str(slice['slice_id'])+")")
-                
-    if type == 'component': #component registry
-        #populate node records
-        querystr = "SELECT node_id, hostname FROM nodes WHERE site_id = "+str(site_id)
-        nodes = cnx.query(querystr).dictresult()
-        for node in nodes:
-            new_hrn = plnode_to_node(node['hostname'], 0)
-            existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ").dictresult()
-            if len(existing) > 0:
-                new_hrn = plnode_to_node(node['hostname'], 1)
-                existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ").dictresult()
-                if len(existing) > 0:
-                    new_hrn = plnode_to_node(node['hostname'], 2)
-            cnx.query("INSERT INTO "+tablename+"(hrn,type,wrapperurl,pointer) VALUES('"+new_hrn+"','node','local',"+str(node['node_id'])+")")
-        
diff --git a/util/record.py b/util/record.py
index dfa8d1b8..2d6d7acf 100644
--- a/util/record.py
+++ b/util/record.py
@@ -8,13 +8,37 @@ import report
 from gid import *
 
 ##
-# GeniRecord is a tuple (Name, GID, Type, Info)
-#    info is comprised of the following sub-fields
+# The GeniRecord class implements a Geni Record. A GeniRecord is a tuple
+# (Name, GID, Type, Info).
+#
+# Name specifies the HRN of the object
+# GID is the GID of the object
+# Type is user | sa | ma | slice | component
+#
+# Info is comprised of the following sub-fields
 #        pointer = a pointer to the record in the PL database
 #        pl_info = planetlab-specific info (when talking to client)
 #        geni_info = geni-specific info (when talking to client)
+#
+# The pointer is interpreted depending on the type of the record. For example,
+# if the type=="user", then pointer is assumed to be a person_id that indexes
+# into the persons table.
+#
+# A given HRN may have more than one record, provided that the records are
+# of different types. For example, planetlab.us.arizona may have both an SA
+# and a MA record, but cannot have two SA records.
 
 class GeniRecord():
+
+    ##
+    # Create a Geni Record
+    #
+    # @param name if !=None, assign the name of the record
+    # @param gid if !=None, assign the gid of the record
+    # @param type one of user | sa | ma | slice | component
+    # @param pointer is a pointer to a PLC record
+    # @param dict if !=None, then fill in this record from the dictionary
+
     def __init__(self, name=None, gid=None, type=None, pointer=None, dict=None):
         self.dirty = True
         self.pl_info = None
@@ -37,10 +61,20 @@ class GeniRecord():
             if "geni_info" in dict:
                self.set_geni_info(dict["geni_info"])
 
+    ##
+    # Set the name of the record
+    #
+    # @param name is a string containing the HRN
+
     def set_name(self, name):
         self.name = name
         self.dirty = True
 
+    ##
+    # Set the GID of the record
+    #
+    # @param gid is a GID object or the string representation of a GID object
+
     def set_gid(self, gid):
         if isinstance(gid, str):
             self.gid = gid
@@ -48,53 +82,109 @@ class GeniRecord():
             self.gid = gid.save_to_string(save_parents=True)
         self.dirty = True
 
+    ##
+    # Set the type of the record
+    #
+    # @param type is a string: user | sa | ma | slice | component
+
     def set_type(self, type):
         self.type = type
         self.dirty = True
 
+    ##
+    # Set the pointer of the record
+    #
+    # @param pointer is an integer containing the ID of a PLC record
+
     def set_pointer(self, pointer):
         self.pointer = pointer
         self.dirty = True
 
+    ##
+    # Set the PLC info of the record
+    #
+    # @param pl_info is a dictionary containing planetlab info
+
     def set_pl_info(self, pl_info):
         self.pl_info = pl_info
         self.dirty = True
 
+    ##
+    # Set the geni info the record
+    #
+    # @param geni_info is a dictionary containing geni info
+
     def set_geni_info(self, geni_info):
         self.geni_info = geni_info
         self.dirty = True
 
+    ##
+    # Return the pl_info of the record, or an empty dictionary if none exists
+
     def get_pl_info(self):
         if self.pl_info:
             return self.pl_info
         else:
             return {}
 
+    ##
+    # Return the geni_info of the record, or an empty dictionary if none exists
+
     def get_geni_info(self):
         if self.geni_info:
             return self.geni_info
         else:
             return {}
 
+    ##
+    # Return the name (HRN) of the record
+
     def get_name(self):
         return self.name
 
+    ##
+    # Return the type of the record
+
     def get_type(self):
         return self.type
 
+    ##
+    # Return the pointer of the record. The pointer is an integer that may be
+    # used to look up the record in the PLC database. The evaluation of pointer
+    # depends on the type of the record
+
     def get_pointer(self):
         return self.pointer
 
-    # TODO: not the best name for the function, because we have things called gidObjects in the Cred
+    ##
+    # Return the GID of the record, in the form of a GID object
+    # TODO: not the best name for the function, because we have things called
+    # gidObjects in the Cred
+
     def get_gid_object(self):
         return GID(string=self.gid)
 
+    ##
+    # Return a key that uniquely identifies this record among all records in
+    # Geni. This key is used to uniquely identify the record in the Geni
+    # database.
+
     def get_key(self):
         return self.name + "#" + self.type
 
+    ##
+    # Returns a list of field names in this record. pl_info, geni_info are not
+    # included because they are not part of the record that is stored in the
+    # database, but are rather computed values from other entities
+
     def get_field_names(self):
         return ["name", "gid", "type", "pointer"]
 
+    ##
+    # Given a field name ("name", "gid", ...) return the value of that field.
+    #
+    # @param name is the name of field to be returned
+
     def get_field_value_string(self, fieldname):
         if fieldname == "key":
             val = self.get_key()
@@ -105,12 +195,20 @@ class GeniRecord():
         else:
             return str(val)
 
+    ##
+    # Given a list of field names, return a list of values for those fields.
+    #
+    # @param fieldnames is a list of field names
+
     def get_field_value_strings(self, fieldnames):
         strs = []
         for fieldname in fieldnames:
             strs.append(self.get_field_value_string(fieldname))
         return strs
 
+    ##
+    # Return the record in the form of a dictionary
+
     def as_dict(self):
         dict = {}
         names = self.get_field_names()
@@ -125,6 +223,11 @@ class GeniRecord():
 
         return dict
 
+    ##
+    # Dump the record to stdout
+    #
+    # @param dump_parents if true, then the parents of the GID will be dumped
+
     def dump(self, dump_parents=False):
         print "RECORD", self.name
         print "        hrn:", self.name
diff --git a/util/rights.py b/util/rights.py
index ac5e0fc4..92ab583b 100644
--- a/util/rights.py
+++ b/util/rights.py
@@ -1,10 +1,18 @@
-# rights.py
+##
+# This Module implements rights and lists of rights for the Geni wrapper. Rights
+# are implemented by two classes:
 #
-# support for privileges according to GENI specification
-
-# privilege_table:
+# Right - represents a single right
+#
+# RightList - represents a list of rights
 #
-# a list of priviliges and what operations are allowed per privilege
+# A right may allow several different operations. For example, the "info" right
+# allows "listslices", "listcomponentresources", etc.
+##
+
+##
+# privilege_table is a list of priviliges and what operations are allowed
+# per privilege.
 
 privilege_table = {"authority": ["*"],
                    "refresh": ["remove", "update"],
@@ -16,12 +24,24 @@ privilege_table = {"authority": ["*"],
                    "info": ["listslices", "listcomponentresources", "getsliceresources"],
                    "ma": ["*"]}
 
-# a "Right" is a single privilege.
+##
+# The Right class represents a single privilege.
 
 class Right:
+   ##
+   # Create a new right.
+   #
+   # @param kind is a string naming the right. For example "control"
+
    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".
+
    def can_perform(self, op_name):
       allowed_ops = privilege_table.get(self.kind.lower(), None)
       if not allowed_ops:
@@ -33,6 +53,13 @@ class Right:
 
       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
+
    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)
@@ -46,19 +73,33 @@ class Right:
 
       return True
 
-# a "RightList" is a list of privileges
+##
+# A RightList object represents a list of privileges.
 
 class RightList:
+    ##
+    # Create a new rightlist object, containing no rights.
+    #
+    # @param string if string!=None, load the rightlist from the string
+
     def __init__(self, string=None):
         self.rights = []
         if string:
             self.load_from_string(string)
 
+    ##
+    # Add a right to this list
+    #
+    # @param right is either a Right object or a string describing the right
+
     def add(self, right):
         if isinstance(right, str):
             right = Right(kind = right)
         self.rights.append(right)
 
+    ##
+    # Load the rightlist object from a string
+
     def load_from_string(self, string):
         self.rights = []
 
@@ -70,6 +111,10 @@ class RightList:
         for part in parts:
             self.rights.append(Right(part))
 
+    ##
+    # Save the rightlist object to a string. It is saved in the format of a
+    # comma-separated list.
+
     def save_to_string(self):
         right_names = []
         for right in self.rights:
@@ -77,12 +122,27 @@ class RightList:
 
         return ",".join(right_names)
 
+    ##
+    # Check to see if some right in this list allows an operation. This is
+    # done by evaluating the can_perform function of each operation in the
+    # list.
+    #
+    # @param op_name is an operation to check, for example "listslices"
+
     def can_perform(self, op_name):
         for right in self.rights:
             if right.can_perform(op_name):
                 return True
         return False
 
+    ##
+    # Check to see if all of the rights in this rightlist are a superset
+    # of all the rights in a child rightlist. A rightlist is a superset
+    # if there is no operation in the child rightlist that cannot be
+    # performed in the parent rightlist.
+    #
+    # @param child is a rightlist object describing the child
+
     def is_superset(self, child):
         for child_right in child.rights:
             allowed = False
diff --git a/util/sec/certgen.py b/util/sec/certgen.py
deleted file mode 100755
index d969f27f..00000000
--- a/util/sec/certgen.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#
-# certgen.py
-#
-# Copyright (C) Martin Sjogren and AB Strakt 2001, All rights reserved
-#
-# $Id: certgen.py,v 1.2 2004/07/22 12:01:25 martin Exp $
-#
-"""
-Certificate generation and validation module.
-"""
-
-from OpenSSL import crypto
-import time, calendar, datetime
-
-TYPE_RSA = crypto.TYPE_RSA
-TYPE_DSA = crypto.TYPE_DSA
-
-def createKeyPair(type, bits):
-    """
-    Create a public/private key pair.
-
-    Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA
-               bits - Number of bits to use in the key
-    Returns:   The public/private key pair in a PKey object
-    """
-    pkey = crypto.PKey()
-    pkey.generate_key(type, bits)
-    return pkey
-
-def createCertRequest(pkey, name, digest="md5"):
-    """
-    Create a certificate request.
-
-    Arguments: pkey   - The key to associate with the request
-               digest - Digestion method to use for signing, default is md5
-               **name - The name of the subject of the request, possible
-                        arguments are:
-                          C     - Country name
-                          ST    - State or province name
-                          L     - Locality name
-                          O     - Organization name
-                          OU    - Organizational unit name
-                          CN    - Common name
-                          emailAddress - E-mail address
-    Returns:   The certificate request in an X509Req object
-    """
-    req = crypto.X509Req()
-    subj = req.get_subject()
-    for (key,value) in name.items():
-        setattr(subj, key, value)
-    req.set_pubkey(pkey)
-    req.sign(pkey, digest)
-    return req
-
-def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), extensions=[], digest="md5"):
-    """
-    Generate a certificate given a certificate request.
-
-    Arguments: req        - Certificate reqeust to use
-               issuerCert - The certificate of the issuer
-               issuerKey  - The private key of the issuer
-               serial     - Serial number for the certificate
-               notBefore  - Timestamp (relative to now) when the certificate
-                            starts being valid
-               notAfter   - Timestamp (relative to now) when the certificate
-                            stops being valid
-               digest     - Digest method to use for signing, default is md5
-    Returns:   The signed certificate in an X509 object
-    """
-    cert = crypto.X509()
-    cert.set_serial_number(serial)
-    cert.gmtime_adj_notBefore(notBefore)
-    cert.gmtime_adj_notAfter(notAfter)
-    cert.set_issuer(issuerCert.get_subject())
-    cert.set_subject(req.get_subject())
-    cert.set_pubkey(req.get_pubkey())
-    if extensions:
-        extList = []
-        for name, critical, value in extensions:
-            ext = crypto.X509Extension (name, critical, value)
-            extList.append(ext)
-        cert.add_extensions(extList)
-    cert.sign(issuerKey, digest)
-    return cert
-
-
-#checks if a certificate is valid in terms of validity periods    
-def check_valid(usercert):
-    """
-    Method that ensures the issuer cert has
-    valid, not_before and not_after fields
-    """
-    valid = True
-    before_time = usercert.get_not_before()
-    after_time = usercert.get_not_after()
-    before_tuple = time.strptime(str(before_time), "%b %d %H:%M:%S %Y %Z")
-    after_tuple = time.strptime(str(after_time), "%b %d %H:%M:%S %Y %Z")
-    starts =  datetime.timedelta(seconds=calendar.timegm(before_tuple))
-    expires = datetime.timedelta(seconds=calendar.timegm(after_tuple))
-    now = datetime.timedelta(seconds=time.time())
-    time_delta = expires - now
-    
-    #cert has expired
-    if time_delta.days < 0:
-        valid = False
-    #cert is not yet valid
-    time_delta = now - starts
-    if time_delta.days < 0:   
-        valid = False
-
-    return valid
diff --git a/util/sec/certgen.pyc b/util/sec/certgen.pyc
deleted file mode 100644
index 4bfb1aea183a6538282c3c99f153c7f0dbabe17a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 4119
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

-- 
2.43.0