From ad42c64abe77feaca0922c02af14ebe460e60149 Mon Sep 17 00:00:00 2001 From: Josh Karlin Date: Wed, 7 Apr 2010 21:17:52 +0000 Subject: [PATCH] Delegation is now per-privilege, instead of one bit per credential --- sfa/client/sfi.py | 7 ++-- sfa/managers/registry_manager_pl.py | 2 +- sfa/trust/credential.py | 60 ++++++++++++----------------- sfa/trust/hierarchy.py | 2 +- sfa/trust/rights.py | 49 +++++++++++++++++++---- tests/testCred.py | 5 +-- 6 files changed, 73 insertions(+), 52 deletions(-) diff --git a/sfa/client/sfi.py b/sfa/client/sfi.py index deb565e9..90e1f870 100755 --- a/sfa/client/sfi.py +++ b/sfa/client/sfi.py @@ -477,7 +477,7 @@ class Sfi: dcred.set_gid_caller(delegee_gid) dcred.set_gid_object(object_gid) dcred.set_privileges(user_cred.get_privileges()) - dcred.set_delegate(True) + dcred.get_privileges().delegate_all_privileges(True) # Save the issuer's gid to a file @@ -623,7 +623,7 @@ class Sfi: 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 @@ -645,8 +645,9 @@ class Sfi: dcred = Credential(subject=object_hrn + " delegated to " + delegee_hrn) 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) diff --git a/sfa/managers/registry_manager_pl.py b/sfa/managers/registry_manager_pl.py index d2ed29bf..2108c154 100644 --- a/sfa/managers/registry_manager_pl.py +++ b/sfa/managers/registry_manager_pl.py @@ -58,7 +58,7 @@ def get_credential(api, xrn, type, is_self=False): 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" # Parent not necessary, verify with certs #new_cred.set_parent(api.auth.hierarchy.get_auth_cred(auth_hrn, kind=auth_kind)) diff --git a/sfa/trust/credential.py b/sfa/trust/credential.py index 8609c3b3..d533b95f 100644 --- a/sfa/trust/credential.py +++ b/sfa/trust/credential.py @@ -1,8 +1,7 @@ ## # 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$ @@ -13,7 +12,6 @@ import random import os import datetime -#import xml.dom.minidom from xml.dom.minidom import Document, parseString from sfa.trust.credential_legacy import CredentialLegacy from sfa.trust.certificate import Certificate @@ -24,16 +22,12 @@ from sfa.util.sfalogging import logger # TODO: -# . SFA is using set_parent to do chaining, but that's no longer necessary -# with the new credentials. fix. -# . This probably requires setting up some sort of CA hierarchy. -# . Make sure that the creds pass xml verification (probably need some reordering) # . Need to implement full verification (parent signatures etc). # . remove verify_chain # . make delegation per privilege instead of global # . make privs match between PG and PL # . what about tickets? do they need to be redone to be like credentials? -# . Need to test +# . Need to test delegation, xml verification signature_template = \ ''' @@ -127,7 +121,7 @@ class Signature(object): ## # Credential is a tuple: -# (GIDCaller, GIDObject, Expiration (in UTC time), Privileges, DelegateBit) +# (GIDCaller, GIDObject, Expiration (in UTC time), Privileges) # # These fields are encoded in one of two ways. The legacy style places # it in the subjectAltName of an X509 certificate. The new credentials @@ -139,7 +133,6 @@ class Credential(object): gidObject = None expiration = None privileges = None - delegate = False issuer_privkey = None issuer_gid = None issuer_pubkey = None @@ -187,7 +180,7 @@ class Credential(object): self.set_lifetime(int(lifetime)) self.lifeTime = legacy.get_lifetime() self.set_privileges(legacy.get_privileges()) - self.delegate = legacy.get_delegate() + self.get_privileges().delegate_all_privileges(legacy.get_delegate()) ## # Need the issuer's private key and name @@ -286,22 +279,7 @@ class Credential(object): self.decode() return self.expiration - ## - # 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 # @@ -312,6 +290,7 @@ class Credential(object): self.privileges = RightList(string = privs) else: self.privileges = privs + ## # return the privileges as a RightList object @@ -371,11 +350,11 @@ class Credential(object): cred.appendChild(privileges) if self.privileges: - rights = self.privileges.save_to_string().split(",") - for right in rights: + rights = self.get_privileges() + for right in rights.rights: priv = doc.createElement("privilege") - self.append_sub(doc, priv, "name", right.strip()) - self.append_sub(doc, priv, "can_delegate", str(self.delegate)) + self.append_sub(doc, priv, "name", right.kind) + self.append_sub(doc, priv, "can_delegate", str(right.delegate)) privileges.appendChild(priv) # Add the parent credential if it exists @@ -637,9 +616,23 @@ class Credential(object): if root_issuer != target_authority: raise CredentialNotVerifiable("issuer (%s) != authority of target (%s)" \ % (root_issuer, target_authority)) - + + ## + # -- 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()) + if parent_cred.parent_xml: parent_cred.verify_parent(Credential(string=parent_cred.parent_xml)) @@ -651,9 +644,6 @@ class Credential(object): # # Each credential must be a subset of the rights of the parent. - def verify_chain(self, trusted_certs): - return - ## def verify_chain(self, trusted_certs = None): ## # do the normal certificate verification stuff ## Certificate.verify_chain(self, trusted_certs) diff --git a/sfa/trust/hierarchy.py b/sfa/trust/hierarchy.py index 609a48a9..e73e5bd6 100644 --- a/sfa/trust/hierarchy.py +++ b/sfa/trust/hierarchy.py @@ -302,7 +302,7 @@ class Hierarchy: cred.set_gid_caller(gid) cred.set_gid_object(gid) cred.set_privileges(kind) - cred.set_delegate(True) + cred.get_privileges().delegate_all_privileges(True) #cred.set_pubkey(auth_info.get_gid_object().get_pubkey()) parent_hrn = get_authority(hrn) diff --git a/sfa/trust/rights.py b/sfa/trust/rights.py index 16ef185d..1c08a1ec 100644 --- a/sfa/trust/rights.py +++ b/sfa/trust/rights.py @@ -78,9 +78,10 @@ class Right: # # @param kind is a string naming the right. For example "control" - def __init__(self, kind): + def __init__(self, kind, delegate=False): self.kind = kind - + self.delegate = delegate + ## # Test to see if this right object is allowed to perform an operation. # Returns True if the operation is allowed, False otherwise. @@ -109,6 +110,9 @@ class Right: 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 @@ -140,9 +144,9 @@ class RightList: # # @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(kind = right, delegate=delegate) self.rights.append(right) ## @@ -157,16 +161,23 @@ class RightList: parts = string.split(",") for part in parts: - self.rights.append(Right(part)) + if ':' in part: + spl = part.split(':') + kind = spl[0] + delegate = int(spl[1]) + else: + kind = part + delegate = 0 + self.rights.append(Right(kind, bool(delegate))) ## # Save the rightlist object to a string. It is saved in the format of a # comma-separated list. - def save_to_string(self): + def save_to_string(self): right_names = [] for right in self.rights: - right_names.append(right.kind) + right_names.append('%s:%d' % (right.kind, right.delegate)) return ",".join(right_names) @@ -203,7 +214,29 @@ class RightList: ## - # 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". # diff --git a/tests/testCred.py b/tests/testCred.py index 68c9b743..155543cc 100755 --- a/tests/testCred.py +++ b/tests/testCred.py @@ -23,7 +23,7 @@ class TestCred(unittest.TestCase): gidObject = GID(subject="object", uuid=create_uuid(), hrn="foo.object") lifeTime = 12345 delegate = True - rights = "embed,bind" + rights = "embed:1,bind:1" cred.set_gid_caller(gidCaller) self.assertEqual(cred.get_gid_caller().get_subject(), gidCaller.get_subject()) @@ -34,9 +34,6 @@ class TestCred(unittest.TestCase): cred.set_lifetime(lifeTime) self.assertEqual(cred.get_lifetime(), lifeTime) - cred.set_delegate(delegate) - self.assertEqual(cred.get_delegate(), delegate) - cred.set_privileges(rights) self.assertEqual(cred.get_privileges().save_to_string(), rights) -- 2.47.0