1#------------------------------------------------------------------------------
2# Copyright (c) 2008, Riverbank Computing Limited
3# All rights reserved.
4#
5# This software is provided without warranty under the terms of the BSD
6# license included in enthought/LICENSE.txt and may be redistributed only
7# under the conditions described in the aforementioned license.  The license
8# is also available online at http://www.enthought.com/licenses/BSD.txt
9# Thanks for using Enthought open source!
10#
11# Author: Riverbank Computing Limited
12# Description: <Enthought permissions package component>
13#------------------------------------------------------------------------------
14
15
16# Enthought library imports.
17from pyface.api import error
18from pyface.action.api import Action
19from traits.api import Dict, HasTraits, provides, Instance, List
20
21# Local imports.
22from apptools.permissions.i_policy_manager import IPolicyManager
23from apptools.permissions.permission import ManagePolicyPermission, Permission
24from apptools.permissions.secure_proxy import SecureProxy
25from .i_policy_storage import IPolicyStorage, PolicyStorageError
26from .role_assignment import role_assignment
27from .role_definition import role_definition
28
29
30@provides(IPolicyManager)
31class PolicyManager(HasTraits):
32    """The default policy manager implementation.  This policy enforces the use
33    of roles.  Permissions are associated with roles rather than directly with
34    users.  Users are then associated with one or more roles."""
35
36
37
38    #### 'IPolicyManager' interface ###########################################
39
40    management_actions = List(Instance(Action))
41
42    user_permissions = List(Instance(Permission))
43
44    #### 'PolicyManager' interface ############################################
45
46    # The dictionary of registered permissions keyed on the permission name.
47    permissions = Dict
48
49    # The policy data storage.
50    policy_storage = Instance(IPolicyStorage)
51
52    ###########################################################################
53    # 'IPolicyManager' interface.
54    ###########################################################################
55
56    def bootstrapping(self):
57        """Return True if we are bootstrapping, ie. no roles have been defined
58        or assigned."""
59
60        try:
61            bootstrap = self.policy_storage.is_empty()
62        except PolicyStorageError:
63            # Suppress the error and assume it isn't empty.
64            bootstrap = False
65
66        return bootstrap
67
68    def load_policy(self, user):
69        """Load the policy for the given user."""
70
71        self.user_permissions = []
72
73        # See if the policy is to be unloaded.
74        if user is None:
75            return
76
77        # Get the user's policy.
78        try:
79            user_name, perm_ids = self.policy_storage.get_policy(user.name)
80        except PolicyStorageError as e:
81            error(None, str(e))
82            return
83
84        for id in perm_ids:
85            try:
86                permission = self.permissions[id]
87            except KeyError:
88                # This shouldn't happen if referential integrity is maintained.
89                continue
90
91            self.user_permissions.append(permission)
92
93    def register_permission(self, permission):
94        """Register the given permission."""
95
96        if permission.id in self.permissions:
97            other = self.permissions[permission.id]
98
99            if other.application_defined:
100                if permission.application_defined:
101                    raise KeyError('permission "%s" has already been defined' % permission.id)
102
103                # Use the description from the policy manager, if there is
104                # one, in preference to the application supplied one.
105                if permission.description:
106                    other.description = permission.description
107            elif permission.application_defined:
108                # Again, prefer the policy manager description.
109                if other.description:
110                    permission.description = other.description
111
112                self.permissions[permission.id] = permission
113            else:
114                # This should never happen if the policy manager is working
115                # properly.
116                raise KeyError('permission "%s" has already been defined by the same policy manager' % permission.id)
117        else:
118            self.permissions[permission.id] = permission
119
120    ###########################################################################
121    # Trait handlers.
122    ###########################################################################
123
124    def _management_actions_default(self):
125        """Return the management actions to manage the policy."""
126
127        actions = []
128        perm = ManagePolicyPermission()
129
130        act = Action(name='&Role Definitions...', on_perform=role_definition)
131        actions.append(SecureProxy(act, permissions=[perm], show=False))
132
133        act = Action(name='&Role Assignments...', on_perform=role_assignment)
134        actions.append(SecureProxy(act, permissions=[perm], show=False))
135
136        return actions
137
138    def _policy_storage_default(self):
139        """Return the default storage for the policy data."""
140
141        # Defer to an external storage manager if there is one.
142        try:
143            from apptools.permissions.external.policy_storage import PolicyStorage
144        except ImportError:
145            from apptools.permissions.default.policy_storage import PolicyStorage
146
147        return PolicyStorage()
148