def create_role(new_role, state): role_container = role_state_pb2.RoleAttributesContainer() role = role_container.role_attributes.add() role.role_id = new_role.role_id role.name = new_role.name role.metadata = new_role.metadata entries_to_set = { addresser.make_role_attributes_address( new_role.role_id ): role_container.SerializeToString() } pubkeys_by_address = {} for admin in list(new_role.admins): admin_address = addresser.make_role_admins_address( role_id=new_role.role_id, user_id=admin ) if admin_address in pubkeys_by_address: pubkeys_by_address[admin_address].append(admin) else: pubkeys_by_address[admin_address] = [admin] for owner in list(new_role.owners): owner_address = addresser.make_role_owners_address( role_id=new_role.role_id, user_id=owner ) if owner_address in pubkeys_by_address: pubkeys_by_address[owner_address].append(owner) else: pubkeys_by_address[owner_address] = [owner] state_returns = state_accessor.get_state( state, [ addresser.make_role_admins_address(role_id=new_role.role_id, user_id=a) for a in new_role.admins ] + [ addresser.make_role_owners_address(role_id=new_role.role_id, user_id=o) for o in new_role.owners ], ) for addr, pubkeys in pubkeys_by_address.items(): try: state_entry = state_accessor.get_state_entry(state_returns, addr) container = role_state_pb2.RoleRelationshipContainer() container.ParseFromString(state_entry.data) except KeyError: container = role_state_pb2.RoleRelationshipContainer() message_accessor.add_role_rel_to_container(container, new_role.role_id, pubkeys) entries_to_set[addr] = container.SerializeToString() state_accessor.set_state(state, entries_to_set)
def confirm_remove_role_admins(txn_key, batch_key, proposal_id, role_id, user_id, reason): confirm_add_payload = role_transaction_pb2.ConfirmRemoveRoleAdmin( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason) inputs = [ addresser.make_role_admins_address(role_id=role_id, user_id=txn_key.public_key) ] inputs.append(addresser.make_proposal_address(role_id, user_id)) outputs = [ addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, user_id), ] rbac_payload = rbac_payload_pb2.RBACPayload( content=confirm_add_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.CONFIRM_REMOVE_ROLE_ADMINS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def apply_confirm(header, payload, state): confirm_payload = role_transaction_pb2.ConfirmAddRoleAdmin() confirm_payload.ParseFromString(payload.content) role_admin_address = addresser.make_role_admins_address( role_id=confirm_payload.role_id, user_id=confirm_payload.user_id ) txn_signer_admin_address = addresser.make_role_admins_address( role_id=confirm_payload.role_id, user_id=header.signer_public_key ) state_entries = role_validator.get_state_entries( header=header, confirm=confirm_payload, txn_signer_rel_address=txn_signer_admin_address, state=state, ) state_change.confirm_role_action( state_entries=state_entries, header=header, confirm=confirm_payload, role_rel_address=role_admin_address, state=state, )
def create_role(txn_key, batch_key, role_name, role_id, metadata, admins, owners): """Create a BatchList with a CreateRole transaction in it. Args: txn_key (Key): The transaction signer's key pair. batch_key (Key): The batch signer's key pair. role_name (str): The name of the Role. role_id (str): A uuid that identifies this Role. metadata (str): Client supplied information that is not parsed. admins (list): A list of User ids of the Users who are admins of this Role. owners (list): A list of User ids of the Users who are owners of this Role. Returns: tuple BatchList, batch header_signature tuple """ create_role_payload = role_transaction_pb2.CreateRole(role_id=role_id, name=role_name, metadata=metadata, admins=admins, owners=owners) inputs = [ addresser.make_sysadmin_members_address(txn_key.public_key), addresser.make_role_attributes_address(role_id), ] inputs.extend([addresser.make_user_address(u) for u in admins]) inputs.extend([addresser.make_user_address(u) for u in owners]) inputs.extend([ addresser.make_role_admins_address(role_id=role_id, user_id=a) for a in admins ]) inputs.extend([ addresser.make_role_owners_address(role_id=role_id, user_id=o) for o in owners ]) outputs = [addresser.make_role_attributes_address(role_id)] outputs.extend([ addresser.make_role_admins_address(role_id=role_id, user_id=a) for a in admins ]) outputs.extend([ addresser.make_role_owners_address(role_id=role_id, user_id=o) for o in owners ]) rbac_payload = rbac_payload_pb2.RBACPayload( content=create_role_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.CREATE_ROLE, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def confirm_add_role_owners(txn_key, batch_key, proposal_id, role_id, user_id, reason): confirm_payload = role_transaction_pb2.ConfirmAddRoleOwner( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason) inputs = [ addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, txn_key.public_key), ] outputs = [ addresser.make_proposal_address(role_id, user_id), addresser.make_role_owners_address(role_id, user_id), ] rbac_payload = rbac_payload_pb2.RBACPayload( content=confirm_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.CONFIRM_ADD_ROLE_OWNERS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def check_admin(self, role_id, user_id): container = role_state_pb2.RoleRelationshipContainer() address = addresser.make_role_admins_address(role_id=role_id, user_id=user_id) container.ParseFromString(self.client.get_address(address=address)) items = list(container.relationships) if len(items) == 0: return False elif len(items) > 1: LOGGER.warning( "role %s admins container for user %s at address %s has more than one record", role_id, user_id, address, ) item = items[0] identifiers = list(item.identifiers) if len(identifiers) == 0: LOGGER.warning( "role %s admins container for user %s at address %s has no identifiers", role_id, user_id, address, ) return False if len(identifiers) > 1: LOGGER.warning( "role %s admins container for user %s at address %s has more than one identifier", role_id, user_id, address, ) return bool(user_id in item.identifiers)
def test_generated_role_admin_addr(self): """Tests the role admin address creation function as well as the address_is function. """ role_id = uuid4().hex admin_id = uuid4().hex address = addresser.make_role_admins_address(role_id, admin_id) self.assertEqual(len(address), addresser.ADDRESS_LENGTH, "The address is 70 characters") self.assertTrue(addresser.is_address(address), "The address is 70 character hexidecimal") self.assertTrue(addresser.namespace_ok(address), "The address has correct namespace prefix") self.assertTrue( addresser.is_family_address(address), "The address is 70 character hexidecimal with family prefix", ) self.assertEqual( addresser.address_is(address), AddressSpace.ROLES_ADMINS, "The address created must be a Role Attributes address.", )
def propose_remove_role_admins( txn_key, batch_key, proposal_id, role_id, user_id, reason, metadata ): propose = role_transaction_pb2.ProposeRemoveRoleAdmin( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason, metadata=metadata, ) inputs = [ addresser.make_user_address(user_id=user_id), addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, user_id), addresser.make_role_attributes_address(role_id=role_id), ] outputs = [addresser.make_proposal_address(role_id, user_id)] rbac_payload = rbac_payload_pb2.RBACPayload( content=propose.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.PROPOSE_REMOVE_ROLE_ADMINS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def test_determine_role_admin_addr(self): """Tests that a specific role_id and admin_id generates the expected role admin address, and thus is probably deterministic. """ role_id = "99968acb8f1a48b3a4bc21e2cd252e67" admin_id = "966ab67317234df489adb4bc1f517b88" expected_address = "9f444809326a1713a905b26359fc8d\ a2817c1a5f67de6f464701f0c10042da345d28f7" address = addresser.make_role_admins_address(role_id, admin_id) self.assertEqual(len(address), addresser.ADDRESS_LENGTH, "The address is 70 characters") self.assertTrue(addresser.is_address(address), "The address is 70 character hexidecimal") self.assertTrue(addresser.namespace_ok(address), "The address has correct namespace prefix") self.assertTrue( addresser.is_family_address(address), "The address is 70 character hexidecimal with family prefix", ) self.assertEqual(address, expected_address, "The address is the one we expected it to be") self.assertEqual( addresser.address_is(address), AddressSpace.ROLES_ADMINS, "The address created must be a Role Attributes address.", )
def apply_propose_remove(header, payload, state): role_admins_payload = role_transaction_pb2.ProposeRemoveRoleAdmin() role_admins_payload.ParseFromString(payload.content) role_admins_address = addresser.make_role_admins_address( role_id=role_admins_payload.role_id, user_id=role_admins_payload.user_id) proposal_address = addresser.make_proposal_address( object_id=role_admins_payload.role_id, related_id=role_admins_payload.user_id) state_entries = role_validator.validate_role_rel_proposal( header, role_admins_payload, role_admins_address, state, True) if not proposal_validator.has_no_open_proposal( state_entries=state_entries, object_id=role_admins_payload.role_id, related_id=role_admins_payload.user_id, proposal_address=proposal_address, proposal_type=proposal_state_pb2.Proposal.REMOVE_ROLE_ADMINS, ): raise InvalidTransaction( "There is already an open proposal for REMOVE_ROLE_ADMINS " "with role id {} and user id {}".format( role_admins_payload.role_id, role_admins_payload.user_id)) state_change.propose_role_action( state_entries=state_entries, header=header, payload=role_admins_payload, address=proposal_address, proposal_type=proposal_state_pb2.Proposal.REMOVE_ROLE_ADMINS, state=state, )
def hierarchical_decide(header, payload, state, isApproval): confirm = role_transaction_pb2.ConfirmAddRoleAdmin() confirm.ParseFromString(payload.content) txn_signer_admin_address = addresser.make_role_admins_address( role_id=confirm.role_id, user_id=confirm.on_behalf_id) role_operation.hierarchical_decide(header, confirm, state, txn_signer_admin_address, isApproval)
def confirm_add_role_admins(txn_key, batch_key, proposal_id, role_id, user_id, reason): """Creates a BatchList with a ConfirmAddRoleAdmin transaction in it. Args: txn_key (Key): The txn signer key pair. batch_key (Key): The batch signer key pair. proposal_id (str): The proposal's identifier. role_id (str): The role's identifier. user_id (str): The user's signer public key. reason (str): The client supplied reason to confirm. Returns: tuple BatchList, batch header_signature tuple """ confirm_add_payload = role_transaction_pb2.ConfirmAddRoleAdmin( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason) inputs = [ addresser.make_role_admins_address(role_id=role_id, user_id=txn_key.public_key) ] inputs.append(addresser.make_proposal_address(role_id, user_id)) outputs = [ addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, user_id), ] rbac_payload = rbac_payload_pb2.RBACPayload( content=confirm_add_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.CONFIRM_ADD_ROLE_ADMINS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def create(self, signer_keypair, role, do_batch=True, do_send=True, do_get=False): if not isinstance(signer_keypair, Key): raise TypeError("Expected signer_keypair to be a Key") if not isinstance(role, role_transaction_pb2.CreateRole): raise TypeError( "Expected role to be a role_transaction_pb2.CreateRole, use make first" ) inputs = [ addresser.make_sysadmin_members_address(signer_keypair.public_key), addresser.make_role_attributes_address(role.role_id), ] inputs.extend([addresser.make_user_address(u) for u in role.admins]) inputs.extend([addresser.make_user_address(u) for u in role.owners]) inputs.extend( [ addresser.make_role_admins_address(role_id=role.role_id, user_id=a) for a in role.admins ] ) inputs.extend( [ addresser.make_role_owners_address(role_id=role.role_id, user_id=o) for o in role.owners ] ) transaction = self.batch.make_transaction( message=role, message_type=RBACPayload.CREATE_ROLE, inputs=inputs, outputs=inputs, signer_keypair=signer_keypair, ) if not do_batch: return transaction batch = self.batch.make_batch(transaction=transaction) if not do_send: return batch batch_list = self.batch.batch_to_list(batch) status = self.client.send_batches_get_status(batch_list=batch_list) if not do_get: return status return self.get(role_id=role.role_id)
def apply_reject(header, payload, state): reject_payload = role_transaction_pb2.RejectAddRoleOwner() reject_payload.ParseFromString(payload.content) txn_signer_admins_address = addresser.make_role_admins_address( role_id=reject_payload.role_id, user_id=header.signer_public_key ) state_entries = state_accessor.get_state_entries( header=header, confirm=reject_payload, txn_signer_rel_address=txn_signer_admins_address, state=state, ) state_change.reject_role_action( state_entries, header, reject=reject_payload, state=state )
def reject_add_role_admins(txn_key, batch_key, proposal_id, role_id, user_id, reason): reject_add_payload = role_transaction_pb2.RejectAddRoleAdmin( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason ) inputs = [ addresser.make_role_admins_address(role_id=role_id, user_id=txn_key.public_key) ] inputs.append(addresser.make_proposal_address(role_id, user_id)) outputs = [addresser.make_proposal_address(role_id, user_id)] rbac_payload = rbac_payload_pb2.RBACPayload( content=reject_add_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.REJECT_ADD_ROLE_ADMINS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def reject_remove_role_owners( txn_key, batch_key, proposal_id, role_id, user_id, reason ): reject_payload = role_transaction_pb2.RejectRemoveRoleOwner( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason ) inputs = [ addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, txn_key.public_key), ] outputs = [addresser.make_proposal_address(role_id, user_id)] rbac_payload = rbac_payload_pb2.RBACPayload( content=reject_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.REJECT_REMOVE_ROLE_OWNERS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def propose_add_role_admins( txn_key, batch_key, proposal_id, role_id, user_id, reason, metadata ): """Create a BatchList with a ProposeAddRoleAdmins transaction in it. Args: txn_key (Key): The txn signer key pair. batch_key (Key): The batch signer key pair. role_id (str): The role's id. user_id (str): The user that is being proposed to be an admin. reason (str): The client supplied reason for the proposal. metadata (str): The client supplied metadata. Returns: tuple BatchList, batch header_signature tuple """ propose_add_payload = role_transaction_pb2.ProposeAddRoleAdmin( proposal_id=proposal_id, role_id=role_id, user_id=user_id, reason=reason, metadata=metadata, ) inputs = [ addresser.make_user_address(user_id=user_id), addresser.make_proposal_address(role_id, user_id), addresser.make_role_admins_address(role_id, user_id), addresser.make_role_attributes_address(role_id=role_id), ] outputs = [addresser.make_proposal_address(role_id, user_id)] rbac_payload = rbac_payload_pb2.RBACPayload( content=propose_add_payload.SerializeToString(), message_type=rbac_payload_pb2.RBACPayload.PROPOSE_ADD_ROLE_ADMINS, ) return make_header_and_batch(rbac_payload, inputs, outputs, txn_key, batch_key)
def make_addresses(self, message, signer_public_key=None): """Makes the approporiate inputs & output addresses for the message type""" if isinstance(message, role_transaction_pb2.CreateRole): inputs = [ # addresser.make_sysadmin_members_address(signer_public_key), addresser.make_role_attributes_address(message.role_id) ] inputs.extend([addresser.make_user_address(u) for u in message.admins]) inputs.extend([addresser.make_user_address(u) for u in message.owners]) inputs.extend( [ addresser.make_role_admins_address( role_id=message.role_id, user_id=a ) for a in message.admins ] ) inputs.extend( [ addresser.make_role_owners_address( role_id=message.role_id, user_id=o ) for o in message.owners ] ) outputs = inputs elif isinstance(message, role_transaction_pb2.ProposeAddRoleMember): relationship_address = addresser.make_role_members_address( role_id=message.role_id, user_id=message.user_id ) elif isinstance(message, role_transaction_pb2.ProposeAddRoleOwner): relationship_address = addresser.make_role_owners_address( role_id=message.role_id, user_id=message.user_id ) elif isinstance(message, role_transaction_pb2.ProposeAddRoleAdmin): relationship_address = addresser.make_role_admins_address( role_id=message.role_id, user_id=message.user_id ) else: raise TypeError( "RoleManager.make_addresses doesn't support message type {}".format( type(message) ) ) if ( isinstance(message, role_transaction_pb2.ProposeAddRoleMember) or isinstance(message, role_transaction_pb2.ProposeAddRoleOwner) or isinstance(message, role_transaction_pb2.ProposeAddRoleAdmin) ): proposal_address = addresser.make_proposal_address( object_id=message.role_id, related_id=message.user_id ) role_address = addresser.make_role_attributes_address( role_id=message.role_id ) user_address = addresser.make_user_address(user_id=message.user_id) inputs = [ relationship_address, role_address, user_address, proposal_address, ] outputs = [proposal_address] return inputs, outputs
def test_role_addresses(self): """Tests the Role address creation functions as well as the address_is function. Notes: 1. Create an address of a particular type: - Role Attributes - Role Members - Role Owners - Role Admins - Role Tasks 2. Assert that address_is returns the correct address type. """ role_address = addresser.make_role_attributes_address(role_id=uuid4().hex) self.assertEqual(len(role_address), 70, "The address is a well-formed address.") self.assertEqual( addresser.address_is(role_address), AddressSpace.ROLES_ATTRIBUTES, "The Role Attributes address created must " "be found to be a Role Attributes address.", ) role_members_address = addresser.make_role_members_address( role_id=uuid4().hex, user_id=uuid4().hex ) self.assertEqual( len(role_members_address), 70, "The address is a well-formed address." ) self.assertEqual( addresser.address_is(role_members_address), AddressSpace.ROLES_MEMBERS, "The Role Members address created must be " "found to be a Role Members address.", ) role_owners_address = addresser.make_role_owners_address( role_id=uuid4().hex, user_id=uuid4().hex ) self.assertEqual( len(role_owners_address), 70, "The address is a well-formed address." ) self.assertEqual( addresser.address_is(role_owners_address), AddressSpace.ROLES_OWNERS, "The Role Owners address created must be found to be " "a Role Members address.", ) role_admins_address = addresser.make_role_admins_address( role_id=uuid4().hex, user_id=uuid4().hex ) self.assertEqual( len(role_admins_address), 70, "The address is a well-formed address." ) self.assertEqual( addresser.address_is(role_admins_address), AddressSpace.ROLES_ADMINS, "The Role Admins address created must be " "found to be a Role Admins address.", ) role_tasks_address = addresser.make_role_tasks_address( role_id=uuid4().hex, task_id=uuid4().hex ) self.assertEqual( len(role_tasks_address), 70, "The address is a well-formed address." ) self.assertEqual( addresser.address_is(role_tasks_address), AddressSpace.ROLES_TASKS, "The Role Tasks address created must be " "found to be a Role Tasks address.", )