Show More
@@ -627,3 +627,21 b' def authenticate(username, password, env' | |||
|
627 | 627 | log.debug("User `%s` failed to authenticate against %s", |
|
628 | 628 | display_user, plugin.get_id()) |
|
629 | 629 | return None |
|
630 | ||
|
631 | ||
|
632 | def chop_at(s, sub, inclusive=False): | |
|
633 | """Truncate string ``s`` at the first occurrence of ``sub``. | |
|
634 | ||
|
635 | If ``inclusive`` is true, truncate just after ``sub`` rather than at it. | |
|
636 | ||
|
637 | >>> chop_at("plutocratic brats", "rat") | |
|
638 | 'plutoc' | |
|
639 | >>> chop_at("plutocratic brats", "rat", True) | |
|
640 | 'plutocrat' | |
|
641 | """ | |
|
642 | pos = s.find(sub) | |
|
643 | if pos == -1: | |
|
644 | return s | |
|
645 | if inclusive: | |
|
646 | return s[:pos+len(sub)] | |
|
647 | return s[:pos] |
@@ -28,10 +28,9 b' import base64' | |||
|
28 | 28 | import logging |
|
29 | 29 | import urllib2 |
|
30 | 30 | |
|
31 |
from |
|
|
32 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
33 | ||
|
34 | from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin | |
|
31 | from rhodecode.translation import _ | |
|
32 | from rhodecode.authentication.base import ( | |
|
33 | RhodeCodeExternalAuthPlugin, hybrid_property) | |
|
35 | 34 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
36 | 35 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
37 | 36 | from rhodecode.lib.colander_utils import strip_whitespace |
@@ -21,15 +21,14 b'' | |||
|
21 | 21 | import colander |
|
22 | 22 | import logging |
|
23 | 23 | |
|
24 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
25 | ||
|
26 | from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin | |
|
24 | from rhodecode.translation import _ | |
|
25 | from rhodecode.authentication.base import ( | |
|
26 | RhodeCodeExternalAuthPlugin, hybrid_property) | |
|
27 | 27 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
28 | 28 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
29 | 29 | from rhodecode.lib.colander_utils import strip_whitespace |
|
30 | 30 | from rhodecode.lib.utils2 import str2bool, safe_unicode |
|
31 | 31 | from rhodecode.model.db import User |
|
32 | from rhodecode.translation import _ | |
|
33 | 32 | |
|
34 | 33 | |
|
35 | 34 | log = logging.getLogger(__name__) |
@@ -30,10 +30,9 b' import rhodecode' | |||
|
30 | 30 | import urllib |
|
31 | 31 | import urllib2 |
|
32 | 32 | |
|
33 |
from |
|
|
34 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
35 | ||
|
36 | from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin | |
|
33 | from rhodecode.translation import _ | |
|
34 | from rhodecode.authentication.base import ( | |
|
35 | RhodeCodeExternalAuthPlugin, hybrid_property) | |
|
37 | 36 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
38 | 37 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
39 | 38 | from rhodecode.lib.colander_utils import strip_whitespace |
@@ -27,10 +27,9 b' import colander' | |||
|
27 | 27 | import logging |
|
28 | 28 | import traceback |
|
29 | 29 | |
|
30 |
from |
|
|
31 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
32 | ||
|
33 | from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin | |
|
30 | from rhodecode.translation import _ | |
|
31 | from rhodecode.authentication.base import ( | |
|
32 | RhodeCodeExternalAuthPlugin, chop_at, hybrid_property) | |
|
34 | 33 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
35 | 34 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
36 | 35 | from rhodecode.lib.colander_utils import strip_whitespace |
@@ -72,14 +71,15 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
72 | 71 | host = colander.SchemaNode( |
|
73 | 72 | colander.String(), |
|
74 | 73 | default='', |
|
75 |
description=_('Host of the LDAP Server' |
|
|
74 | description=_('Host of the LDAP Server \n' | |
|
75 | '(e.g., 192.168.2.154, or ldap-server.domain.com'), | |
|
76 | 76 | preparer=strip_whitespace, |
|
77 | 77 | title=_('LDAP Host'), |
|
78 | 78 | widget='string') |
|
79 | 79 | port = colander.SchemaNode( |
|
80 | 80 | colander.Int(), |
|
81 | 81 | default=389, |
|
82 |
description=_(' |
|
|
82 | description=_('Custom port that the LDAP server is listening on. Default: 389'), | |
|
83 | 83 | preparer=strip_whitespace, |
|
84 | 84 | title=_('Port'), |
|
85 | 85 | validator=colander.Range(min=0, max=65536), |
@@ -87,7 +87,9 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
87 | 87 | dn_user = colander.SchemaNode( |
|
88 | 88 | colander.String(), |
|
89 | 89 | default='', |
|
90 |
description=_(' |
|
|
90 | description=_('Optional user DN/account to connect to LDAP if authentication is required. \n' | |
|
91 | 'e.g., cn=admin,dc=mydomain,dc=com, or ' | |
|
92 | 'uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com'), | |
|
91 | 93 | missing='', |
|
92 | 94 | preparer=strip_whitespace, |
|
93 | 95 | title=_('Account'), |
@@ -95,7 +97,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
95 | 97 | dn_pass = colander.SchemaNode( |
|
96 | 98 | colander.String(), |
|
97 | 99 | default='', |
|
98 |
description=_('Password to |
|
|
100 | description=_('Password to authenticate for given user DN.'), | |
|
99 | 101 | missing='', |
|
100 | 102 | preparer=strip_whitespace, |
|
101 | 103 | title=_('Password'), |
@@ -117,7 +119,9 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
117 | 119 | base_dn = colander.SchemaNode( |
|
118 | 120 | colander.String(), |
|
119 | 121 | default='', |
|
120 |
description=_('Base DN to search |
|
|
122 | description=_('Base DN to search. Dynamic bind is supported. Add `$login` marker ' | |
|
123 | 'in it to be replaced with current user credentials \n' | |
|
124 | '(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)'), | |
|
121 | 125 | missing='', |
|
122 | 126 | preparer=strip_whitespace, |
|
123 | 127 | title=_('Base DN'), |
@@ -125,22 +129,25 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
125 | 129 | filter = colander.SchemaNode( |
|
126 | 130 | colander.String(), |
|
127 | 131 | default='', |
|
128 |
description=_('Filter to narrow results |
|
|
132 | description=_('Filter to narrow results \n' | |
|
133 | '(e.g., (&(objectCategory=Person)(objectClass=user)), or \n' | |
|
134 | '(memberof=cn=rc-login,ou=groups,ou=company,dc=mydomain,dc=com)))'), | |
|
129 | 135 | missing='', |
|
130 | 136 | preparer=strip_whitespace, |
|
131 | 137 | title=_('LDAP Search Filter'), |
|
132 | 138 | widget='string') |
|
139 | ||
|
133 | 140 | search_scope = colander.SchemaNode( |
|
134 | 141 | colander.String(), |
|
135 |
default=search_scope_choices[ |
|
|
136 | description=_('How deep to search LDAP'), | |
|
142 | default=search_scope_choices[2], | |
|
143 | description=_('How deep to search LDAP. If unsure set to SUBTREE'), | |
|
137 | 144 | title=_('LDAP Search Scope'), |
|
138 | 145 | validator=colander.OneOf(search_scope_choices), |
|
139 | 146 | widget='select') |
|
140 | 147 | attr_login = colander.SchemaNode( |
|
141 | 148 | colander.String(), |
|
142 | default='', | |
|
143 | description=_('LDAP Attribute to map to user name'), | |
|
149 | default='uid', | |
|
150 | description=_('LDAP Attribute to map to user name (e.g., uid, or sAMAccountName)'), | |
|
144 | 151 | preparer=strip_whitespace, |
|
145 | 152 | title=_('Login Attribute'), |
|
146 | 153 | missing_msg=_('The LDAP Login attribute of the CN must be specified'), |
@@ -148,7 +155,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
148 | 155 | attr_firstname = colander.SchemaNode( |
|
149 | 156 | colander.String(), |
|
150 | 157 | default='', |
|
151 | description=_('LDAP Attribute to map to first name'), | |
|
158 | description=_('LDAP Attribute to map to first name (e.g., givenName)'), | |
|
152 | 159 | missing='', |
|
153 | 160 | preparer=strip_whitespace, |
|
154 | 161 | title=_('First Name Attribute'), |
@@ -156,7 +163,7 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
156 | 163 | attr_lastname = colander.SchemaNode( |
|
157 | 164 | colander.String(), |
|
158 | 165 | default='', |
|
159 | description=_('LDAP Attribute to map to last name'), | |
|
166 | description=_('LDAP Attribute to map to last name (e.g., sn)'), | |
|
160 | 167 | missing='', |
|
161 | 168 | preparer=strip_whitespace, |
|
162 | 169 | title=_('Last Name Attribute'), |
@@ -164,7 +171,9 b' class LdapSettingsSchema(AuthnPluginSett' | |||
|
164 | 171 | attr_email = colander.SchemaNode( |
|
165 | 172 | colander.String(), |
|
166 | 173 | default='', |
|
167 |
description=_('LDAP Attribute to map to email address' |
|
|
174 | description=_('LDAP Attribute to map to email address (e.g., mail).\n' | |
|
175 | 'Emails are a crucial part of RhodeCode. \n' | |
|
176 | 'If possible add a valid email attribute to ldap users.'), | |
|
168 | 177 | missing='', |
|
169 | 178 | preparer=strip_whitespace, |
|
170 | 179 | title=_('Email Attribute'), |
@@ -182,7 +191,7 b' class AuthLdap(object):' | |||
|
182 | 191 | def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='', |
|
183 | 192 | tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3, |
|
184 | 193 | search_scope='SUBTREE', attr_login='uid', |
|
185 | ldap_filter='(&(objectClass=user)(!(objectClass=computer)))'): | |
|
194 | ldap_filter=None): | |
|
186 | 195 | if ldap == Missing: |
|
187 | 196 | raise LdapImportError("Missing or incompatible ldap library") |
|
188 | 197 | |
@@ -236,14 +245,13 b' class AuthLdap(object):' | |||
|
236 | 245 | server.start_tls_s() |
|
237 | 246 | |
|
238 | 247 | if self.LDAP_BIND_DN and self.LDAP_BIND_PASS: |
|
239 | log.debug('Trying simple_bind with password and given DN: %s', | |
|
248 | log.debug('Trying simple_bind with password and given login DN: %s', | |
|
240 | 249 | self.LDAP_BIND_DN) |
|
241 | 250 | server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS) |
|
242 | 251 | |
|
243 | 252 | return server |
|
244 | 253 | |
|
245 | 254 | def get_uid(self, username): |
|
246 | from rhodecode.lib.helpers import chop_at | |
|
247 | 255 | uid = username |
|
248 | 256 | for server_addr in self.SERVER_ADDRESSES: |
|
249 | 257 | uid = chop_at(username, "@%s" % server_addr) |
@@ -292,8 +300,11 b' class AuthLdap(object):' | |||
|
292 | 300 | self.BASE_DN, self.SEARCH_SCOPE, filter_) |
|
293 | 301 | |
|
294 | 302 | if not lobjects: |
|
303 | log.debug("No matching LDAP objects for authentication " | |
|
304 | "of UID:'%s' username:(%s)", uid, username) | |
|
295 | 305 | raise ldap.NO_SUCH_OBJECT() |
|
296 | 306 | |
|
307 | log.debug('Found matching ldap object, trying to authenticate') | |
|
297 | 308 | for (dn, _attrs) in lobjects: |
|
298 | 309 | if dn is None: |
|
299 | 310 | continue |
@@ -304,15 +315,13 b' class AuthLdap(object):' | |||
|
304 | 315 | break |
|
305 | 316 | |
|
306 | 317 | else: |
|
307 | log.debug("No matching LDAP objects for authentication " | |
|
308 | "of '%s' (%s)", uid, username) | |
|
309 | 318 | raise LdapPasswordError('Failed to authenticate user ' |
|
310 | 319 | 'with given password') |
|
311 | 320 | |
|
312 | 321 | except ldap.NO_SUCH_OBJECT: |
|
313 | 322 | log.debug("LDAP says no such user '%s' (%s), org_exc:", |
|
314 | 323 | uid, username, exc_info=True) |
|
315 | raise LdapUsernameError() | |
|
324 | raise LdapUsernameError('Unable to find user') | |
|
316 | 325 | except ldap.SERVER_DOWN: |
|
317 | 326 | org_exc = traceback.format_exc() |
|
318 | 327 | raise LdapConnectionError( |
@@ -447,7 +456,7 b' class RhodeCodeAuthPlugin(RhodeCodeExter' | |||
|
447 | 456 | 'email': get_ldap_attr('attr_email') or email, |
|
448 | 457 | 'admin': admin, |
|
449 | 458 | 'active': active, |
|
450 |
|
|
|
459 | 'active_from_extern': None, | |
|
451 | 460 | 'extern_name': user_dn, |
|
452 | 461 | 'extern_type': extern_type, |
|
453 | 462 | } |
@@ -17,6 +17,7 b'' | |||
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | ||
|
20 | 21 | """ |
|
21 | 22 | RhodeCode authentication library for PAM |
|
22 | 23 | """ |
@@ -29,10 +30,9 b' import pwd' | |||
|
29 | 30 | import re |
|
30 | 31 | import socket |
|
31 | 32 | |
|
32 |
from |
|
|
33 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
34 | ||
|
35 | from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin | |
|
33 | from rhodecode.translation import _ | |
|
34 | from rhodecode.authentication.base import ( | |
|
35 | RhodeCodeExternalAuthPlugin, hybrid_property) | |
|
36 | 36 | from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase |
|
37 | 37 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
38 | 38 | from rhodecode.lib.colander_utils import strip_whitespace |
@@ -25,9 +25,8 b' RhodeCode authentication plugin for buil' | |||
|
25 | 25 | import logging |
|
26 | 26 | |
|
27 | 27 | from pylons.i18n.translation import lazy_ugettext as _ |
|
28 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
29 | 28 | |
|
30 | from rhodecode.authentication.base import RhodeCodeAuthPluginBase | |
|
29 | from rhodecode.authentication.base import RhodeCodeAuthPluginBase, hybrid_property | |
|
31 | 30 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
32 | 31 | from rhodecode.lib.utils2 import safe_str |
|
33 | 32 | from rhodecode.model.db import User |
@@ -24,10 +24,9 b' RhodeCode authentication token plugin fo' | |||
|
24 | 24 | |
|
25 | 25 | import logging |
|
26 | 26 | |
|
27 | from sqlalchemy.ext.hybrid import hybrid_property | |
|
28 | ||
|
29 | 27 | from rhodecode.translation import _ |
|
30 |
from rhodecode.authentication.base import |
|
|
28 | from rhodecode.authentication.base import ( | |
|
29 | RhodeCodeAuthPluginBase, VCS_TYPE, hybrid_property) | |
|
31 | 30 | from rhodecode.authentication.routes import AuthnPluginResourceBase |
|
32 | 31 | from rhodecode.model.db import User, UserApiKeys |
|
33 | 32 |
@@ -40,10 +40,11 b' class AuthnPluginSettingsSchemaBase(cola' | |||
|
40 | 40 | cache_ttl = colander.SchemaNode( |
|
41 | 41 | colander.Int(), |
|
42 | 42 | default=0, |
|
43 | description=_('Amount of seconds to cache the authentication ' | |
|
44 |
'call for this plugin. |
|
|
45 |
'LDAP to improve the |
|
|
46 |
'authentication system |
|
|
43 | description=_('Amount of seconds to cache the authentication response' | |
|
44 | 'call for this plugin. \n' | |
|
45 | 'Useful for long calls like LDAP to improve the ' | |
|
46 | 'performance of the authentication system ' | |
|
47 | '(0 means disabled).'), | |
|
47 | 48 | missing=0, |
|
48 | 49 | title=_('Auth Cache TTL'), |
|
49 | 50 | validator=colander.Range(min=0, max=None), |
@@ -57,7 +57,12 b' class RhodecodeEvent(object):' | |||
|
57 | 57 | def actor(self): |
|
58 | 58 | auth_user = self.auth_user |
|
59 | 59 | if auth_user: |
|
60 |
|
|
|
60 | instance = auth_user.get_instance() | |
|
61 | if not instance: | |
|
62 | return AttributeDict(dict( | |
|
63 | username=auth_user.username | |
|
64 | )) | |
|
65 | ||
|
61 | 66 | return SYSTEM_USER |
|
62 | 67 | |
|
63 | 68 | @property |
General Comments 0
You need to be logged in to leave comments.
Login now