cubicweb/server/sources/ldapfeed.py
changeset 12828 dadbd4148a44
parent 12567 26744ad37953
child 12893 4942a6ebf21b
equal deleted inserted replaced
12827:5d1568572895 12828:dadbd4148a44
    63     support_entities = {'CWUser': False}
    63     support_entities = {'CWUser': False}
    64     use_cwuri_as_url = False
    64     use_cwuri_as_url = False
    65 
    65 
    66     options = (
    66     options = (
    67         ('auth-mode',
    67         ('auth-mode',
    68          {'type' : 'choice',
    68          {'type': 'choice',
    69           'default': 'simple',
    69           'default': 'simple',
    70           'choices': ('simple', 'digest_md5', 'gssapi'),
    70           'choices': ('simple', 'digest_md5', 'gssapi'),
    71           'help': 'authentication mode used to authenticate user to the ldap.',
    71           'help': 'authentication mode used to authenticate user to the ldap.',
    72           'group': 'ldap-source', 'level': 3,
    72           'group': 'ldap-source', 'level': 3,
    73           }),
    73           }),
    74         ('auth-realm',
    74         ('auth-realm',
    75          {'type' : 'string',
    75          {'type': 'string',
    76           'default': None,
    76           'default': None,
    77           'help': 'realm to use when using gssapi/kerberos authentication.',
    77           'help': 'realm to use when using gssapi/kerberos authentication.',
    78           'group': 'ldap-source', 'level': 3,
    78           'group': 'ldap-source', 'level': 3,
    79           }),
    79           }),
    80 
    80 
    81         ('data-cnx-dn',
    81         ('data-cnx-dn',
    82          {'type' : 'string',
    82          {'type': 'string',
    83           'default': '',
    83           'default': '',
    84           'help': 'user dn to use to open data connection to the ldap (eg used \
    84           'help': 'user dn to use to open data connection to the ldap (eg used \
    85 to respond to rql queries). Leave empty for anonymous bind',
    85 to respond to rql queries). Leave empty for anonymous bind',
    86           'group': 'ldap-source', 'level': 1,
    86           'group': 'ldap-source', 'level': 1,
    87           }),
    87           }),
    88         ('data-cnx-password',
    88         ('data-cnx-password',
    89          {'type' : 'string',
    89          {'type': 'string',
    90           'default': '',
    90           'default': '',
    91           'help': 'password to use to open data connection to the ldap (eg used to respond to rql queries). Leave empty for anonymous bind.',
    91           'help': 'password to use to open data connection to the ldap (eg used to respond to rql queries). Leave empty for anonymous bind.',
    92           'group': 'ldap-source', 'level': 1,
    92           'group': 'ldap-source', 'level': 1,
    93           }),
    93           }),
    94 
    94 
    95         ('user-base-dn',
    95         ('user-base-dn',
    96          {'type' : 'string',
    96          {'type': 'string',
    97           'default': '',
    97           'default': '',
    98           'help': 'base DN to lookup for users; disable user importation mechanism if unset',
    98           'help': 'base DN to lookup for users; disable user importation mechanism if unset',
    99           'group': 'ldap-source', 'level': 1,
    99           'group': 'ldap-source', 'level': 1,
   100           }),
   100           }),
   101         ('user-scope',
   101         ('user-scope',
   102          {'type' : 'choice',
   102          {'type': 'choice',
   103           'default': 'ONELEVEL',
   103           'default': 'ONELEVEL',
   104           'choices': ('BASE', 'ONELEVEL', 'SUBTREE'),
   104           'choices': ('BASE', 'ONELEVEL', 'SUBTREE'),
   105           'help': 'user search scope (valid values: "BASE", "ONELEVEL", "SUBTREE")',
   105           'help': 'user search scope (valid values: "BASE", "ONELEVEL", "SUBTREE")',
   106           'group': 'ldap-source', 'level': 1,
   106           'group': 'ldap-source', 'level': 1,
   107           }),
   107           }),
   108         ('user-classes',
   108         ('user-classes',
   109          {'type' : 'csv',
   109          {'type': 'csv',
   110           'default': ('top', 'posixAccount'),
   110           'default': ('top', 'posixAccount'),
   111           'help': 'classes of user (with Active Directory, you want to say "user" here)',
   111           'help': 'classes of user (with Active Directory, you want to say "user" here)',
   112           'group': 'ldap-source', 'level': 1,
   112           'group': 'ldap-source', 'level': 1,
   113           }),
   113           }),
   114         ('user-filter',
   114         ('user-filter',
   116           'default': '',
   116           'default': '',
   117           'help': 'additional filters to be set in the ldap query to find valid users',
   117           'help': 'additional filters to be set in the ldap query to find valid users',
   118           'group': 'ldap-source', 'level': 2,
   118           'group': 'ldap-source', 'level': 2,
   119           }),
   119           }),
   120         ('user-login-attr',
   120         ('user-login-attr',
   121          {'type' : 'string',
   121          {'type': 'string',
   122           'default': 'uid',
   122           'default': 'uid',
   123           'help': 'attribute used as login on authentication (with Active Directory, you want to use "sAMAccountName" here)',
   123           'help': 'attribute used as login on authentication (with Active Directory, you want to use "sAMAccountName" here)',
   124           'group': 'ldap-source', 'level': 1,
   124           'group': 'ldap-source', 'level': 1,
   125           }),
   125           }),
   126         ('user-default-group',
   126         ('user-default-group',
   127          {'type' : 'csv',
   127          {'type': 'csv',
   128           'default': ('users',),
   128           'default': ('users',),
   129           'help': 'name of a group in which ldap users will be by default. \
   129           'help': 'name of a group in which ldap users will be by default. \
   130 You can set multiple groups by separating them by a comma.',
   130 You can set multiple groups by separating them by a comma.',
   131           'group': 'ldap-source', 'level': 1,
   131           'group': 'ldap-source', 'level': 1,
   132           }),
   132           }),
   133         ('user-attrs-map',
   133         ('user-attrs-map',
   134          {'type' : 'named',
   134          {'type': 'named',
   135           'default': {'uid': 'login'},
   135           'default': {'uid': 'login'},
   136           'help': 'map from ldap user attributes to cubicweb attributes (with Active Directory, you want to use sAMAccountName:login,mail:email,givenName:firstname,sn:surname)',
   136           'help': 'map from ldap user attributes to cubicweb attributes (with Active Directory, you want to use sAMAccountName:login,mail:email,givenName:firstname,sn:surname)',
   137           'group': 'ldap-source', 'level': 1,
   137           'group': 'ldap-source', 'level': 1,
   138           }),
   138           }),
   139         ('group-base-dn',
   139         ('group-base-dn',
   140          {'type' : 'string',
   140          {'type': 'string',
   141           'default': '',
   141           'default': '',
   142           'help': 'base DN to lookup for groups; disable group importation mechanism if unset',
   142           'help': 'base DN to lookup for groups; disable group importation mechanism if unset',
   143           'group': 'ldap-source', 'level': 1,
   143           'group': 'ldap-source', 'level': 1,
   144           }),
   144           }),
   145         ('group-scope',
   145         ('group-scope',
   146          {'type' : 'choice',
   146          {'type': 'choice',
   147           'default': 'ONELEVEL',
   147           'default': 'ONELEVEL',
   148           'choices': ('BASE', 'ONELEVEL', 'SUBTREE'),
   148           'choices': ('BASE', 'ONELEVEL', 'SUBTREE'),
   149           'help': 'group search scope (valid values: "BASE", "ONELEVEL", "SUBTREE")',
   149           'help': 'group search scope (valid values: "BASE", "ONELEVEL", "SUBTREE")',
   150           'group': 'ldap-source', 'level': 1,
   150           'group': 'ldap-source', 'level': 1,
   151           }),
   151           }),
   152         ('group-classes',
   152         ('group-classes',
   153          {'type' : 'csv',
   153          {'type': 'csv',
   154           'default': ('top', 'posixGroup'),
   154           'default': ('top', 'posixGroup'),
   155           'help': 'classes of group',
   155           'help': 'classes of group',
   156           'group': 'ldap-source', 'level': 1,
   156           'group': 'ldap-source', 'level': 1,
   157           }),
   157           }),
   158         ('group-filter',
   158         ('group-filter',
   160           'default': '',
   160           'default': '',
   161           'help': 'additional filters to be set in the ldap query to find valid groups',
   161           'help': 'additional filters to be set in the ldap query to find valid groups',
   162           'group': 'ldap-source', 'level': 2,
   162           'group': 'ldap-source', 'level': 2,
   163           }),
   163           }),
   164         ('group-attrs-map',
   164         ('group-attrs-map',
   165          {'type' : 'named',
   165          {'type': 'named',
   166           'default': {'cn': 'name', 'memberUid': 'member'},
   166           'default': {'cn': 'name', 'memberUid': 'member'},
   167           'help': 'map from ldap group attributes to cubicweb attributes',
   167           'help': 'map from ldap group attributes to cubicweb attributes',
   168           'group': 'ldap-source', 'level': 1,
   168           'group': 'ldap-source', 'level': 1,
   169           }),
   169           }),
   170     )
   170     )
   271     def _connect(self, user=None, userpwd=None):
   271     def _connect(self, user=None, userpwd=None):
   272         protocol, host, port = self.connection_info()
   272         protocol, host, port = self.connection_info()
   273         self.info('connecting %s://%s:%s as %s', protocol, host, port,
   273         self.info('connecting %s://%s:%s as %s', protocol, host, port,
   274                   user and user['dn'] or 'anonymous')
   274                   user and user['dn'] or 'anonymous')
   275         server = ldap3.Server(host, port=int(port))
   275         server = ldap3.Server(host, port=int(port))
   276         conn = ldap3.Connection(server, user=user and user['dn'], client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE, auto_referrals=False)
   276         conn = ldap3.Connection(
       
   277             server, user=user and user['dn'],
       
   278             client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE,
       
   279             auto_referrals=False)
   277         # Now bind with the credentials given. Let exceptions propagate out.
   280         # Now bind with the credentials given. Let exceptions propagate out.
   278         if user is None:
   281         if user is None:
   279             # XXX always use simple bind for data connection
   282             # XXX always use simple bind for data connection
   280             if not self.cnx_dn:
   283             if not self.cnx_dn:
   281                 conn.bind()
   284                 conn.bind()
   328 
   331 
   329     def _process_ldap_item(self, dn, iterator):
   332     def _process_ldap_item(self, dn, iterator):
   330         """Turn an ldap received item into a proper dict."""
   333         """Turn an ldap received item into a proper dict."""
   331         itemdict = {'dn': dn}
   334         itemdict = {'dn': dn}
   332         for key, value in iterator:
   335         for key, value in iterator:
   333             if self.user_attrs.get(key) == 'upassword': # XXx better password detection
   336             if self.user_attrs.get(key) == 'upassword':  # XXx better password detection
   334                 value = value[0].encode('utf-8')
   337                 value = value[0].encode('utf-8')
   335                 # we only support ldap_salted_sha1 for ldap sources, see: server/utils.py
   338                 # we only support ldap_salted_sha1 for ldap sources, see: server/utils.py
   336                 if not value.startswith(b'{SSHA}'):
   339                 if not value.startswith(b'{SSHA}'):
   337                     value = utils.crypt_password(value)
   340                     value = utils.crypt_password(value)
   338                 itemdict[key] = Binary(value)
   341                 itemdict[key] = Binary(value)