-<?xml version="1.0" encoding="UTF-8"?>\r
-<!--\r
- \r
- Copyright (c) 2014 Raytheon BBN Technologies\r
- \r
- Permission is hereby granted, free of charge, to any person obtaining\r
- a copy of this software and/or hardware specification (the "Work") to\r
- deal in the Work without restriction, including without limitation the\r
- rights to use, copy, modify, merge, publish, distribute, sublicense,\r
- and/or sell copies of the Work, and to permit persons to whom the Work\r
- is furnished to do so, subject to the following conditions:\r
-\r
- The above copyright notice and this permission notice shall be\r
- included in all copies or substantial portions of the Work.\r
- \r
- THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\r
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
- OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS\r
- IN THE WORK.\r
-\r
- Portions have this copyright:\r
-\r
- GENIPUBLIC-COPYRIGHT\r
- Copyright (c) 2008-2009 University of Utah and the Flux Group.\r
- All rights reserved.\r
- \r
--->\r
-<!--\r
- GENI credential and privilege specification. The key points:\r
- \r
- * A credential is a set of privileges or a Ticket, each with a flag\r
- to indicate delegation is permitted. Or an ABAC RT0 statement.\r
- * A credential is signed and the signature included in the body of the\r
- document.\r
- * To support delegation, a credential will include its parent, and that\r
- blob will be signed. So, there will be multiple signatures in the\r
- document, each with a reference to the credential it signs.\r
- \r
- Default namespace = "http://www.geni.net/resources/credential/2"\r
--->\r
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:sig="http://www.w3.org/2000/09/xmldsig#">\r
- <xs:include schemaLocation="protogeni-rspec-common.xsd"/>\r
- <xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="sig.xsd"/>\r
- <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>\r
- <xs:group name="anyelementbody">\r
- <xs:sequence>\r
- <xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>\r
- </xs:sequence>\r
- </xs:group>\r
- <xs:attributeGroup name="anyelementbody">\r
- <xs:anyAttribute processContents="skip"/>\r
- </xs:attributeGroup>\r
- <!-- This is where we get the definition of RSpec from -->\r
- <xs:element name="privilege">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element ref="name"/>\r
- <xs:element name="can_delegate" type="xs:boolean"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="name">\r
- <xs:simpleType>\r
- <xs:restriction base="xs:string">\r
- <xs:minLength value="1"/>\r
- </xs:restriction>\r
- </xs:simpleType>\r
- </xs:element>\r
- <xs:element name="privileges"> <!-- For type 'privilege' only -->\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="privilege"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="capability">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element ref="name"/>\r
- <xs:element name="can_delegate">\r
- <xs:simpleType>\r
- <xs:restriction base="xs:token">\r
- <xs:enumeration value="0"/>\r
- <xs:enumeration value="1"/>\r
- </xs:restriction>\r
- </xs:simpleType>\r
- </xs:element>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="capabilities"> <!-- For type 'capability' only -->\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="capability"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="ticket"> <!-- For type 'ticket' only -->\r
- <xs:complexType mixed="true">\r
- <xs:sequence>\r
- <xs:element name="can_delegate" type="xs:boolean">\r
- <xs:annotation>\r
- <xs:documentation>Can the ticket be delegated?</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element ref="redeem_before"/>\r
- <xs:group ref="anyelementbody">\r
- <xs:annotation>\r
- <xs:documentation>A desciption of the resources that are being promised</xs:documentation>\r
- </xs:annotation>\r
- </xs:group>\r
- </xs:sequence>\r
- <xs:attributeGroup ref="anyelementbody"/>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="redeem_before" type="xs:dateTime">\r
- <xs:annotation>\r
- <xs:documentation>The ticket must be "cashed in" by this date </xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
-\r
- <!-- Elements used for type 'abac'. See http://groups.geni.net/geni/wiki/TIEDABACCredential -->\r
- <xs:element name="ABACprincipal">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element name="keyid" type="xs:string"/> <!-- SHA1 hash of the principal's public key -->\r
- <xs:element name="mnemonic" type="xs:string" minOccurs="0" maxOccurs="1"/> <!-- EG principal's URN -->\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <!-- A single rt0 element is required for creds of type 'abac'. Must have a single 'head'\r
- and at least one 'tail'. -->\r
- <xs:element name="rt0">\r
- <xs:annotation>\r
- <xs:documentation>An ABAC RT0 statement, used only for type 'abac'.</xs:documentation>\r
- </xs:annotation>\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element name="version" type="xs:string" /> <!-- 1.1 for this schema -->\r
- <xs:element name="head">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element ref="ABACprincipal"/> <!-- Matching the cred signer -->\r
- <xs:element name="role" type="xs:string"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="tail" minOccurs="1" maxOccurs="unbounded">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element ref="ABACprincipal"/>\r
- <xs:element name="role" type="xs:string" minOccurs="0" maxOccurs="1"/>\r
- <xs:element name="linking_role" type="xs:string" minOccurs="0" \r
- maxOccurs="1"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="abac">\r
- <xs:annotation>\r
- <xs:documentation>An ABAC assertion containing a single RT0 statement, used only for type 'abac'.</xs:documentation>\r
- </xs:annotation>\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element minOccurs="1" maxOccurs="1" ref="rt0"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
-\r
- <xs:element name="signatures">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element maxOccurs="unbounded" ref="sig:Signature"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:complexType name="credentials">\r
- <xs:annotation>\r
- <xs:documentation>A credential granting privileges or a ticket or making an ABAC assertion.</xs:documentation>\r
- </xs:annotation>\r
- <xs:sequence>\r
- <xs:element ref="credential"/>\r
- </xs:sequence>\r
- </xs:complexType>\r
- <xs:element name="credential">\r
- <xs:complexType>\r
- <xs:sequence>\r
- <xs:element ref="type"/>\r
- <xs:element ref="serial"/>\r
- <xs:element ref="owner_gid"/>\r
- <xs:element minOccurs="0" ref="owner_urn"/>\r
- <xs:element ref="target_gid"/>\r
- <xs:element minOccurs="0" ref="target_urn"/>\r
- <xs:element ref="uuid"/>\r
- <xs:element ref="expires"/>\r
- <xs:choice>\r
- <xs:annotation>\r
- <xs:documentation>Privileges or a ticket or an ABAC assertion</xs:documentation>\r
- </xs:annotation>\r
- <xs:element ref="privileges"/>\r
- <xs:element ref="ticket"/>\r
- <xs:element ref="capabilities"/>\r
- <xs:element ref="abac"/>\r
- </xs:choice>\r
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="extensions"/>\r
- <xs:element minOccurs="0" ref="parent"/>\r
- </xs:sequence>\r
- <xs:attribute ref="xml:id" use="required"/>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="type">\r
- <xs:annotation>\r
- <xs:documentation>The type of this credential. Currently a Privilege set or a Ticket or ABAC.</xs:documentation>\r
- </xs:annotation>\r
- <xs:simpleType>\r
- <xs:restriction base="xs:token">\r
- <xs:enumeration value="privilege"/>\r
- <xs:enumeration value="ticket"/>\r
- <xs:enumeration value="capability"/>\r
- <xs:enumeration value="abac"/>\r
- </xs:restriction>\r
- </xs:simpleType>\r
- </xs:element>\r
- <xs:element name="serial" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>A serial number.</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="owner_gid" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>GID of the owner of this credential. </xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="owner_urn" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>URN of the owner. Not everyone can parse DER</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="target_gid" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>GID of the target of this credential. </xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="target_urn" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>URN of the target.</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="uuid" type="xs:string">\r
- <xs:annotation>\r
- <xs:documentation>UUID of this credential</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="expires" type="xs:dateTime">\r
- <xs:annotation>\r
- <xs:documentation>Expires on in ISO8601 format but preferably RFC3339</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="extensions">\r
- <xs:annotation>\r
- <xs:documentation>Optional Extensions</xs:documentation>\r
- </xs:annotation>\r
- <xs:complexType mixed="true">\r
- <xs:group ref="anyelementbody"/>\r
- <xs:attributeGroup ref="anyelementbody"/>\r
- </xs:complexType>\r
- </xs:element>\r
- <xs:element name="parent" type="credentials">\r
- <xs:annotation>\r
- <xs:documentation>Parent that delegated to us</xs:documentation>\r
- </xs:annotation>\r
- </xs:element>\r
- <xs:element name="signed-credential">\r
- <xs:complexType>\r
- <xs:complexContent>\r
- <xs:extension base="credentials">\r
- <xs:sequence>\r
- <xs:element minOccurs="0" ref="signatures"/>\r
- </xs:sequence>\r
- </xs:extension>\r
- </xs:complexContent>\r
- </xs:complexType>\r
- </xs:element>\r
-</xs:schema>\r
+#
+# SfaAPI authentication
+#
+import sys
+
+from sfa.util.faults import InsufficientRights, MissingCallerGID, \
+ MissingTrustedRoots, PermissionError, BadRequestHash, \
+ ConnectionKeyGIDMismatch, SfaPermissionDenied, CredentialNotVerifiable, \
+ Forbidden, BadArgs
+from sfa.util.sfalogging import logger
+from sfa.util.py23 import StringType
+from sfa.util.config import Config
+from sfa.util.xrn import Xrn, get_authority
+
+from sfa.trust.gid import GID
+from sfa.trust.rights import Rights
+from sfa.trust.certificate import Keypair, Certificate
+from sfa.trust.credential import Credential
+from sfa.trust.trustedroots import TrustedRoots
+from sfa.trust.hierarchy import Hierarchy
+from sfa.trust.sfaticket import SfaTicket
+from sfa.trust.speaksfor_util import determine_speaks_for
+
+
+class Auth:
+ """
+ Credential based authentication
+ """
+
+ def __init__(self, peer_cert=None, config=None):
+ self.peer_cert = peer_cert
+ self.hierarchy = Hierarchy()
+ if not config:
+ self.config = Config()
+ self.load_trusted_certs()
+
+ def load_trusted_certs(self):
+ self.trusted_cert_list = \
+ TrustedRoots(self.config.get_trustedroots_dir()).get_list()
+ self.trusted_cert_file_list = \
+ TrustedRoots(self.config.get_trustedroots_dir()).get_file_list()
+
+ # this convenience methods extracts speaking_for_xrn
+ # from the passed options using 'geni_speaking_for'
+ def checkCredentialsSpeaksFor(self, *args, **kwds):
+ if 'options' not in kwds:
+ logger.error(
+ "checkCredentialsSpeaksFor was not passed options=options")
+ return
+ # remove the options arg
+ options = kwds['options']
+ del kwds['options']
+ # compute the speaking_for_xrn arg and pass it to checkCredentials
+ if options is None:
+ speaking_for_xrn = None
+ else:
+ speaking_for_xrn = options.get('geni_speaking_for', None)
+ kwds['speaking_for_xrn'] = speaking_for_xrn
+ return self.checkCredentials(*args, **kwds)
+
+ # do not use mutable as default argument
+ # http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments
+ def checkCredentials(self, creds, operation, xrns=None,
+ check_sliver_callback=None,
+ speaking_for_xrn=None):
+ if xrns is None:
+ xrns = []
+ error = (None, None)
+
+ def log_invalid_cred(cred, exception):
+ if not isinstance(cred, StringType):
+ logger.info(
+ "{}: cannot validate credential {}"
+ .format(exception, cred))
+ error = ('TypeMismatch',
+ "checkCredentials: expected a string, got {} -- {}"
+ .format(type(cred), cred))
+ else:
+ cred_obj = Credential(string=cred)
+ logger.info("{}: failed to validate credential dump={}"
+ .format(exception,
+ cred_obj.dump_string(dump_parents=True)))
+ error = sys.exc_info()[:2]
+ return error
+
+ # if xrns are specified they cannot be None or empty string
+ if xrns:
+ for xrn in xrns:
+ if not xrn:
+ raise BadArgs("Invalid urn or hrn")
+
+ if not isinstance(xrns, list):
+ xrns = [xrns]
+
+ # slice_xrns = Xrn.filter_type(xrns, 'slice')
+ sliver_xrns = Xrn.filter_type(xrns, 'sliver')
+
+ # we are not able to validate slivers in the traditional way so
+ # we make sure not to include sliver urns/hrns in the core validation
+ # loop
+ hrns = [Xrn(xrn).hrn for xrn in xrns if xrn not in sliver_xrns]
+ valid = []
+ if not isinstance(creds, list):
+ creds = [creds]
+ logger.debug("Auth.checkCredentials with %d creds on hrns=%s" %
+ (len(creds), hrns))
+ # won't work if either creds or hrns is empty - let's make it more
+ # explicit
+ if not creds:
+ raise Forbidden("no credential provided")
+ if not hrns:
+ hrns = [None]
+
+ speaks_for_gid = determine_speaks_for(logger, creds, self.peer_cert,
+ speaking_for_xrn, self.trusted_cert_list)
+
+ if self.peer_cert and \
+ not self.peer_cert.is_pubkey(speaks_for_gid.get_pubkey()):
+ valid = creds
+ else:
+ for cred in creds:
+ for hrn in hrns:
+ try:
+ self.check(cred, operation, hrn)
+ valid.append(cred)
+ except Exception as exc:
+ error = log_invalid_cred(cred, exc)
+
+ # make sure all sliver xrns are validated against the valid credentials
+ if sliver_xrns:
+ if not check_sliver_callback:
+ msg = "sliver verification callback method not found."
+ msg += " Unable to validate sliver xrns: %s" % sliver_xrns
+ raise Forbidden(msg)
+ check_sliver_callback(valid, sliver_xrns)
+
+ if not len(valid):
+ raise Forbidden("Invalid credential %s -- %s" %
+ (error[0], error[1]))
+
+ return valid
+
+ def check(self, credential, operation, hrn=None):
+ """
+ Check the credential against the peer cert (callerGID) included
+ in the credential matches the caller that is connected to the
+ HTTPS connection, check if the credential was signed by a
+ trusted cert and check if the credential is allowed to perform
+ the specified operation.
+ """
+ cred = Credential(cred=credential)
+ self.client_cred = cred
+ logger.debug("Auth.check: handling hrn=%s and credential=%s" %
+ (hrn, cred.pretty_cred()))
+
+ if cred.type not in ['geni_sfa']:
+ raise CredentialNotVerifiable(
+ cred.type, "%s not supported" % cred.type)
+ self.client_gid = self.client_cred.get_gid_caller()
+ self.object_gid = self.client_cred.get_gid_object()
+
+ # make sure the client_gid is not blank
+ if not self.client_gid:
+ raise MissingCallerGID(self.client_cred.pretty_subject())
+
+ # validate the client cert if it exists
+ if self.peer_cert:
+ self.verifyPeerCert(self.peer_cert, self.client_gid)
+
+ # make sure the client is allowed to perform the operation
+ if operation:
+ if not self.client_cred.can_perform(operation):
+ raise InsufficientRights(operation)
+
+ if self.trusted_cert_list:
+ self.client_cred.verify(self.trusted_cert_file_list,
+ self.config.SFA_CREDENTIAL_SCHEMA)
+ 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]
+ if hrn and self.client_gid.get_hrn() not in trusted_peers:
+ target_hrn = self.object_gid.get_hrn()
+ if not hrn == target_hrn:
+ raise PermissionError("Target hrn: %s doesn't match specified hrn: %s " %
+ (target_hrn, hrn))
+ return True
+
+ def check_ticket(self, ticket):
+ """
+ Check if the ticket was signed by a trusted cert
+ """
+ if self.trusted_cert_list:
+ client_ticket = SfaTicket(string=ticket)
+ client_ticket.verify_chain(self.trusted_cert_list)
+ else:
+ raise MissingTrustedRoots(self.config.get_trustedroots_dir())
+
+ return True
+
+ def verifyPeerCert(self, cert, gid):
+ # make sure the client_gid matches client's certificate
+ if not cert.is_pubkey(gid.get_pubkey()):
+ raise ConnectionKeyGIDMismatch(
+ gid.get_subject() + ":" + cert.get_subject())
+
+ def verifyGidRequestHash(self, gid, hash, arglist):
+ key = gid.get_pubkey()
+ if not key.verify_string(str(arglist), hash):
+ raise BadRequestHash(hash)
+
+ def verifyCredRequestHash(self, cred, hash, arglist):
+ gid = cred.get_gid_caller()
+ self.verifyGidRequestHash(gid, hash, arglist)
+
+ def validateGid(self, gid):
+ if self.trusted_cert_list:
+ gid.verify_chain(self.trusted_cert_list)
+
+ def validateCred(self, cred):
+ if self.trusted_cert_list:
+ cred.verify(self.trusted_cert_file_list)
+
+ def authenticateGid(self, gidStr, argList, requestHash=None):
+ gid = GID(string=gidStr)
+ self.validateGid(gid)
+ # request_hash is optional
+ if requestHash:
+ self.verifyGidRequestHash(gid, requestHash, argList)
+ return gid
+
+ def authenticateCred(self, credStr, argList, requestHash=None):
+ cred = Credential(string=credStr)
+ self.validateCred(cred)
+ # request hash is optional
+ if requestHash:
+ self.verifyCredRequestHash(cred, requestHash, argList)
+ return cred
+
+ def authenticateCert(self, certStr, requestHash):
+ cert = Certificate(string=certStr)
+ # xxx should be validateCred ??
+ self.validateCred(cert)
+
+ def gidNoop(self, gidStr, value, requestHash):
+ self.authenticateGid(gidStr, [gidStr, value], requestHash)
+ return value
+
+ def credNoop(self, credStr, value, requestHash):
+ self.authenticateCred(credStr, [credStr, value], requestHash)
+ return value
+
+ def verify_cred_is_me(self, credential):
+ is_me = False
+ cred = Credential(string=credential)
+ caller_gid = cred.get_gid_caller()
+ caller_hrn = caller_gid.get_hrn()
+ if caller_hrn != self.config.SFA_INTERFACE_HRN:
+ raise SfaPermissionDenied(self.config.SFA_INTEFACE_HRN)
+
+ return
+
+ def get_auth_info(self, auth_hrn):
+ """
+ Given an authority name, return the information for that authority.
+ This is basically a stub that calls the hierarchy module.
+
+ @param auth_hrn human readable name of authority
+ """
+
+ return self.hierarchy.get_auth_info(auth_hrn)
+
+ def veriry_auth_belongs_to_me(self, name):
+ """
+ Verify that an authority belongs to our hierarchy.
+ This is basically left up to the implementation of the hierarchy
+ module. If the specified name does not belong, ane exception is
+ thrown indicating the caller should contact someone else.
+
+ @param auth_name human readable name of authority
+ """
+
+ # get auth info will throw an exception if the authority doesnt exist
+ self.get_auth_info(name)
+
+ def verify_object_belongs_to_me(self, name):
+ """
+ Verify that an object belongs to our hierarchy. By extension,
+ this implies that the authority that owns the object belongs
+ to our hierarchy. If it does not an exception is thrown.
+
+ @param name human readable name of object
+ """
+ auth_name = self.get_authority(name)
+ if not auth_name:
+ auth_name = name
+ if name == self.config.SFA_INTERFACE_HRN:
+ return
+ self.verify_auth_belongs_to_me(auth_name)
+
+ def verify_auth_belongs_to_me(self, name):
+ # get auth info will throw an exception if the authority doesnt exist
+ self.get_auth_info(name)
+
+ def verify_object_permission(self, name):
+ """
+ Verify that the object gid that was specified in the credential
+ allows permission to the object 'name'. This is done by a simple
+ prefix test. For example, an object_gid for plc.arizona would
+ match the objects plc.arizona.slice1 and plc.arizona.
+
+ @param name human readable name to test
+ """
+ object_hrn = self.object_gid.get_hrn()
+ if object_hrn == name:
+ return
+ if name.startswith(object_hrn + "."):
+ return
+ # if name.startswith(get_authority(name)):
+ # return
+
+ raise PermissionError(name)
+
+ def determine_user_rights(self, caller_hrn, reg_record):
+ """
+ Given a user credential and a record, determine what set of rights the
+ user should have to that record.
+
+ This is intended to replace determine_user_rights() and
+ verify_cancreate_credential()
+ """
+
+ rl = Rights()
+ type = reg_record.type
+
+ logger.debug("entering determine_user_rights with record %s and caller_hrn %s" %
+ (reg_record, caller_hrn))
+
+ if type == 'slice':
+ # researchers in the slice are in the DB as-is
+ researcher_hrns = [user.hrn for user in reg_record.reg_researchers]
+ # locating PIs attached to that slice
+ slice_pis = reg_record.get_pis()
+ pi_hrns = [user.hrn for user in slice_pis]
+ if (caller_hrn in researcher_hrns + pi_hrns):
+ rl.add('refresh')
+ rl.add('embed')
+ rl.add('bind')
+ rl.add('control')
+ rl.add('info')
+
+ elif type == 'authority':
+ pi_hrns = [user.hrn for user in reg_record.reg_pis]
+ if (caller_hrn == self.config.SFA_INTERFACE_HRN):
+ rl.add('authority')
+ rl.add('sa')
+ rl.add('ma')
+ if (caller_hrn in pi_hrns):
+ rl.add('authority')
+ rl.add('sa')
+ # NOTE: for the PL implementation, this 'operators' list
+ # amounted to users with 'tech' role in that site
+ # it seems like this is not needed any longer, so for now I just drop that
+ # operator_hrns = reg_record.get('operator', [])
+ # if (caller_hrn in operator_hrns):
+ # rl.add('authority')
+ # rl.add('ma')
+
+ elif type == 'user':
+ rl.add('refresh')
+ rl.add('resolve')
+ rl.add('info')
+
+ elif type == 'node':
+ rl.add('operator')
+
+ return rl
+
+ def get_authority(self, hrn):
+ return get_authority(hrn)
+
+ def filter_creds_by_caller(self, creds, caller_hrn_list):
+ """
+ Returns a list of creds who's gid caller matches the
+ specified caller hrn
+ """
+ if not isinstance(creds, list):
+ creds = [creds]
+ creds = []
+ if not isinstance(caller_hrn_list, list):
+ caller_hrn_list = [caller_hrn_list]
+ for cred in creds:
+ try:
+ tmp_cred = Credential(string=cred)
+ if tmp_cred.get_gid_caller().get_hrn() in [caller_hrn_list]:
+ creds.append(cred)
+ except:
+ pass
+ return creds