def testRolePermission(self):
     permission = definePermission('APerm', 'aPerm title').id
     role = defineRole('ARole', 'A Role').id
     manager.grantPermissionToRole(permission, role)
     self.assertEqual(manager.getRolesForPermission(permission),
                                                     [(role,Allow)])
     self.assertEqual(manager.getPermissionsForRole(role),
                                                 [(permission,Allow)])
Ejemplo n.º 2
0
def zcml_transition_permission(pid, title, roles):
    ZCML_LINES.append(ZCML_INDENT)
    ZCML_LINES.append('%s<permission id="%s" title="%s" />' % (
        ZCML_INDENT, pid, title))
    provideUtility(Permission(pid), IPermission, pid)
    for role in roles:
        ZCML_LINES.append(
            '%s<grant permission="%s" role="%s" />' % (ZCML_INDENT, pid, role))
        rpm.grantPermissionToRole(pid, role, check=False)
Ejemplo n.º 3
0
def reload_roles(stream):
    log.info("(Re)Loading OMS permission definitions")
    for line in stream:
        nick, role, permissions = line.split(':', 4)
        oms_role = Role(role, nick)
        provideUtility(oms_role, IRole, role)
        for perm in permissions.split(','):
            if perm.strip():
                rolePermissionManager.grantPermissionToRole(perm.strip(), role.strip())
def reload_roles(stream):
    log.info("(Re)Loading OMS permission definitions")
    for line in stream:
        nick, role, permissions = line.split(':', 4)
        oms_role = Role(role, nick)
        provideUtility(oms_role, IRole, role)
        for perm in permissions.split(','):
            if perm.strip():
                rolePermissionManager.grantPermissionToRole(
                    perm.strip(), role.strip())
Ejemplo n.º 5
0
    def add_retract_transitions(wf):
        def getRoles(transition):
            original_roles = transition.user_data.get("_roles", [])
            allowed_roles = set()
            #transitions to  source
            tx_to_source = wf.get_transitions_to(transition.source)
            for tx in tx_to_source:
                if tx.source is None:
                    allowed_roles.update(set(original_roles))
                else:
                    for role in tx.user_data.get("_roles", []):
                        if role in original_roles:
                            allowed_roles.add(role)
            if not len(allowed_roles):
                allowed_roles = original_roles
            return allowed_roles

        transitions = wf._transitions_by_id.values()
        terminal_transitions = [
            transition for transition in transitions if
            (wf.get_transitions_from(transition.destination) == [] and
                transition.source and transition.trigger in [MANUAL, SYSTEM]
            )
        ]
        for transition in terminal_transitions:
            roles = getRoles(transition)
            if roles:
                title = _("revert_transition_title",
                    default="Undo - ${title}",
                    mapping={
                        "title": translate(transition.title, domain="bungeni")
                    }
                )
                title = "Undo - %s" % transition.title
                tid = "%s.%s" % (transition.destination, 
                    transition.source)
                pid = "bungeni.%s.wf.%s" % (wf.name, tid)
                ntransition = Transition(title, transition.destination,
                    transition.source, 
                    trigger=MANUAL,
                    condition=allow_retract,
                    permission=pid,
                    condition_args=True,
                    roles=roles)
                if ntransition.id in wf._transitions_by_id:
                    continue
                log.debug("adding transition %s", ntransition.id)
                provideUtility(Permission(pid), IPermission, pid)
                for role in roles:
                    role_perm_mgr.grantPermissionToRole(pid, role, check=False)
                transitions.append(ntransition)
        wf.refresh(wf._states_by_id.values(), transitions)
