auth: refactor code and simplified instructions.

- added new rfc selector
- cleanup imports
This commit is contained in:
Marcin Kuzminski 2017-02-21 18:05:29 +01:00
parent 8c73a665d3
commit 8ceda76718
12 changed files with 81 additions and 51 deletions

View file

@ -627,3 +627,21 @@ def authenticate(username, password, environ=None, auth_type=None,
log.debug("User `%s` failed to authenticate against %s",
display_user, plugin.get_id())
return None
def chop_at(s, sub, inclusive=False):
"""Truncate string ``s`` at the first occurrence of ``sub``.
If ``inclusive`` is true, truncate just after ``sub`` rather than at it.
>>> chop_at("plutocratic brats", "rat")
'plutoc'
>>> chop_at("plutocratic brats", "rat", True)
'plutocrat'
"""
pos = s.find(sub)
if pos == -1:
return s
if inclusive:
return s[:pos+len(sub)]
return s[:pos]

View file

@ -28,10 +28,9 @@ import base64
import logging
import urllib2
from pylons.i18n.translation import lazy_ugettext as _
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
from rhodecode.translation import _
from rhodecode.authentication.base import (
RhodeCodeExternalAuthPlugin, hybrid_property)
from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.colander_utils import strip_whitespace

View file

@ -21,15 +21,14 @@
import colander
import logging
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
from rhodecode.translation import _
from rhodecode.authentication.base import (
RhodeCodeExternalAuthPlugin, hybrid_property)
from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.colander_utils import strip_whitespace
from rhodecode.lib.utils2 import str2bool, safe_unicode
from rhodecode.model.db import User
from rhodecode.translation import _
log = logging.getLogger(__name__)

View file

@ -30,10 +30,9 @@ import rhodecode
import urllib
import urllib2
from pylons.i18n.translation import lazy_ugettext as _
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
from rhodecode.translation import _
from rhodecode.authentication.base import (
RhodeCodeExternalAuthPlugin, hybrid_property)
from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.colander_utils import strip_whitespace

View file

@ -27,10 +27,9 @@ import colander
import logging
import traceback
from pylons.i18n.translation import lazy_ugettext as _
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
from rhodecode.translation import _
from rhodecode.authentication.base import (
RhodeCodeExternalAuthPlugin, chop_at, hybrid_property)
from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.colander_utils import strip_whitespace
@ -72,14 +71,15 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
host = colander.SchemaNode(
colander.String(),
default='',
description=_('Host of the LDAP Server'),
description=_('Host of the LDAP Server \n'
'(e.g., 192.168.2.154, or ldap-server.domain.com'),
preparer=strip_whitespace,
title=_('LDAP Host'),
widget='string')
port = colander.SchemaNode(
colander.Int(),
default=389,
description=_('Port that the LDAP server is listening on'),
description=_('Custom port that the LDAP server is listening on. Default: 389'),
preparer=strip_whitespace,
title=_('Port'),
validator=colander.Range(min=0, max=65536),
@ -87,7 +87,9 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
dn_user = colander.SchemaNode(
colander.String(),
default='',
description=_('User to connect to LDAP'),
description=_('Optional user DN/account to connect to LDAP if authentication is required. \n'
'e.g., cn=admin,dc=mydomain,dc=com, or '
'uid=root,cn=users,dc=mydomain,dc=com, or admin@mydomain.com'),
missing='',
preparer=strip_whitespace,
title=_('Account'),
@ -95,7 +97,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
dn_pass = colander.SchemaNode(
colander.String(),
default='',
description=_('Password to connect to LDAP'),
description=_('Password to authenticate for given user DN.'),
missing='',
preparer=strip_whitespace,
title=_('Password'),
@ -117,7 +119,9 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
base_dn = colander.SchemaNode(
colander.String(),
default='',
description=_('Base DN to search (e.g., dc=mydomain,dc=com)'),
description=_('Base DN to search. Dynamic bind is supported. Add `$login` marker '
'in it to be replaced with current user credentials \n'
'(e.g., dc=mydomain,dc=com, or ou=Users,dc=mydomain,dc=com)'),
missing='',
preparer=strip_whitespace,
title=_('Base DN'),
@ -125,22 +129,25 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
filter = colander.SchemaNode(
colander.String(),
default='',
description=_('Filter to narrow results (e.g., ou=Users, etc)'),
description=_('Filter to narrow results \n'
'(e.g., (&(objectCategory=Person)(objectClass=user)), or \n'
'(memberof=cn=rc-login,ou=groups,ou=company,dc=mydomain,dc=com)))'),
missing='',
preparer=strip_whitespace,
title=_('LDAP Search Filter'),
widget='string')
search_scope = colander.SchemaNode(
colander.String(),
default=search_scope_choices[0],
description=_('How deep to search LDAP'),
default=search_scope_choices[2],
description=_('How deep to search LDAP. If unsure set to SUBTREE'),
title=_('LDAP Search Scope'),
validator=colander.OneOf(search_scope_choices),
widget='select')
attr_login = colander.SchemaNode(
colander.String(),
default='',
description=_('LDAP Attribute to map to user name'),
default='uid',
description=_('LDAP Attribute to map to user name (e.g., uid, or sAMAccountName)'),
preparer=strip_whitespace,
title=_('Login Attribute'),
missing_msg=_('The LDAP Login attribute of the CN must be specified'),
@ -148,7 +155,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
attr_firstname = colander.SchemaNode(
colander.String(),
default='',
description=_('LDAP Attribute to map to first name'),
description=_('LDAP Attribute to map to first name (e.g., givenName)'),
missing='',
preparer=strip_whitespace,
title=_('First Name Attribute'),
@ -156,7 +163,7 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
attr_lastname = colander.SchemaNode(
colander.String(),
default='',
description=_('LDAP Attribute to map to last name'),
description=_('LDAP Attribute to map to last name (e.g., sn)'),
missing='',
preparer=strip_whitespace,
title=_('Last Name Attribute'),
@ -164,7 +171,9 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
attr_email = colander.SchemaNode(
colander.String(),
default='',
description=_('LDAP Attribute to map to email address'),
description=_('LDAP Attribute to map to email address (e.g., mail).\n'
'Emails are a crucial part of RhodeCode. \n'
'If possible add a valid email attribute to ldap users.'),
missing='',
preparer=strip_whitespace,
title=_('Email Attribute'),
@ -182,7 +191,7 @@ class AuthLdap(object):
def __init__(self, server, base_dn, port=389, bind_dn='', bind_pass='',
tls_kind='PLAIN', tls_reqcert='DEMAND', ldap_version=3,
search_scope='SUBTREE', attr_login='uid',
ldap_filter='(&(objectClass=user)(!(objectClass=computer)))'):
ldap_filter=None):
if ldap == Missing:
raise LdapImportError("Missing or incompatible ldap library")
@ -236,14 +245,13 @@ class AuthLdap(object):
server.start_tls_s()
if self.LDAP_BIND_DN and self.LDAP_BIND_PASS:
log.debug('Trying simple_bind with password and given DN: %s',
log.debug('Trying simple_bind with password and given login DN: %s',
self.LDAP_BIND_DN)
server.simple_bind_s(self.LDAP_BIND_DN, self.LDAP_BIND_PASS)
return server
def get_uid(self, username):
from rhodecode.lib.helpers import chop_at
uid = username
for server_addr in self.SERVER_ADDRESSES:
uid = chop_at(username, "@%s" % server_addr)
@ -292,8 +300,11 @@ class AuthLdap(object):
self.BASE_DN, self.SEARCH_SCOPE, filter_)
if not lobjects:
log.debug("No matching LDAP objects for authentication "
"of UID:'%s' username:(%s)", uid, username)
raise ldap.NO_SUCH_OBJECT()
log.debug('Found matching ldap object, trying to authenticate')
for (dn, _attrs) in lobjects:
if dn is None:
continue
@ -304,15 +315,13 @@ class AuthLdap(object):
break
else:
log.debug("No matching LDAP objects for authentication "
"of '%s' (%s)", uid, username)
raise LdapPasswordError('Failed to authenticate user '
'with given password')
except ldap.NO_SUCH_OBJECT:
log.debug("LDAP says no such user '%s' (%s), org_exc:",
uid, username, exc_info=True)
raise LdapUsernameError()
raise LdapUsernameError('Unable to find user')
except ldap.SERVER_DOWN:
org_exc = traceback.format_exc()
raise LdapConnectionError(
@ -447,7 +456,7 @@ class RhodeCodeAuthPlugin(RhodeCodeExternalAuthPlugin):
'email': get_ldap_attr('attr_email') or email,
'admin': admin,
'active': active,
"active_from_extern": None,
'active_from_extern': None,
'extern_name': user_dn,
'extern_type': extern_type,
}

View file

@ -17,6 +17,7 @@
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
RhodeCode authentication library for PAM
"""
@ -29,10 +30,9 @@ import pwd
import re
import socket
from pylons.i18n.translation import lazy_ugettext as _
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeExternalAuthPlugin
from rhodecode.translation import _
from rhodecode.authentication.base import (
RhodeCodeExternalAuthPlugin, hybrid_property)
from rhodecode.authentication.schema import AuthnPluginSettingsSchemaBase
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.colander_utils import strip_whitespace

View file

@ -25,9 +25,8 @@ RhodeCode authentication plugin for built in internal auth
import logging
from pylons.i18n.translation import lazy_ugettext as _
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.authentication.base import RhodeCodeAuthPluginBase
from rhodecode.authentication.base import RhodeCodeAuthPluginBase, hybrid_property
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.lib.utils2 import safe_str
from rhodecode.model.db import User

View file

@ -24,10 +24,9 @@ RhodeCode authentication token plugin for built in internal auth
import logging
from sqlalchemy.ext.hybrid import hybrid_property
from rhodecode.translation import _
from rhodecode.authentication.base import RhodeCodeAuthPluginBase, VCS_TYPE
from rhodecode.authentication.base import (
RhodeCodeAuthPluginBase, VCS_TYPE, hybrid_property)
from rhodecode.authentication.routes import AuthnPluginResourceBase
from rhodecode.model.db import User, UserApiKeys

View file

@ -40,10 +40,11 @@ class AuthnPluginSettingsSchemaBase(colander.MappingSchema):
cache_ttl = colander.SchemaNode(
colander.Int(),
default=0,
description=_('Amount of seconds to cache the authentication '
'call for this plugin. Useful for long calls like '
'LDAP to improve the responsiveness of the '
'authentication system (0 means disabled).'),
description=_('Amount of seconds to cache the authentication response'
'call for this plugin. \n'
'Useful for long calls like LDAP to improve the '
'performance of the authentication system '
'(0 means disabled).'),
missing=0,
title=_('Auth Cache TTL'),
validator=colander.Range(min=0, max=None),

View file

@ -57,7 +57,12 @@ class RhodecodeEvent(object):
def actor(self):
auth_user = self.auth_user
if auth_user:
return auth_user.get_instance()
instance = auth_user.get_instance()
if not instance:
return AttributeDict(dict(
username=auth_user.username
))
return SYSTEM_USER
@property

View file

@ -61,6 +61,7 @@
.help-block {
display: block;
margin-left: @label-width;
white-space: pre;
}
.action_button {
@ -116,7 +117,7 @@
float: none;
margin-left: @label-width;
.help-block{
.help-block {
margin-left: 0;
}
}

View file

@ -111,6 +111,7 @@ $(document).ready(function() {
$("#tls_kind").select2(select2Options);
$("#tls_reqcert").select2(select2Options);
$("#search_scope").select2(select2Options);
$("#group_extraction_type").select2(select2Options);
});
</script>
</%def>