@@ -104,25 +104,29 @@ Here's a typical ldap setup::
Enable ldap = checked #controls if ldap access is enabled
Host = host.domain.org #actual ldap server to connect
Port = 389 or 689 for ldaps #ldap server ports
Enable LDAPS = unchecked #enable disable ldaps
Account = <account> #access for ldap server(if required)
Password = <password> #password for ldap server(if required)
Base DN = uid=%(user)s,CN=users,DC=host,DC=domain,DC=org
`Account` and `Password` are optional, and used for two-phase ldap
authentication so those are credentials to access Your ldap, if it doesn't
support anonymous search/user lookups.
Base DN must have %(user)s template inside, it's a placer where Your uid used
to login would go, it allows admins to specify not standard schema for uid
variable
If all data are entered correctly, and `python-ldap` is properly installed
Users should be granted to access RhodeCode wit ldap accounts. When
logging at the first time an special ldap account is created inside RhodeCode,
so You can control over permissions even on ldap users. If such user exists
already in RhodeCode database ldap user with the same username would be not
able to access RhodeCode.
If You have problems with ldap access and believe You entered correct
information check out the RhodeCode logs,any error messages sent from
ldap will be saved there.
@@ -46,58 +46,58 @@ class AuthLdap(object):
#USE FOR READ ONLY BIND TO LDAP SERVER
self.LDAP_BIND_DN = bind_dn
self.LDAP_BIND_PASS = bind_pass
ldap_server_type = 'ldap'
if self.LDAP_USE_LDAPS:ldap_server_type = ldap_server_type + 's'
self.LDAP_SERVER = "%s://%s:%s" % (ldap_server_type,
self.LDAP_SERVER_ADDRESS,
self.LDAP_SERVER_PORT)
self.BASE_DN = base_dn
self.AUTH_DN = "uid=%s,%s"
def authenticate_ldap(self, username, password):
"""Authenticate a user via LDAP and return his/her LDAP properties.
Raises AuthenticationError if the credentials are rejected, or
EnvironmentError if the LDAP server can't be reached.
:param username: username
:param password: password
"""
from rhodecode.lib.helpers import chop_at
uid = chop_at(username, "@%s" % self.LDAP_SERVER_ADDRESS)
dn = self.AUTH_DN % (uid, self.BASE_DN)
log.debug("Authenticating %r at %s", dn, self.LDAP_SERVER)
if "," in username:
raise LdapUsernameError("invalid character in username: ,")
try:
ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, '/etc/openldap/cacerts')
ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, 10)
server = ldap.initialize(self.LDAP_SERVER)
if self.ldap_version == 2:
server.protocol = ldap.VERSION2
else:
server.protocol = ldap.VERSION3
if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
server.simple_bind_s(self.AUTH_DN % (self.LDAP_BIND_DN,
self.BASE_DN),
self.LDAP_BIND_PASS)
login_dn = self.BASE_DN % {'user':uid}
server.simple_bind_s(login_dn, self.LDAP_BIND_PASS)
dn = self.BASE_DN % {'user':uid}
server.simple_bind_s(dn, password)
properties = server.search_s(dn, ldap.SCOPE_SUBTREE)
if not properties:
raise ldap.NO_SUCH_OBJECT()
except ldap.NO_SUCH_OBJECT, e:
log.debug("LDAP says no such user '%s' (%s)", uid, username)
raise LdapUsernameError()
except ldap.INVALID_CREDENTIALS, e:
log.debug("LDAP rejected password for user '%s' (%s)", uid, username)
raise LdapPasswordError()
except ldap.SERVER_DOWN, e:
raise LdapConnectionError("LDAP can't access authentication server")
@@ -291,24 +291,44 @@ class ValidSystemEmail(formencode.valida
return value
class LdapLibValidator(formencode.validators.FancyValidator):
def to_python(self, value, state):
import ldap
except ImportError:
raise LdapImportError
class BaseDnValidator(formencode.validators.FancyValidator):
value % {'user':'valid'}
if value.find('%(user)s') == -1:
raise formencode.Invalid(_("You need to specify %(user)s in "
"template for example uid=%(user)s "
",dc=company...") ,
value, state)
except KeyError:
raise formencode.Invalid(_("Wrong template used, only %(user)s "
"is an valid entry") ,
#===============================================================================
# FORMS
class LoginForm(formencode.Schema):
allow_extra_fields = True
filter_extra_fields = True
username = UnicodeString(
strip=True,
min=1,
not_empty=True,
messages={
'empty':_('Please enter a login'),
@@ -448,15 +468,15 @@ def DefaultPermissionsForm(perms_choices
def LdapSettingsForm():
class _LdapSettingsForm(formencode.Schema):
pre_validators = [LdapLibValidator]
ldap_active = StringBoolean(if_missing=False)
ldap_host = UnicodeString(strip=True,)
ldap_port = Number(strip=True,)
ldap_ldaps = StringBoolean(if_missing=False)
ldap_dn_user = UnicodeString(strip=True,)
ldap_dn_pass = UnicodeString(strip=True,)
ldap_base_dn = UnicodeString(strip=True,)
ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
return _LdapSettingsForm
from rhodecode import get_version
import sys
py_version = sys.version_info
requirements = [
"Pylons>=1.0.0",
"SQLAlchemy>=0.6.5",
"Mako>=0.3.6",
"vcs>=0.1.10",
"pygments>=1.3.0",
"mercurial>=1.7.1",
"whoosh>=1.3.1",
"whoosh==1.3.1",
"celery>=2.1.3",
"py-bcrypt",
"babel",
]
classifiers = ['Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Framework :: Pylons',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python', ]
@@ -84,15 +85,19 @@ setup(
zip_safe=False,
paster_plugins=['PasteScript', 'Pylons'],
entry_points="""
[paste.app_factory]
main = rhodecode.config.middleware:make_app
[paste.app_install]
main = pylons.util:PylonsInstaller
[paste.global_paster_command]
make-index = rhodecode.lib.indexers:MakeIndex
upgrade-db = rhodecode.lib.utils:UpgradeDb
celeryd=rhodecode.lib.celerypylons.commands:CeleryDaemonCommand
celerybeat=rhodecode.lib.celerypylons.commands:CeleryBeatCommand
camqadm=rhodecode.lib.celerypylons.commands:CAMQPAdminCommand
celeryev=rhodecode.lib.celerypylons.commands:CeleryEventCommand
""",
)
Status change: