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)
Example #2
0
    def test_deterministic_role_address(self):
        """Tests that a specific role_id generates the expected
        role address, and thus is probably deterministic.
        """

        ident = '99968acb8f1a48b3a4bc21e2cd252e67'
        expected_address = '9f444809326a1713a905b26359fc8d\
a2817c1a5f67de6f464701f0c10042da345d2800'

        address = addresser.make_role_attributes_address(ident)

        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_ATTRIBUTES,
            "The address created must be a Role Attributes address.")
def propose_add_role_tasks(txn_key, batch_key, proposal_id, role_id, task_id,
                           reason, metadata):
    propose_payload = role_transaction_pb2.ProposeAddRoleTask(
        proposal_id=proposal_id,
        role_id=role_id,
        task_id=task_id,
        reason=reason,
        metadata=metadata)

    inputs = [
        addresser.make_proposal_address(role_id, task_id),
        addresser.make_role_tasks_address(role_id, task_id),
        addresser.make_role_owners_address(role_id, txn_key.public_key),
        addresser.make_role_attributes_address(role_id),
        addresser.make_task_attributes_address(task_id)
    ]

    outputs = [addresser.make_proposal_address(role_id, task_id)]

    rbac_payload = rbac_payload_pb2.RBACPayload(
        content=propose_payload.SerializeToString(),
        message_type=rbac_payload_pb2.RBACPayload.PROPOSE_ADD_ROLE_TASKS)

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key,
                                 batch_key)
Example #4
0
def _handle_role_state_set(create_role, state):
    role_container = role_state_pb2.RoleAttributesContainer()
    role = role_container.role_attributes.add()
    role.role_id = create_role.role_id
    role.name = create_role.name
    role.metadata = create_role.metadata

    entries_to_set = [
        StateEntry(address=addresser.make_role_attributes_address(
            create_role.role_id),
                   data=role_container.SerializeToString())
    ]

    pubkeys_by_address = {}

    for admin in list(create_role.admins):
        admin_address = addresser.make_role_admins_address(
            role_id=create_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(create_role.owners):
        owner_address = addresser.make_role_owners_address(
            role_id=create_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 = get_state(state, [
        addresser.make_role_admins_address(role_id=create_role.role_id,
                                           user_id=a)
        for a in create_role.admins
    ] + [
        addresser.make_role_owners_address(role_id=create_role.role_id,
                                           user_id=o)
        for o in create_role.owners
    ])

    for addr, pubkeys in pubkeys_by_address.items():
        try:
            state_entry = get_state_entry(state_returns, addr)
            container = role_state_pb2.RoleRelationshipContainer()
            container.ParseFromString(state_entry.data)
        except KeyError:
            container = role_state_pb2.RoleRelationshipContainer()

        _add_role_rel_to_container(container, create_role.role_id, pubkeys)

        entries_to_set.append(
            StateEntry(address=addr, data=container.SerializeToString()))
    set_state(state, entries_to_set)
Example #5
0
def validate_role_rel_proposal(header, propose, rel_address, state):
    """Validates that the User exists, the Role exists, and the User is not
    in the Role's relationship specified by rel_address.

    Args:
        header (TransactionHeader): The transaction header.
        propose (ProposeAddRole_____): The role relationship proposal.
        rel_address (str): The Role relationship address produced by the Role
            and the User.
        state (sawtooth_sdk.Context): The way to communicate to the validator
            the state gets and sets.

    Returns:
        (dict of addresses)
    """

    user_address = addresser.make_user_address(propose.user_id)
    role_address = addresser.make_role_attributes_address(propose.role_id)
    proposal_address = addresser.make_proposal_address(
        object_id=propose.role_id, related_id=propose.user_id)

    state_entries = get_state(
        state, [user_address, role_address, proposal_address, rel_address])
    validate_identifier_is_user(state_entries,
                                identifier=propose.user_id,
                                address=user_address)
    user_entry = get_state_entry(state_entries, user_address)
    user = get_user_from_container(return_user_container(user_entry),
                                   propose.user_id)

    if header.signer_public_key not in [user.user_id, user.manager_id]:
        raise InvalidTransaction(
            "Txn signer {} is not the user or the user's "
            "manager {}".format(header.signer_public_key,
                                [user.user_id, user.manager_id]))

    validate_identifier_is_role(state_entries,
                                identifier=propose.role_id,
                                address=role_address)

    try:
        role_admins_entry = get_state_entry(state_entries, rel_address)
        role_rel_container = return_role_rel_container(role_admins_entry)
        if is_in_role_rel_container(role_rel_container, propose.role_id,
                                    propose.user_id):
            raise InvalidTransaction("User {} is already in the Role {} "
                                     "relationship".format(
                                         propose.user_id, propose.role_id))
    except KeyError:
        # The role rel container doesn't exist so no role relationship exists
        pass

    return state_entries
Example #6
0
def _validate_create_role_state(create_role, state):
    state_return = get_state(
        state, [addresser.make_role_attributes_address(create_role.role_id)])

    if _role_already_exists(state_return, create_role.role_id):
        raise InvalidTransaction("Role id {} is already in state".format(
            create_role.role_id))

    users = list(create_role.admins) + list(create_role.owners)
    user_state_return = get_state(
        state, [addresser.make_user_address(u) for u in users])

    validate_list_of_user_are_users(user_state_return, users)
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)
Example #8
0
    def test_generated_role_address(self):
        """Tests the role address creation function as well as the
        address_is function.
        """

        ident = uuid4().hex
        address = addresser.make_role_attributes_address(ident)

        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_ATTRIBUTES,
            "The address created must be a Role Attributes address.")
