List of contributors to RhodeCode project:
Marcin Kuźmiński <marcin@python-works.com>
Lukasz Balcerzak <lukaszbalcerzak@gmail.com>
Jason Harris <jason@jasonfharris.com>
Thayne Harbaugh <thayne@fusionio.com>
cejones
Lorenzo M. Catucci <lorenzo@sancho.ccd.uniroma2.it>
Dmitri Kuznetsov
Jared Bunting <jared.bunting@peachjean.com>
\ No newline at end of file
Steve Romanow <slestak989@gmail.com>
# -*- coding: utf-8 -*-
"""
rhodecode.lib.auth
~~~~~~~~~~~~~~~~~~
authentication and permission libraries
:created_on: Apr 4, 2010
:copyright: (c) 2010 by marcink.
:license: LICENSE_NAME, see LICENSE_FILE for more details.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import random
import logging
import traceback
import hashlib
from tempfile import _RandomNameSequence
from decorator import decorator
from pylons import config, session, url, request
from pylons.controllers.util import abort, redirect
from pylons.i18n.translation import _
from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
if __platform__ in PLATFORM_WIN:
from hashlib import sha256
if __platform__ in PLATFORM_OTHERS:
import bcrypt
from rhodecode.lib import str2bool
from rhodecode.lib import str2bool, safe_unicode
from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
from rhodecode.lib.utils import get_repo_slug
from rhodecode.lib.auth_ldap import AuthLdap
from rhodecode.model import meta
from rhodecode.model.user import UserModel
from rhodecode.model.db import Permission, RhodeCodeSettings
log = logging.getLogger(__name__)
class PasswordGenerator(object):
"""This is a simple class for generating password from
different sets of characters
usage:
passwd_gen = PasswordGenerator()
#print 8-letter password containing only big and small letters
of alphabet
print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
ALPHABETS_NUM = r'''1234567890'''
ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
+ ALPHABETS_NUM + ALPHABETS_SPECIAL
ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
def __init__(self, passwd=''):
self.passwd = passwd
def gen_password(self, len, type):
self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
return self.passwd
class RhodeCodeCrypto(object):
@classmethod
def hash_string(cls, str_):
Cryptographic function used for password hashing based on pybcrypt
or pycrypto in windows
:param password: password to hash
@@ -162,100 +162,100 @@ def authenticate(username, password):
return True
elif user.username == username and check_password(password,
user.password):
log.info('user %s authenticated correctly', username)
else:
log.warning('user %s is disabled', username)
log.debug('Regular authentication failed')
user_obj = user_model.get_by_username(username, cache=False,
case_insensitive=True)
if user_obj is not None and not user_obj.ldap_dn:
log.debug('this user already exists as non ldap')
return False
ldap_settings = RhodeCodeSettings.get_ldap_settings()
#======================================================================
# FALLBACK TO LDAP AUTH IF ENABLE
if str2bool(ldap_settings.get('ldap_active')):
log.debug("Authenticating user using ldap")
kwargs = {
'server': ldap_settings.get('ldap_host', ''),
'base_dn': ldap_settings.get('ldap_base_dn', ''),
'port': ldap_settings.get('ldap_port'),
'bind_dn': ldap_settings.get('ldap_dn_user'),
'bind_pass': ldap_settings.get('ldap_dn_pass'),
'tls_kind': ldap_settings.get('ldap_tls_kind'),
'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
'ldap_filter': ldap_settings.get('ldap_filter'),
'search_scope': ldap_settings.get('ldap_search_scope'),
'attr_login': ldap_settings.get('ldap_attr_login'),
'ldap_version': 3,
}
log.debug('Checking for ldap authentication')
try:
aldap = AuthLdap(**kwargs)
(user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
password)
log.debug('Got ldap DN response %s', user_dn)
get_ldap_attr = lambda k: ldap_attrs.get(ldap_settings\
.get(k), [''])[0]
user_attrs = {
'name': get_ldap_attr('ldap_attr_firstname'),
'lastname': get_ldap_attr('ldap_attr_lastname'),
'email': get_ldap_attr('ldap_attr_email'),
'name': safe_unicode(get_ldap_attr('ldap_attr_firstname')),
'lastname': safe_unicode(get_ldap_attr('ldap_attr_lastname')),
if user_model.create_ldap(username, password, user_dn,
user_attrs):
log.info('created new ldap user %s', username)
except (LdapUsernameError, LdapPasswordError,):
pass
except (Exception,):
log.error(traceback.format_exc())
class AuthUser(object):
A simple object that handles all attributes of user in RhodeCode
It does lookup based on API key,given user, or user present in session
Then it fills all required information for such user. It also checks if
anonymous access is enabled and if so, it returns default user as logged
in
def __init__(self, user_id=None, api_key=None):
self.user_id = user_id
self.api_key = None
self.username = 'None'
self.name = ''
self.lastname = ''
self.email = ''
self.is_authenticated = False
self.admin = False
self.permissions = {}
self._api_key = api_key
self.propagate_data()
def propagate_data(self):
user_model = UserModel()
self.anonymous_user = user_model.get_by_username('default', cache=True)
if self._api_key and self._api_key != self.anonymous_user.api_key:
#try go get user by api key
log.debug('Auth User lookup by API KEY %s', self._api_key)
user_model.fill_data(self, api_key=self._api_key)
log.debug('Auth User lookup by USER ID %s', self.user_id)
from rhodecode.tests import *
from rhodecode.model.db import RhodeCodeSettings
import ldap
except ImportError:
# means that python-ldap is not installed
class TestLdapSettingsController(TestController):
def test_index(self):
self.log_user()
response = self.app.get(url(controller='admin/ldap_settings',
action='index'))
# Test response...
self.assertTrue('LDAP administration' in response.body)
def test_ldap_save_settings(self):
test_url = url(controller='admin/ldap_settings',
action='ldap_settings')
response = self.app.post(url=test_url,
params={'ldap_host' : u'dc.example.com',
'ldap_port' : '999',
'ldap_tls_kind' : 'PLAIN',
'ldap_tls_reqcert' : 'NEVER',
'ldap_dn_user':'test_user',
'ldap_dn_pass':'test_pass',
'ldap_base_dn':'test_base_dn',
'ldap_filter':'test_filter',
'ldap_search_scope':'BASE',
'ldap_attr_login':'test_attr_login',
'ldap_attr_firstname':'ima',
'ldap_attr_lastname':'tester',
'ldap_attr_email':'test@example.com' })
new_settings = RhodeCodeSettings.get_ldap_settings()
self.assertEqual(new_settings['ldap_host'], u'dc.example.com',
'fail db write compare')
self.checkSessionFlash(response,
'Ldap settings updated successfully')
def test_ldap_error_form(self):
params={'ldap_host' : '',
'ldap_port' : 'i-should-be-number',
'ldap_dn_user':'',
'ldap_dn_pass':'',
'ldap_base_dn':'',
'ldap_filter':'',
'ldap_attr_login':'', # <----- missing required input
'ldap_attr_firstname':'',
'ldap_attr_lastname':'',
'ldap_attr_email':'' })
self.assertTrue("""<span class="error-message">The LDAP Login"""
""" attribute of the CN must be specified""" in
response.body)
self.assertTrue("""<span class="error-message">Please """
"""enter a number</span>""" in response.body)
def test_ldap_login(self):
def test_ldap_login_incorrect(self):
Status change: