File: LDAPUserFolderAdapter.py

package info (click to toggle)
zope-groupuserfolder 3.1.1-3
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 1,416 kB
  • ctags: 1,037
  • sloc: python: 6,755; sh: 1,365; makefile: 147
file content (185 lines) | stat: -rwxr-xr-x 5,980 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# Re-define a few methods

from global_symbols import *


# These mandatory attributes are required by LDAP schema.
# They will be filled with user name as a default value.
# You have to provide a gruf_ldap_required_fields python script
# in your Plone's skins if you want to override this.
MANDATORY_ATTRIBUTES = ("sn", "cn", )


def _doAddUser(self, name, password, roles, domains, **kw):
    """
    Special user adding method for use with LDAPUserFolder.
    This will ensure parameters are correct for LDAP management
    """
    kwargs = {}               # We will pass this dict
    attrs = {}

    # Get gruf_ldap_required_fields result and fill in mandatory stuff
    if hasattr(self, "gruf_ldap_required_fields"):
        attrs = self.gruf_ldap_required_fields(login = name)
    else:
        for attr in MANDATORY_ATTRIBUTES:
            attrs[attr] = name
    kwargs.update(attrs)

    # We assume that name is rdn attribute
    rdn_attr = self._rdnattr
    kwargs[rdn_attr] = name

    # Manage password(s)
    kwargs['user_pw'] = password
    kwargs['confirm_pw'] = password

    # Mangle roles
    kwargs['user_roles'] = self._mangleRoles(name, roles)

    # Delegate to LDAPUF default method
    msg = self.manage_addUser(kwargs = kwargs)
    if msg:
        raise RuntimeError, msg


def _doDelUsers(self, names):
    """
    Remove a bunch of users from LDAP.
    We have to call manage_deleteUsers but, before, we need to find their dn.
    """
    dns = []
    for name in names:
        dns.append(self._find_user_dn(name))

    self.manage_deleteUsers(dns)


def _find_user_dn(self, name):
    """
    Convert a name to an LDAP dn
    """
    # Search records matching name
    rdn_attr = self._rdnattr
    v = self.findUser(search_param = rdn_attr, search_term = name)

    # Filter to keep exact matches only
    v = filter(lambda x: x[rdn_attr] == name, v)

    # Now, decide what to do
    l = len(v)
    if not l:
        # Invalid name
        raise "Invalid user name: '%s'" % (name, )
    elif l > 1:
        # Several records... don't know how to handle
        raise "Duplicate user name for '%s'" % (name, )
    return v[0]['dn']


def _mangleRoles(self, name, roles):
    """
    Return role_dns for this user
    """
    # Local groups => the easiest part
    if self._local_groups:
        return roles

    # We have to transform roles into group dns: transform them as a dict
    role_dns = []
    all_groups = self.getGroups()
    all_roles = self.valid_roles()
    groups = {}
    for g in all_groups:
        groups[g[0]] = g[1]

    # LDAPUF does the mistake of adding possibly invalid roles to the user roles
    # (for example, adding the cn of a group additionnaly to the mapped zope role).
    # So we must remove from our 'roles' list all roles which are prefixed by group prefix
    # but are not actually groups.
    # See http://www.dataflake.org/tracker/issue_00376 for more information on that
    # particular issue.
    # If a group has the same name as a role, we assume that it should be a _role_.
    # We should check against group/role mapping here, but... well... XXX TODO !
    # See "HERE IT IS" comment below.

    # Scan roles we are asking for to manage groups correctly
    Log(LOG_DEBUG, "Scanning roles for", name, roles, )
    for role in roles:
        if not role in all_roles:
            continue                        # Do not allow propagation of invalid roles
        if role.startswith(GROUP_PREFIX):
            role = role[GROUP_PREFIX_LEN:]          # Remove group prefix : groups are stored WITHOUT prefix in LDAP
            if role in all_roles:
                continue                            # HERE IT IS
        r = groups.get(role, None)
        if not r:
            Log(LOG_WARNING, "LDAP Server doesn't provide a '%s' group (required for user '%s')." % (role, name, ))
        role_dns.append(r)

    Log(LOG_DEBUG, name, role_dns)
    return role_dns


def _doChangeUser(self, name, password, roles, domains, **kw):
    """
    Update a user
    """
    # Find the dn at first
    dn = self._find_user_dn(name)
    
    # Change password
    if password is not None:
        if password == '':
            raise ValueError, "Password must not be empty for LDAP users."
        self.manage_editUserPassword(dn, password)
        
    # Perform role change
    self.manage_editUserRoles(dn, self._mangleRoles(name, roles))

    # (No domain management with LDAP.)

    
def manage_editGroupRoles(self, user_dn, role_dns=[], REQUEST=None):
    """ Edit the roles (groups) of a group """
    from Products.LDAPUserFolder.utils import ldap_scopes, GROUP_MEMBER_MAP, filter_format
    from Products.LDAPUserFolder.LDAPDelegate import ADD, DELETE, REPLACE, BASE

    msg = ""

##    Log(LOG_DEBUG, "assigning", role_dns, "to", user_dn)
    all_groups = self.getGroups(attr='dn')
    cur_groups = self.getGroups(dn=user_dn, attr='dn')
    group_dns = []
    for group in role_dns:
        if group.find('=') == -1:
            group_dns.append('cn=%s,%s' % (group, self.groups_base))
        else:
            group_dns.append(group)

    if self._local_groups:
        if len(role_dns) == 0:
            del self._groups_store[user_dn]
        else:
            self._groups_store[user_dn] = role_dns

    else:
        for group in all_groups:
            member_attr = GROUP_MEMBER_MAP.get(self.getGroupType(group))

            if group in cur_groups and group not in group_dns:
                action = DELETE
            elif group in group_dns and group not in cur_groups:
                action = ADD
            else:
                action = None
            if action is not None:
                msg = self._delegate.modify(
                    group
                    , action
                    , {member_attr : [user_dn]}
                    )
##                Log(LOG_DEBUG, "group", group, "subgroup", user_dn, "result", msg)

    if msg:
        raise RuntimeError, msg