def propose_remove_role_members(txn_key, batch_key, proposal_id, role_id,
                                user_id, reason, metadata):
    propose = role_transaction_pb2.ProposeRemoveRoleMember(
        proposal_id=proposal_id,
        role_id=role_id,
        user_id=user_id,
        reason=reason,
        metadata=metadata)

    inputs = [
        addresser.make_role_members_address(role_id, user_id),
        addresser.make_role_attributes_address(role_id=role_id),
        addresser.make_user_address(user_id=user_id),
        addresser.make_proposal_address(role_id, user_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_MEMBERS)

    return make_header_and_batch(rbac_payload, inputs, outputs, txn_key,
                                 batch_key)
Example #10
0
def validate_role_task_proposal(header, propose, state):
    """Applies state validation rules for ADDRoleTaskProposal.
        - The Role exists.
        - The Task exists.
        - The Transaction was signed by a Role Owner.
        - There is no open Proposal for the same change.
        - The task is not already part of the Role.

    Args:
        header (TransactionHeader): The propobuf transaction header.
        propose (ProposeAddRoleTask): The protobuf transaction.
        state (Context): A connection to the validator to ask about state.

    Returns:
        (list of StateEntry)

    """

    role_address = addresser.make_role_attributes_address(propose.role_id)

    task_address = addresser.make_task_attributes_address(propose.task_id)

    proposal_address = addresser.make_proposal_address(
        propose.role_id,
        propose.task_id)

    txn_signer_role_owner_address = addresser.make_role_owners_address(
        role_id=propose.role_id,
        user_id=header.signer_pubkey)

    role_tasks_address = addresser.make_role_tasks_address(propose.role_id,
                                                           propose.task_id)

    state_entries = get_state(
        state=state,
        addresses=[role_address,
                   task_address,
                   proposal_address,
                   role_tasks_address,
                   txn_signer_role_owner_address])

    validate_identifier_is_role(
        state_entries=state_entries,
        address=role_address,
        identifier=propose.role_id)

    validate_identifier_is_task(
        state_entries=state_entries,
        identifier=propose.task_id,
        address=task_address)
    try:
        role_task_entry = get_state_entry(state_entries, role_tasks_address)
        role_task_container = return_role_rel_container(role_task_entry)
        if is_in_role_rel_container(role_task_container,
                                    role_id=propose.role_id,
                                    identifier=propose.task_id):
            raise InvalidTransaction("Role {} already contains task {}".format(
                propose.role_id,
                propose.task_id))
    except KeyError:
        # The Task is not in the RoleTask state
        pass

    try:
        role_owner_entry = get_state_entry(
            state_entries,
            txn_signer_role_owner_address)
        role_owner_container = return_role_rel_container(role_owner_entry)

        if not is_in_role_rel_container(role_owner_container,
                                        role_id=propose.role_id,
                                        identifier=header.signer_pubkey):
            raise InvalidTransaction(
                "Txn signer {} is not a role owner".format(
                    header.signer_pubkey))
    except KeyError:
        raise InvalidTransaction(
            "Txn signer {} is not a role owner.".format(header.signer_pubkey))

    if not no_open_proposal(
            state_entries=state_entries,
            object_id=propose.role_id,
            related_id=propose.task_id,
            proposal_address=proposal_address,
            proposal_type=proposal_state_pb2.Proposal.ADD_ROLE_TASKS):
        raise InvalidTransaction(
            "There is already an open proposal to add task {} to "
            "role {}".format(propose.task_id, propose.role_id))
    return state_entries
    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.")