Ejemplo n.º 6
0
    def add_retract_transitions(wf):
        def getRoles(transition):
            original_roles = transition.user_data.get("_roles", [])
            allowed_roles = set()
            #transitions to  source
            tx_to_source = wf.get_transitions_to(transition.source)
            for tx in tx_to_source:
                if tx.source is None:
                    allowed_roles.update(set(original_roles))
                else:
                    for role in tx.user_data.get("_roles", []):
                        if role in original_roles:
                            allowed_roles.add(role)
            if not len(allowed_roles):
                allowed_roles = original_roles
            return allowed_roles

        transitions = wf._transitions_by_id.values()
        terminal_transitions = [
            transition for transition in transitions
            if (wf.get_transitions_from(transition.destination) == [] and
                transition.source and transition.trigger in [MANUAL, SYSTEM])
        ]
        for transition in terminal_transitions:
            roles = getRoles(transition)
            if roles:
                title = _("revert_transition_title",
                          default="Undo - ${title}",
                          mapping={
                              "title":
                              translate(transition.title, domain="bungeni")
                          })
                title = "Undo - %s" % transition.title
                tid = "%s.%s" % (transition.destination, transition.source)
                pid = "bungeni.%s.wf.%s" % (wf.name, tid)
                ntransition = Transition(title,
                                         transition.destination,
                                         transition.source,
                                         trigger=MANUAL,
                                         condition=allow_retract,
                                         permission=pid,
                                         condition_args=True,
                                         roles=roles)
                if ntransition.id in wf._transitions_by_id:
                    continue
                log.debug("adding transition %s", ntransition.id)
                provideUtility(Permission(pid), IPermission, pid)
                for role in roles:
                    role_perm_mgr.grantPermissionToRole(pid, role, check=False)
                transitions.append(ntransition)
        wf.refresh(wf._states_by_id.values(), transitions)
Ejemplo n.º 7
0
def create_special_principals():
    auth = queryUtility(IAuthentication)

    auth.registerPrincipal(User('oms.anonymous'))

    groot = Group('root')
    auth.registerPrincipal(groot)

    root = User('root')
    root.groups.append('root')
    auth.registerPrincipal(root)

    # TODO: create/use a global registry of permissions
    permissions = ['read', 'modify', 'create', 'add', 'remove', 'delete', 'view', 'traverse',
                   'zope.Security']

    root_role = Role('root', 'root')
    provideUtility(root_role, IRole, 'root')
    for perm in permissions:
        rolePermissionManager.grantPermissionToRole(perm, 'root')

    principalRoleManager.assignRoleToPrincipal('root', 'root')

    owner_role = Role('owner', 'o')
    provideUtility(owner_role, IRole, 'owner')
    for perm in permissions:
        rolePermissionManager.grantPermissionToRole(perm, 'owner')

    for permission in permissions:
        rolePermissionManager.grantPermissionToRole(permission, 'root')
        rolePermissionManager.grantPermissionToRole(permission, 'owner')

    auth.registerPrincipal(User('oms.rest_options'))

    principalPermissionManager.grantPermissionToPrincipal('rest', 'oms.rest_options')
def create_special_principals():
    auth = queryUtility(IAuthentication)

    auth.registerPrincipal(User('oms.anonymous'))

    groot = Group('root')
    auth.registerPrincipal(groot)

    root = User('root')
    root.groups.append('root')
    auth.registerPrincipal(root)

    # TODO: create/use a global registry of permissions
    permissions = [
        'read', 'modify', 'create', 'add', 'remove', 'delete', 'view',
        'traverse', 'zope.Security'
    ]

    root_role = Role('root', 'root')
    provideUtility(root_role, IRole, 'root')
    for perm in permissions:
        rolePermissionManager.grantPermissionToRole(perm, 'root')

    principalRoleManager.assignRoleToPrincipal('root', 'root')

    owner_role = Role('owner', 'o')
    provideUtility(owner_role, IRole, 'owner')
    for perm in permissions:
        rolePermissionManager.grantPermissionToRole(perm, 'owner')

    for permission in permissions:
        rolePermissionManager.grantPermissionToRole(permission, 'root')
        rolePermissionManager.grantPermissionToRole(permission, 'owner')

    auth.registerPrincipal(User('oms.rest_options'))

    principalPermissionManager.grantPermissionToPrincipal(
        'rest', 'oms.rest_options')
 def testManyRolesOnePermission(self):
     perm1 = definePermission('Perm One', 'title').id
     role1 = defineRole('Role One', 'Role #1').id
     role2 = defineRole('Role Two', 'Role #2').id
     roles = manager.getRolesForPermission(perm1)
     self.assertEqual(len(roles), 0)
     manager.grantPermissionToRole(perm1, role1)
     manager.grantPermissionToRole(perm1, role2)
     manager.grantPermissionToRole(perm1, role2)
     manager.denyPermissionToRole(perm1, role1)
     roles = manager.getRolesForPermission(perm1)
     self.assertEqual(len(roles), 2)
     self.failIf((role1,Allow) in roles)
     self.failUnless((role1,Deny) in roles)
     self.failUnless((role2,Allow) in roles)
     manager.unsetPermissionFromRole(perm1, role1)
     roles = manager.getRolesForPermission(perm1)
     self.assertEqual(len(roles), 1)
     self.failUnless((role2,Allow) in roles)
