--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Nodes import Node, Nodes
+from PLC.NodeGroups import NodeGroup, NodeGroups
+from PLC.Sites import Site, Sites
+from PLC.Auth import Auth
+import uuid ##################################soners
+import sys
+sys.path.append('../../../../util')
+from pl_to_geni import *
+from util import *
+from db import *
+
+can_update = lambda (field, value): field in \
+ ['hostname', 'boot_state', 'model', 'version', 'uuid']
+
+class AddNode(Method):
+ """
+ Adds a new node. Any values specified in node_fields are used,
+ otherwise defaults are used.
+
+ PIs and techs may only add nodes to their own sites. Admins may
+ add nodes to any site.
+
+ Returns the new node_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi', 'tech']
+
+ node_fields = dict(filter(can_update, Node.fields.items()))
+
+ accepts = [
+ Auth(),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base']),
+ node_fields
+ ]
+
+ returns = Parameter(int, 'New node_id (> 0) if successful')
+
+ def call(self, auth, site_id_or_login_base, node_fields):
+ node_fields = dict(filter(can_update, node_fields.items()))
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+
+ site = sites[0]
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # If we are not an admin, make sure that the caller is a
+ # member of the site.
+ if 'admin' not in self.caller['roles']:
+ if site['site_id'] not in self.caller['site_ids']:
+ assert self.caller['person_id'] not in site['person_ids']
+ raise PLCPermissionDenied, "Not allowed to add nodes to specified site"
+ else:
+ assert self.caller['person_id'] in site['person_ids']
+
+ node = Node(self.api, node_fields)
+ node['site_id'] = site['site_id']
+ node['uuid'] = str(uuid.uuid4().int)###############################soners
+ node.sync()
+
+ self.event_objects = {'Site': [site['site_id']],
+ 'Node': [node['node_id']]}
+ self.message = "Node %s created" % node['node_id']
+
+ #insert the record into GENI tables ###############################soner
+ (global_sr_tree, global_cr_tree) = get_tree_globals()
+ (site_id, site_hrn) = site_to_auth(site['site_id'])
+ dbinfo = determine_dbinfo(site_hrn, global_cr_tree)
+ if dbinfo == None:
+ raise PLCInvalidArgument, "No GENI authority corresponding to the site "+site['name']
+ cnx = dbinfo[0]
+ tablename = dbinfo[1]
+
+ new_hrn = plnode_to_node(node['hostname'], 0)
+ existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ")
+ if existing != None:
+ new_hrn = plnode_to_node(node['hostname'], 1)
+ existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ")
+ if existing != None:
+ new_hrn = plnode_to_node(node['hostname'], 2)
+
+ geni_record = {'hrn':''}
+ geni_record["hrn"] = new_hrn
+ geni_record["type"] = 'node'
+ geni_record['pointer'] = node['node_id']
+
+ querystr = generate_querystr('INSERT', tablename, geni_record)
+ cnx.query(querystr)
+
+ return node['node_id']
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import Auth
+import uuid ##################################soners
+
+can_update = lambda (field, value): field in \
+ ['first_name', 'last_name', 'title',
+ 'email', 'password', 'phone', 'url', 'bio']
+
+class AddPerson(Method):
+ """
+ Adds a new account. Any fields specified in person_fields are
+ used, otherwise defaults are used.
+
+ Accounts are disabled by default. To enable an account, use
+ UpdatePerson().
+
+ Returns the new person_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ person_fields = dict(filter(can_update, Person.fields.items()))
+
+ accepts = [
+ Auth(),
+ person_fields
+ ]
+
+ returns = Parameter(int, 'New person_id (> 0) if successful')
+
+ def call(self, auth, person_fields):
+ person_fields = dict(filter(can_update, person_fields.items()))
+ person_fields['uuid'] = str(uuid.uuid4().int)###############################soners
+ person_fields['enabled'] = False
+ person = Person(self.api, person_fields)
+ person.sync()
+
+ # Logging variables
+ self.event_objects = {'Person': [person['person_id']]}
+ self.message = 'Person %d added' % person['person_id']
+
+ return person['person_id']
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Sites import Site, Sites
+from PLC.Auth import Auth
+import sys ###########################soner
+sys.path.append('../../../../util')
+from pl_to_geni import *
+from util import *
+from db import *
+
+class AddPersonToSite(Method):
+ """
+ Adds the specified person to the specified site. If the person is
+ already a member of the site, no errors are returned. Does not
+ change the person's primary site.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ accepts = [
+ Auth(),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ Mixed(Site.fields['site_id'],
+ Site.fields['login_base'])
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, person_id_or_email, site_id_or_login_base):
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+ person = persons[0]
+
+ if person['peer_id'] is not None:
+ raise PLCInvalidArgument, "Not a local account"
+
+ # Get site information
+ sites = Sites(self.api, [site_id_or_login_base])
+ if not sites:
+ raise PLCInvalidArgument, "No such site"
+ site = sites[0]
+
+ if site['peer_id'] is not None:
+ raise PLCInvalidArgument, "Not a local site"
+
+ if site['site_id'] not in person['site_ids']:
+ site.add_person(person)
+
+ # Logging variables
+ self.event_objects = {'Site': [site['site_id']],
+ 'Person': [person['person_id']]}
+ self.message = 'Person %d added to site %d' % \
+ (person['person_id'], site['site_id'])
+
+ #insert the record into GENI tables ###################soner
+ (global_sr_tree, global_cr_tree) = get_tree_globals()
+ (site_id, site_hrn) = site_to_auth(site_id_or_login_base)
+ dbinfo = determine_dbinfo(site_hrn, global_sr_tree)
+ if dbinfo == None:
+ raise PLCInvalidArgument, "No GENI authority corresponding to the site "+site['name']
+ cnx = dbinfo[0]
+ tablename = dbinfo[1]
+
+ new_hrn = person_to_user(person['email'])
+ existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ")
+ if existing != None:
+ new_hrn = person_to_user(person['email'], 1)
+ existing = cnx.query("SELECT * FROM "+tablename+" WHERE hrn = '"+new_hrn+"'; ")
+ if existing != None:
+ new_hrn = person_to_user(person['email'], 2)
+
+ geni_record = {'hrn':''}
+ geni_record["hrn"] = new_hrn
+ geni_record["type"] = 'user'
+ geni_record['pointer'] = person['person_id']
+
+ querystr = generate_querystr('INSERT', tablename, geni_record)
+ cnx.query(querystr)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Persons import Person, Persons
+from PLC.Auth import Auth
+from PLC.Roles import Role, Roles
+import sys ##################################soners
+sys.path.append('../../../../util')
+from pl_to_geni import *
+from util import *
+from db import *
+
+class AddRoleToPerson(Method):
+ """
+ Grants the specified role to the person.
+
+ PIs can only grant the tech and user roles to users and techs at
+ their sites. Admins can grant any role to any user.
+
+ Returns 1 if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ accepts = [
+ Auth(),
+ Mixed(Role.fields['role_id'],
+ Role.fields['name']),
+ Mixed(Person.fields['person_id'],
+ Person.fields['email']),
+ ]
+
+ returns = Parameter(int, '1 if successful')
+
+ def call(self, auth, role_id_or_name, person_id_or_email):
+ # Get role
+ roles = Roles(self.api, [role_id_or_name])
+ if not roles:
+ raise PLCInvalidArgument, "Invalid role '%s'" % unicode(role_id_or_name)
+ role = roles[0]
+
+ # Get account information
+ persons = Persons(self.api, [person_id_or_email])
+ if not persons:
+ raise PLCInvalidArgument, "No such account"
+ person = persons[0]
+
+ if person['peer_id'] is not None:
+ raise PLCInvalidArgument, "Not a local account"
+
+ # Authenticated function
+ assert self.caller is not None
+
+ # Check if we can update this account
+ if not self.caller.can_update(person):
+ raise PLCPermissionDenied, "Not allowed to update specified account"
+
+ # Can only grant lesser (higher) roles to others
+ if 'admin' not in self.caller['roles'] and \
+ role['role_id'] <= min(self.caller['role_ids']):
+ raise PLCInvalidArgument, "Not allowed to grant that role"
+
+ if role['role_id'] not in person['role_ids']:
+ person.add_role(role)
+
+ self.event_objects = {'Person': [person['person_id']],
+ 'Role': [role['role_id']]}
+ self.message = "Role %d granted to person %d" % \
+ (role['role_id'], person['person_id'])
+
+ #erase the GENI rights so that PL will not be imcompatible with GENI ############################soners
+ (global_sr_tree, global_cr_tree) = get_tree_globals()
+ cnx = get_plDB_conn()
+ site_ids = cnx.query("SELECT site_id FROM person_slice WHERE person_id = "+person['person_id'])
+ for sid in site_ids:
+ (site_id, site_hrn) = site_to_auth(sid)
+ dbinfo = determine_dbinfo(site_hrn, global_sr_tree)
+ if dbinfo == None:
+ raise PLCInvalidArgument, "No GENI authority corresponding to the site"
+ cnx = dbinfo[0]
+ tablename = dbinfo[1]
+
+ querystr = "UPDATE "+tablename+" SET rights = '' WHERE pointer = "+person['person_id']
+ cnx.query(querystr)
+
+ return 1
--- /dev/null
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Sites import Site, Sites
+from PLC.Auth import Auth
+import uuid ##################################soners
+
+can_update = lambda (field, value): field in \
+ ['name', 'abbreviated_name', 'login_base',
+ 'is_public', 'latitude', 'longitude', 'url',
+ 'max_slices', 'max_slivers', 'enabled', 'uuid']
+
+class AddSite(Method):
+ """
+ Adds a new site, and creates a node group for that site. Any
+ fields specified in site_fields are used, otherwise defaults are
+ used.
+
+ Returns the new site_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin']
+
+ site_fields = dict(filter(can_update, Site.fields.items()))
+
+ accepts = [
+ Auth(),
+ site_fields
+ ]
+
+ returns = Parameter(int, 'New site_id (> 0) if successful')
+
+ def call(self, auth, site_fields):
+ site_fields = dict(filter(can_update, site_fields.items()))
+ site = Site(self.api, site_fields)
+ site['uuid'] = str(uuid.uuid4().int)###############################soners
+ site.sync()
+
+ # Logging variables
+ self.event_objects = {'Site': [site['site_id']]}
+ self.message = 'Site %d created' % site['site_id']
+
+ return site['site_id']
--- /dev/null
+import re
+
+from PLC.Faults import *
+from PLC.Method import Method
+from PLC.Parameter import Parameter, Mixed
+from PLC.Slices import Slice, Slices
+from PLC.Auth import Auth
+from PLC.Sites import Site, Sites
+import uuid ##################################soners
+import sys
+sys.path.append('../../../../util')
+from pl_to_geni import *
+from util import *
+from db import *
+
+can_update = lambda (field, value): field in \
+ ['name', 'instantiation', 'url', 'description', 'max_nodes', 'uuid']
+
+class AddSlice(Method):
+ """
+ Adds a new slice. Any fields specified in slice_fields are used,
+ otherwise defaults are used.
+
+ Valid slice names are lowercase and begin with the login_base
+ (slice prefix) of a valid site, followed by a single
+ underscore. Thereafter, only letters, numbers, or additional
+ underscores may be used.
+
+ PIs may only add slices associated with their own sites (i.e.,
+ slice prefixes must always be the login_base of one of their
+ sites).
+
+ Returns the new slice_id (> 0) if successful, faults otherwise.
+ """
+
+ roles = ['admin', 'pi']
+
+ slice_fields = dict(filter(can_update, Slice.fields.items()))
+
+ accepts = [
+ Auth(),
+ slice_fields
+ ]
+
+ returns = Parameter(int, 'New slice_id (> 0) if successful')
+
+ def call(self, auth, slice_fields):
+ slice_fields = dict(filter(can_update, slice_fields.items()))
+
+ # 1. Lowercase.
+ # 2. Begins with login_base (letters or numbers).
+ # 3. Then single underscore after login_base.
+ # 4. Then letters, numbers, or underscores.
+ name = slice_fields['name']
+ good_name = r'^[a-z0-9]+_[a-zA-Z0-9_]+$'
+ if not name or \
+ not re.match(good_name, name):
+ raise PLCInvalidArgument, "Invalid slice name"
+
+ # Get associated site details
+ login_base = name.split("_")[0]
+ sites = Sites(self.api, [login_base])
+ if not sites:
+ raise PLCInvalidArgument, "Invalid slice prefix %s in %s"%(login_base,name)
+ site = sites[0]
+
+ if 'admin' not in self.caller['roles']:
+ if site['site_id'] not in self.caller['site_ids']:
+ raise PLCPermissionDenied, "Slice prefix %s must be the same as the login_base of one of your sites"%login_base
+
+ if len(site['slice_ids']) >= site['max_slices']:
+ raise PLCInvalidArgument, "Site %s has reached (%d) its maximum allowable slice count (%d)"%(site['name'],
+ len(site['slice_ids']),
+ site['max_slices'])
+
+ if not site['enabled']:
+ raise PLCInvalidArgument, "Site %s is disabled can cannot create slices" % (site['name'])
+
+ slice = Slice(self.api, slice_fields)
+ slice['creator_person_id'] = self.caller['person_id']
+ slice['site_id'] = site['site_id']
+ slice['uuid'] = str(uuid.uuid4().int)###############################soner
+
+ slice.sync()
+
+ self.event_objects = {'Slice': [slice['slice_id']]}
+
+ #insert the record into GENI tables ###############################soner
+ (global_sr_tree, global_cr_tree) = get_tree_globals()
+ (site_id, site_hrn) = site_to_auth(site['site_id'])
+ dbinfo = determine_dbinfo(site_hrn, global_sr_tree)
+ if dbinfo == None:
+ raise PLCInvalidArgument, "No GENI authority corresponding to the site "+site['name']
+ cnx = dbinfo[0]
+ tablename = dbinfo[1]
+
+ new_hrn = plslice_to_slice(slice['name'])
+ geni_record = {'hrn':''}
+ geni_record["hrn"] = new_hrn
+ geni_record["type"] = 'slice'
+ geni_record['pointer'] = slice['slice_id']
+
+ querystr = generate_querystr('INSERT', tablename, geni_record)
+ cnx.query(querystr)
+
+ return slice['slice_id']
--- /dev/null
+"""
+M2Crypto.SSL.Checker
+
+Copyright (c) 2004-2005 Open Source Applications Foundation.
+All rights reserved.
+"""
+
+from M2Crypto import util, EVP
+import re
+
+class SSLVerificationError(Exception):
+ pass
+
+class NoCertificate(SSLVerificationError):
+ pass
+
+class WrongCertificate(SSLVerificationError):
+ pass
+
+class WrongHost(SSLVerificationError):
+ def __init__(self, expectedHost, actualHost, fieldName='commonName'):
+ """
+ This exception will be raised if the certificate returned by the
+ peer was issued for a different host than we tried to connect to.
+ This could be due to a server misconfiguration or an active attack.
+
+ @param expectedHost: The name of the host we expected to find in the
+ certificate.
+ @param actualHost: The name of the host we actually found in the
+ certificate.
+ @param fieldName: The field name where we noticed the error. This
+ should be either 'commonName' or 'subjectAltName'.
+ """
+ if fieldName not in ('commonName', 'subjectAltName'):
+ raise ValueError('Unknown fieldName, should be either commonName or subjectAltName')
+
+ SSLVerificationError.__init__(self)
+ self.expectedHost = expectedHost
+ self.actualHost = actualHost
+ self.fieldName = fieldName
+
+ def __str__(self):
+ s = 'Peer certificate %s does not match host, expected %s, got %s' \
+ % (self.fieldName, self.expectedHost, self.actualHost)
+ if isinstance(s, unicode):
+ s = s.encode('utf8')
+ return s
+
+
+class Checker:
+ def __init__(self, host=None, peerCertHash=None, peerCertDigest='sha1'):
+ self.host = host
+ self.fingerprint = peerCertHash
+ self.digest = peerCertDigest
+ self.numericIpMatch = re.compile('^[0-9]+(\.[0-9]+)*$')
+
+ def __call__(self, peerCert, host=None):
+ if peerCert is None:
+ raise NoCertificate('peer did not return certificate')
+
+ if host is not None:
+ self.host = host
+
+ if self.fingerprint:
+ if self.digest not in ('sha1', 'md5'):
+ raise ValueError('unsupported digest "%s"' %(self.digest))
+
+ if (self.digest == 'sha1' and len(self.fingerprint) != 40) or \
+ (self.digest == 'md5' and len(self.fingerprint) != 32):
+ raise WrongCertificate('peer certificate fingerprint length does not match')
+
+ der = peerCert.as_der()
+ md = EVP.MessageDigest(self.digest)
+ md.update(der)
+ digest = md.final()
+ if util.octx_to_num(digest) != int(self.fingerprint, 16):
+ raise WrongCertificate('peer certificate fingerprint does not match')
+
+ if self.host:
+ hostValidationPassed = False
+
+ # XXX subjectAltName might contain multiple fields
+ # subjectAltName=DNS:somehost
+ try:
+ subjectAltName = peerCert.get_ext('subjectAltName').get_value()
+ if not self._match(self.host, subjectAltName, True):
+ raise WrongHost(expectedHost=self.host,
+ actualHost=subjectAltName,
+ fieldName='subjectAltName')
+ hostValidationPassed = True
+ except LookupError:
+ pass
+
+ # commonName=somehost
+
+
+##-----by Soner, comment outed
+
+## if not hostValidationPassed:
+## try:
+## commonName = peerCert.get_subject().CN
+## if not self._match(self.host, commonName):
+## raise WrongHost(expectedHost=self.host,
+## actualHost=commonName,
+## fieldName='commonName')
+## except AttributeError:
+## raise WrongCertificate('no commonName in peer certificate')
+
+##-----/by Soner
+
+ return True
+
+ def _match(self, host, certHost, subjectAltName=False):
+ """
+ >>> check = Checker()
+ >>> check._match(host='my.example.com', certHost='DNS:my.example.com', subjectAltName=True)
+ True
+ >>> check._match(host='my.example.com', certHost='DNS:*.example.com', subjectAltName=True)
+ True
+ >>> check._match(host='my.example.com', certHost='DNS:m*.example.com', subjectAltName=True)
+ True
+ >>> check._match(host='my.example.com', certHost='DNS:m*ample.com', subjectAltName=True)
+ False
+ >>> check._match(host='my.example.com', certHost='my.example.com')
+ True
+ >>> check._match(host='my.example.com', certHost='*.example.com')
+ True
+ >>> check._match(host='my.example.com', certHost='m*.example.com')
+ True
+ >>> check._match(host='my.example.com', certHost='m*.EXAMPLE.com')
+ True
+ >>> check._match(host='my.example.com', certHost='m*ample.com')
+ False
+ >>> check._match(host='my.example.com', certHost='*.*.com')
+ False
+ >>> check._match(host='1.2.3.4', certHost='1.2.3.4')
+ True
+ >>> check._match(host='1.2.3.4', certHost='*.2.3.4')
+ False
+ >>> check._match(host='1234', certHost='1234')
+ True
+ """
+ # XXX See RFC 2818 and 3280 for matching rules, this is not
+ # XXX yet complete.
+
+ host = host.lower()
+ certHost = certHost.lower()
+
+ if subjectAltName:
+ if certHost[:4] != 'dns:':
+ return False
+ certHost = certHost[4:]
+
+ if host == certHost:
+ return True
+
+ if certHost.count('*') > 1:
+ # Not sure about this, but being conservative
+ return False
+
+ if self.numericIpMatch.match(host) or \
+ self.numericIpMatch.match(certHost.replace('*', '')):
+ # Not sure if * allowed in numeric IP, but think not.
+ return False
+
+ if certHost.find('\\') > -1:
+ # Not sure about this, maybe some encoding might have these.
+ # But being conservative for now, because regex below relies
+ # on this.
+ return False
+
+ # Massage certHost so that it can be used in regex
+ certHost = certHost.replace('.', '\.')
+ certHost = certHost.replace('*', '[^\.]*')
+ if re.compile('^%s$' %(certHost)).match(host):
+ return True
+
+ return False
+
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
--- /dev/null
+The PLCAPI changes are in the directory "PLCAPI/trunk/PLC/Methods".
+The SSL change is in the M2Crypto directory, at "/var/lib/python-support/python2.5/M2Crypto/SSL".
+
+Soner Sevinc
+04/30/08