Ejemplo n.º 10
0
 def testManyPermissionsOneRole(self):
     perm1 = definePermission('Perm One', 'P1').id
     perm2 = definePermission('Perm Two', 'P2').id
     perm3 = definePermission('Perm Three', 'P3').id
     role1 = defineRole('Role One', 'Role #1').id
     perms = manager.getPermissionsForRole(role1)
     self.assertEqual(len(perms), 0)
     manager.grantPermissionToRole(perm1, role1)
     manager.grantPermissionToRole(perm2, role1)
     manager.grantPermissionToRole(perm2, role1)
     manager.denyPermissionToRole(perm3, role1)
     perms = manager.getPermissionsForRole(role1)
     self.assertEqual(len(perms), 3)
     self.failUnless((perm1,Allow) in perms)
     self.failUnless((perm2,Allow) in perms)
     self.failUnless((perm3,Deny) in perms)
     manager.unsetPermissionFromRole(perm1, role1)
     perms = manager.getPermissionsForRole(role1)
     self.assertEqual(len(perms), 2)
     self.failUnless((perm2,Allow) in perms)
Ejemplo n.º 11
0
def _load(workflow_name, workflow):
    """ (workflow_name:str, workflow:etree_doc) -> Workflow
    """
    workflow_title = xas(workflow, "title")
    naming.MSGIDS.add(workflow_title)
    workflow_description = xas(workflow, "description")
    naming.MSGIDS.add(workflow_description)
    transitions = []
    states = []
    note = xas(workflow, "note")
    
    # initial_state, in XML indicated with a transition.@source=""
    initial_state = None
    
    ZCML_PROCESSED = bool(workflow_name in ZCML_WORKFLOWS_PROCESSED)
    if not ZCML_PROCESSED:
        ZCML_WORKFLOWS_PROCESSED.add(workflow_name)
        ZCML_LINES.append(ZCML_INDENT)
        ZCML_LINES.append(ZCML_INDENT)
        ZCML_LINES.append("%s<!-- %s -->" % (ZCML_INDENT, workflow_name))
    
    def validate_id(id, tag):
        """Ensure that ID values are unique within the same XML doc scope.
        """
        m = "Invalid element <%s> id=%r in workflow %r" % (tag, id, workflow_name)
        assert id not in validate_id.wuids, "%s -- id not unique in workflow document" % (m)
        validate_id.wuids.add(id)
    validate_id.wuids = set() # unique IDs in this XML workflow file
    
    def get_from_state(state_id):
        if state_id is None:
            return
        for state in states:
            if state.id == state_id:
                return state
        raise ValueError("Invalid value: permissions_from_state=%r" % (state_id))
    
    def check_not_global_grant(pid, role):
        # ensure global and local assignments are distinct
        # (global: global_pid_roles, workflow_name)
        global_proles = global_pid_roles.get(pid, "")
        assert role not in global_proles, ("Workflow [%s] may not mix "
            "global and local granting of a same permission [%s] to a "
            "same role [%s].") % (workflow_name, pid, role)
    
    # permission_actions -> permissions for this type
    for (key, permission_action) in capi.schema.qualified_permission_actions(
            workflow_name, xas(workflow, "permission_actions", "").split()
        ):
        pid = "bungeni.%s.%s" % (key, permission_action)
        title = "%s %s" % (
            permission_action, naming.split_camel(naming.model_name(key)))
        # !+ add to a Workflow.defines_permissions list
        ZCML_LINES.append(
            '%s<permission id="%s" title="%s" />' % (ZCML_INDENT, pid, title))
        provideUtility(Permission(pid), IPermission, pid)
    
    # global grants
    global_pid_roles = {} # {pid: [role]}
    global_grants = get_permissions_from_allows(workflow_name, workflow)
    for (setting, pid, role) in global_grants:
        # for each global permission, build list of roles it is set to
        global_pid_roles.setdefault(pid, []).append(role)
        assert setting and pid and role, \
            "Global grant must specify valid permission/role" #!+RNC
        # !+ add to a Workflow.global_grants list
        ZCML_LINES.append(
            '%s<grant permission="%s" role="%s" />' % (ZCML_INDENT, pid, role))
        # no real need to check that the permission and role of a global grant 
        # are properly registered in the system -- an error should be raised 
        # by the zcml if either is not defined.
        rpm.grantPermissionToRole(pid, role, check=False)

    for perm, roles in global_pid_roles.items():
        # assert roles mix limitations for state permissions
        assert_distinct_permission_scopes(perm, roles, workflow_name, "global grants")
    
    # all workflow features (enabled AND disabled)
    workflow_features = load_features(workflow_name, workflow)
    enabled_feature_names = [None] + [ 
        f.name for f in workflow_features if f.enabled ]
    # !+EVENT_FEATURE_TYPES add each as enabled_feature_names, or extend the 
    # facet quailifer by feature_name(sub_type_key).facet_ref?
    # workflow facets
    workflow_facets = load_facets(workflow_name, workflow)
    
    # states
    for s in workflow.iterchildren("state"):
        # @id
        state_id = xas(s, "id")
        assert state_id, "Workflow State must define @id" #!+RNC
        validate_id(state_id, "state")
        
        # @actions - transition-to-state actions
        state_actions = []
        for action_name in xas(s, "actions", "").split():
            state_actions.append(capi.get_workflow_action(action_name))
        
        # @permissions_from_state
        permissions = [] # [ tuple(bool:int, permission:str, role:str) ]
        # state.@permissions_from_state : to reduce repetition and enhance 
        # maintainibility of workflow XML files, a state may inherit ALL 
        # permissions defined by the specified state. NO other permissions 
        # may be specified by this state. 
        from_state = get_from_state(xas(s, "permissions_from_state"))
        parent_permissions = xab(s, "parent_permissions")
        if parent_permissions:
            pass # no own permission definitions allowed
        elif from_state:
            # assimilate (no more no less) the state's permissions !+tuple, use same?
            permissions[:] = from_state.permissions
        else:
            used_facets_fq = resolve_state_facets(
                workflow_name, workflow_facets, enabled_feature_names, s)
            # assimilate permissions from facets from None and all enabled features
            def add_facet_permissions(facet):
                for perm in facet.permissions:
                    check_add_assign_permission(workflow_name, permissions, perm)
                    check_not_global_grant(perm[1], perm[2])
            for (feature_name, qtk) in used_facets_fq:
                # debug check that feature is enabled
                assert feature_name in enabled_feature_names
                facet = used_facets_fq[(feature_name, qtk)]
                if facet is not None:
                    add_facet_permissions(facet)
        
        # states
        state_title = xas(s, "title")
        naming.MSGIDS.add(state_title)
        states.append(
            State(state_id, state_title,
                xas(s, "note"),
                state_actions, permissions,
                parent_permissions,
                xab(s, "obsolete"),
            )
        )
    
    STATE_IDS = [ s.id for s in states ]
    
    # transitions
    for t in workflow.iterchildren("transition"):
        title = xas(t, "title")
        naming.MSGIDS.add(title)
        # sources, empty string -> initial_state
        sources = t.get("source").split() or [initial_state]
        assert len(sources) == len(set(sources)), \
            "Transition contains duplicate sources [%s]" % (sources)
        for source in sources:
            if source is not initial_state:
                assert source in STATE_IDS, \
                    "Unknown transition source state [%s]" % (source)
        # destination must be a valid state
        destination = t.get("destination")
        assert destination in STATE_IDS, \
            "Unknown transition destination state [%s]" % (destination)
        
        # optionals -- only set on kw IFF explicitly defined
        kw = {}
        for i in TRANS_ATTRS_OPTIONALS:
            val = xas(t, i)
            if not val:
                # we let setting of defaults be handled downstream
                continue
            kw[i] = val
        
        # data up-typing
        #
        # trigger
        if "trigger" in kw:
            kw["trigger"] = trigger_value_map[kw["trigger"]]
        # roles -> permission - one-to-one per transition
        roles = capi.schema.qualified_roles(kw.pop("roles", ""))
        if not is_zcml_permissionable(t):
            assert not roles, "Workflow [%s] - non-permissionable transition " \
                "does not allow @roles [%s]." % (workflow_name, roles) #!+RNC
            kw["permission"] = None # None -> CheckerPublic
        # !+CAN_EDIT_AS_DEFAULT_TRANSITION_PERMISSION(mr, oct-2011) this feature
        # is functional (uncomment following elif clause) but as yet not enabled. 
        #
        # Advantage would be that it would be easier to keep transitions 
        # permissions in sync with object permissions (set in state) as the 
        # majority of transition require exactly this as privilege; for the 
        # occassional transition needing a different privilege, the current 
        # transition.@roles mechanism may be used to make this explicit. 
        #
        # Need to consider implications further; the zope_principal_role_map db 
        # table, that caches contextual roles for principals, should probably 
        # first be reworked to be db-less (as for zope_role_permission_map).
        #
        #elif not roles:
        #    # then as fallback transition permission use can modify object
        #    kw["permission"] = "bungeni.%s.Edit" % (workflow_name) # fallback permission
        else:
            # Dedicated permission for XML multi-source transition.
            # Given that, irrespective of how sources are grouped into 
            # multi-source XML <transition> elements, there may be only *one* 
            # path from any given *source* to any given *destination* state, 
            # it suffices to use only the first source element + the destination 
            # to guarantee a unique identifier for an XML transition element.
            #
            # Note: the "-" char is not allowed within a permission id 
            # (so we use "." also here).
            #
            tid = "%s.%s" % (sources[0] or "", destination)
            pid = "bungeni.%s.wf.%s" % (workflow_name, tid)
            if not ZCML_PROCESSED:
                zcml_transition_permission(pid, title, roles)
                # remember list of roles from xml
                kw["_roles"] = roles
            kw["permission"] = pid
        # python resolvables
        if "condition" in kw:
            kw["condition"] = capi.get_workflow_condition(kw["condition"])
        # numeric
        if "order" in kw:
            kw["order"] = float(kw["order"]) # ValueError if not numeric
        # bool
        if "require_confirmation" in kw:
            try:
                kw["require_confirmation"] = misc.as_bool(kw["require_confirmation"])
                assert kw["require_confirmation"] is not None #!+RNC
            except:
                raise ValueError("Invalid transition value "
                    '[require_confirmation="%s"]' % (
                        t.get("require_confirmation")))
        # multiple-source transitions are really multiple "transition paths"
        for source in sources:
            args = (title, source, destination)
            transitions.append(Transition(*args, **kw))
            log.debug("[%s] adding transition [%s-%s] [%s]" % (
                workflow_name, source or "", destination, kw))
    
    return Workflow(workflow_name,
        workflow_features, workflow_facets, states, transitions, global_grants,
        workflow_title, workflow_description, note)