Example #1
0
 def test_extract_username(self):
     self.assertEquals(extract_username('username'), 'username')
     self.assertEquals(extract_username('*****@*****.**'),
                       'u2wqblarhim5su7pxemcbwdyryrghmuk')
     # test for non A-Za-z0-9._- with no @
     self.assertRaises(ValueError, extract_username, 'user\r\nname')
     self.assertRaises(ValueError, extract_username, '%3Cscript%3E')
     self.assertRaises(ValueError, extract_username, '')
     # test unicode/punycode (straight UTF8 and urlencoded)
     self.assertEquals(extract_username('*****@*****.**'),
                       'ym3nccfhvptfrhn7nkhhyvzgf2yl7r5y')  # proper char
     self.assertRaises(UnicodeError, extract_username,
                       '*****@*****.**')        # bad utf-8 char
     self.assertRaises(UnicodeError, extract_username,
                       '*****@*****.**')      # invalid BIDI
Example #2
0
    def setUp(self):
        # loading the app
        self.appdir, self.config, self.auth = initenv()
        self.app = TestApp(make_app(self.config))

        # adding a user if needed
        self.email = '*****@*****.**' % random.randint(1, 1000)
        self.user_name = extract_username(self.email)
        self.user = User(self.user_name)
        self.user_id = self.auth.get_user_id(self.user)
        self.password = '******' * 9

        if self.user_id is None:
            self.auth.create_user(self.user_name, self.password, self.email)
            self.user_id = self.auth.get_user_id(self.user)

        # for the ldap backend, filling available_nodes
        if self.auth.__class__.__name__ == 'LDAPAuth':
            query = ('insert into available_nodes (node, ct, actives) values '
                     ' ("weave:localhost", 10, 10)')
            self.auth._engine.execute(query)

        try:
            self.nodes = load_and_configure(self.config, 'nodes')
        except KeyError:
            logger.debug(traceback.format_exc())
            logger.debug("No node library in place")
            self.nodes = None

        try:
            self.reset = load_and_configure(self.config, 'reset_codes')
        except Exception:
            logger.debug(traceback.format_exc())
            logger.debug("No reset code library in place")
            self.reset = None
Example #3
0
    def setUp(self):
        # loading the app
        self.appdir, self.config, self.auth = initenv()
        self.app = TestApp(make_app(self.config))

        # adding a user if needed
        self.email = '*****@*****.**' % random.randint(1, 1000)
        self.user_name = extract_username(self.email)
        self.user = User(self.user_name)
        self.user_id = self.auth.get_user_id(self.user)
        self.password = '******' * 9

        if self.user_id is None:
            self.auth.create_user(self.user_name, self.password, self.email)
            self.user_id = self.auth.get_user_id(self.user)

        # for the ldap backend, filling available_nodes
        if self.auth.__class__.__name__ == 'LDAPAuth':
            query = ('insert into available_nodes (node, ct, actives) values '
                     ' ("weave:localhost", 10, 10)')
            self.auth._engine.execute(query)

        try:
            self.nodes = load_and_configure(self.config, 'nodes')
        except KeyError:
            logger.debug(traceback.format_exc())
            logger.debug("No node library in place")
            self.nodes = None

        try:
            self.reset = load_and_configure(self.config, 'reset_codes')
        except Exception:
            logger.debug(traceback.format_exc())
            logger.debug("No reset code library in place")
            self.reset = None
Example #4
0
    def test_reset_email(self):
        app = get_app(self.app)
        # let's ask via the web form now
        # the Python web form does not support captcha
        old = app.config['captcha.use']
        app.config['captcha.use'] = False
        try:
            # let's try the reset process with an email
            user_name = extract_username('*****@*****.**')
            self.auth.create_user(user_name, self.password,
                                  '*****@*****.**')

            res = self.app.get('/weave-password-reset')
            res.form['username'].value = '*****@*****.**'
            res = res.form.submit()
            self.assertTrue('next 6 hours' in res)
            self.assertEquals(len(FakeSMTP.msgs), 1)

            # let's visit the link in the email
            msg = message_from_string(FakeSMTP.msgs[0][2]).get_payload()
            msg = base64.decodestring(msg)
            link = msg.split('\n')[2].strip()

            # let's call the real link, it's a form we can fill
            res = self.app.get(link)
            res.form['password'].value = 'mynewpassword'
            res.form['confirm'].value = 'mynewpassword'
            res = res.form.submit()
            self.assertTrue('Password successfully changed' in res)
        finally:
            app.config['captcha.use'] = old
Example #5
0
    def test_delete_user(self):
        # creating another user
        email = '*****@*****.**'
        user = extract_username(email)
        root = '/user/1.0/%s' % user

        res = self.app.get(root)
        if not json.loads(res.body):
            payload = {'email': '*****@*****.**',
                       'password': '******' * 9,
                       'captcha-challenge': 'xxx',
                       'captcha-response': 'xxx'}
            payload = json.dumps(payload)
            self.app.put(root, params=payload)

        # trying to suppress the old user with the new user
        # this should generate a 401
        environ = {'HTTP_AUTHORIZATION': 'Basic %s' % \
                    base64.encodestring('%s:xxxxxxxxx' % user)}
        self.app.extra_environ = environ
        self.app.delete(self.root, status=401)

        # now using the right credentials
        token = base64.encodestring('%s:%s' % (self.user_name, self.password))
        environ = {'HTTP_AUTHORIZATION': 'Basic %s' % token}
        self.app.extra_environ = environ
        res = self.app.delete(self.root)
        self.assertTrue(json.loads(res.body))

        # tarek should be gone
        res = self.app.get(self.root)
        self.assertFalse(json.loads(res.body))
Example #6
0
    def test_create_user(self):
        # creating a user
        email = '*****@*****.**' % (time.time(),
                                           random.randint(1, 100))
        name = extract_username(email)
        user_url = '/user/1.0/%s' % name

        try:
            # the user already exists
            payload = {'email': email, 'password': '******' * 9}
            payload = json.dumps(payload)
            res = self.app.put(self.root, params=payload, status=400)
            self.assertEquals(res.json, ERROR_INVALID_WRITE)

            # missing the password
            payload = {'email': email}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, status=400)
            self.assertEquals(res.json, ERROR_MISSING_PASSWORD)

            # malformed e-mail
            payload = {'email': 'bademailhere', 'password': '******' * 9}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, status=400)
            self.assertEquals(res.json, ERROR_NO_EMAIL_ADDRESS)

            # weak password
            payload = {'email': email, 'password': '******'}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, status=400)
            self.assertEquals(res.json, ERROR_WEAK_PASSWORD)

            # weak password #2
            payload = {'email': email, 'password': '******'}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, status=400)
            self.assertEquals(res.json, ERROR_WEAK_PASSWORD)

            # the user name does not match the email
            payload = {'email': '*****@*****.**', 'password': '******' * 9}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, status=400)
            self.assertEquals(res.json, ERROR_USERNAME_EMAIL_MISMATCH)

            # everything is there
            res = self.app.get(user_url)
            self.assertFalse(json.loads(res.body))
            payload = {'email': email, 'password': '******' * 9,
                       'captcha-challenge': 'xxx', 'captcha-response': 'xxx'}

            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload)
            self.assertEquals(res.body, name)

            res = self.app.get(user_url)
            self.assertTrue(json.loads(res.body))
        finally:
            self.auth.delete_user(User(name), 'x' * 9)
Example #7
0
def change_email(request, **args):
    """The form and process for changing your email address.
    Not supported yet"""

    auth = request.registry["auth"]
    data = {}
    data['trail'] = [[None, _('Change Account Name')]]
    data['email'] = request.session.get('email')
    new_email = request.params.get('new_email')

    if not new_email or not check_crumb(request):
        data['crumb'] = generate_crumb(request)
        return data

    data['crumb'] = generate_crumb(request)
    if not valid_email(new_email):
        request.errors.append(_('The email address appears invalid.'))
        return data

    #because changing the email now changes the username, we need to check
    #for collisions - NOT YET
    new_username = extract_username(new_email)
    if auth.get_user_id(new_username):
        request.errors.append(
                    _('The email address you specified is already in use.'))
        return data

    if auth.update_field(request.user,
                              request.session.get('password'),
                              'mail', new_email):
        #auth.update_field(request.user,
        #                       request.session.get('password'),
        #                       'uid', extract_username(new_email)):
        data['success'] = \
          _('Your account name was succesfully changed to %s.' % new_email)
        #make sure to change our session to have the new email
        request.session['email'] = new_email
        #request.session['username'] = extract_username(new_email)
        request.session.save()
        data['email'] = new_email
        #data['username'] = new_email
    else:
        request.errors.append(
                    _('An unknown problem ocurred. Please try again later.'))

    return data
Example #8
0
def forgot_step_4(request, **args):
    """Final step. reset their password, clear their reset code, and let
    them know that we're done.
    """
    data = {}
    username = extract_username(request.params.get('key_username'))
    request.user['username'] = username

    #verify that password and confirm match
    password = request.params.get('new_password')
    confirm = request.params.get('confirm_password')
    if password != confirm:
        request.errors.append(_('The new password and confirmation do '
                                'not match. Please try again.'))
        return render_to_response('console/password_reset3.mako',
                                  forgot_step_3(request), request)

    if not valid_password(username, password):
        request.errors.append(_('The new password is not valid. '
                                'Please try again.'))
        return render_to_response('console/password_reset3.mako',
                                  forgot_step_3(request), request)

    try:
        auth = request.registry["auth"]
        reset = request.registry.settings.get('app.console.reset')
        if not auth.admin_update_password(request.user,
                                             password, request.params['key']):
            request.errors.append(_('Changing the password failed. '
                         'Please ask for a new key and try again later'))
            return data
    except InvalidCodeError:
            request.errors.append(_('The reset code you submitted was '
                              'invalid. Please request a new one.'))
            return render_to_response('console/password_reset2.mako',
                                      forgot_step_1(request), request)

    log_cef('Password Changed', 5,
            request.environ,
            request.registry.settings.get('config').get_map(),
            username, signature="PasswordReset")
    reset.clear_reset_code(request.user)
    return data
Example #9
0
    def test_non_ascii_password(self):
        # creating a user
        email = '*****@*****.**' % (time.time(), random.randint(1, 100))
        user = extract_username(email)
        password = u'\xe9' * 9
        user_url = '/user/1.0/%s' % user

        payload = {'email': email, 'password': password,
                   'captcha-challenge': 'xxx',
                   'captcha-response': 'xxx'}
        payload = json.dumps(payload)
        res = self.app.put(user_url, params=payload)
        self.assertEquals(res.body, user)

        token = base64.encodestring('%s:%s' % (user, password.encode('utf8')))
        environ = {'HTTP_AUTHORIZATION': 'Basic %s' % token}
        self.app.extra_environ = environ
        self.app.delete(user_url)

        res = self.app.get(user_url)
        self.assertFalse(json.loads(res.body))
    def do_password_reset(self, request):
        """Do a password reset."""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        user_name = request.POST.get('username')
        if user_name is not None:
            user_name = extract_username(user_name)

        if request.POST.keys() == ['username']:
            # setting up a password reset
            # XXX add support for captcha here via **data
            request.user = User(user_name)
            try:
                self.password_reset(request)
            except (HTTPServiceUnavailable, HTTPJsonBadRequest), e:
                return render_mako('password_failure.mako', error=e.detail)
            else:
                return render_mako('password_key_sent.mako')

            raise HTTPJsonBadRequest()
Example #11
0
def forgot_step_3(request, **args):
    """Accessed by the direct email link, we check their key and give them a
    chance to change their password.
    """
    data = {}
    auth = request.registry["auth"]
    username = extract_username(request.params.get('username'))
    request.user['username'] = username
    data['key'] = request.params['key']
    data['usernm'] = username  #needs to be different from the session username

    #validate the access code
    #NOTE: sreg automatically returns true here, and defers code validation
    #until later
    user_id = auth.get_user_id(request.user)
    reset = request.registry.settings.get('app.console.reset')
    if not reset.verify_reset_code(request.user, data['key']):
        request.errors.append(_('The reset code you submitted was '
                                'invalid. Please request a new one.'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)
    return data
Example #12
0
    def do_password_reset(self, request):
        """Do a password reset."""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        user_name = request.POST.get('username')
        if user_name is not None:
            user_name = extract_username(user_name)

        if request.POST.keys() == ['username']:
            # setting up a password reset
            # XXX add support for captcha here via **data
            request.user = User(user_name)
            try:
                self.password_reset(request)
            except (HTTPServiceUnavailable, HTTPJsonBadRequest), e:
                return render_mako('password_failure.mako', error=e.detail)
            else:
                return render_mako('password_key_sent.mako')

            raise HTTPJsonBadRequest()
Example #13
0
    def create_user(self, request):
        """Creates a user."""
        if self.auth.get_user_id(request.user):
            raise HTTPJsonBadRequest(ERROR_INVALID_WRITE)
        username = request.user['username']

        try:
            data = json.loads(request.body)
        except ValueError:
            raise HTTPJsonBadRequest(ERROR_MALFORMED_JSON)

        email = data.get('email')
        if email and not valid_email(email):
            raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS)

        # checking that the e-mail matches the username
        munged_email = extract_username(email)
        if munged_email != username and self.strict_usernames:
            raise HTTPJsonBadRequest(ERROR_USERNAME_EMAIL_MISMATCH)

        password = data.get('password')
        if not password:
            raise HTTPJsonBadRequest(ERROR_MISSING_PASSWORD)

        if not valid_password(username, password):
            raise HTTPJsonBadRequest(ERROR_WEAK_PASSWORD)

        # check if captcha info are provided or if we bypass it
        if (self.shared_secret is None or
            request.headers.get('X-Weave-Secret') != self.shared_secret):
            self._check_captcha(request, data)

        # all looks good, let's create the user
        if not self.auth.create_user(request.user['username'], password,
                                     email):
            raise HTTPInternalServerError('User creation failed.')

        return request.user['username']
    def create_user(self, request):
        """Creates a user."""
        if self.auth.get_user_id(request.user):
            raise HTTPJsonBadRequest(ERROR_INVALID_WRITE)
        username = request.user['username']

        try:
            data = json.loads(request.body)
        except ValueError:
            raise HTTPJsonBadRequest(ERROR_MALFORMED_JSON)

        email = data.get('email')
        if email and not valid_email(email):
            raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS)

        # checking that the e-mail matches the username
        munged_email = extract_username(email)
        if munged_email != username and self.strict_usernames:
            raise HTTPJsonBadRequest(ERROR_USERNAME_EMAIL_MISMATCH)

        password = data.get('password')
        if not password:
            raise HTTPJsonBadRequest(ERROR_MISSING_PASSWORD)

        if not valid_password(username, password):
            raise HTTPJsonBadRequest(ERROR_WEAK_PASSWORD)

        # check if captcha info are provided or if we bypass it
        if (self.shared_secret is None or
                request.headers.get('X-Weave-Secret') != self.shared_secret):
            self._check_captcha(request, data)

        # all looks good, let's create the user
        if not self.auth.create_user(request.user['username'], password,
                                     email):
            raise HTTPInternalServerError('User creation failed.')

        return request.user['username']
    def authenticate(self, environ, identity):
        # Normalize the username for our backend.
        # Some repoze.who plugins use "login" instead of "username".
        username = identity.get("username")
        if username is None:
            username = identity.get("login")
            if username is None:
                return None
        orig_username = username
        identity["username"] = username = extract_username(username)

        # Normalize the password, if any, to be unicode.
        # It it's not valid utf8 then authentication fails.
        password = identity.get("password")
        if password is not None and not isinstance(password, unicode):
            try:
                identity["password"] = password.decode("utf8")
            except UnicodeDecodeError:
                return None

        # Decide whether it's a new-style or old-style auth backend.
        if hasattr(self.backend, 'generate_reset_code'):
            user = self._authenticate_oldstyle(environ, username, identity)
        else:
            user = self._authenticate_newstyle(environ, username, identity)

        # Log the error if that failed.
        if user is None:
            err_username = username
            if username != orig_username:
                err_username += ' (%s)' % (orig_username, )
            self.logger.cef('User Authentication Failed', 5, environ,
                            self.config, err_username, AUTH_FAILURE)
            return None

        # Success!  Store any loaded attributes into the identity dict.
        identity.update(user)
        return user["username"]
Example #16
0
    def test_shared_secret(self):
        # creating a user
        email = '*****@*****.**' % (time.time(),
                                           random.randint(1, 100))
        name = extract_username(email)
        user_url = '/user/1.0/%s' % name

        # we want the captcha to fail
        app = get_app(self.app)
        app.config['captcha.use'] = True

        def _failed(self, *args, **kw):
            return FakeCaptchaResponse(False)

        captcha.submit = _failed
        extra = {'X-Weave-Secret': 'xxx'}

        try:
            # everything is there, but bad secret. This should
            # fallback to the captcha test and eventually fail
            res = self.app.get(user_url)
            self.assertFalse(json.loads(res.body))
            payload = {'email': email, 'password': '******' * 9}
            payload = json.dumps(payload)
            res = self.app.put(user_url, params=payload, headers=extra,
                               status=400)
            self.assertEquals(res.json, ERROR_INVALID_CAPTCHA)

            # let's use the real secret
            extra['X-Weave-Secret'] = 'CHANGEME'
            res = self.app.put(user_url, params=payload, headers=extra)
            self.assertEquals(res.body, name)
            res = self.app.get(user_url)
            self.assertTrue(json.loads(res.body))
        finally:
            self.auth.delete_user(User(name), 'x' * 9)
Example #17
0
    def authenticate(self, environ, identity):
        # Normalize the username for our backend.
        # Some repoze.who plugins use "login" instead of "username".
        username = identity.get("username")
        if username is None:
            username = identity.get("login")
            if username is None:
                return None
        orig_username = username
        identity["username"] = username = extract_username(username)

        # Normalize the password, if any, to be unicode.
        if "password" in identity:
            try:
                identity["password"] = identity["password"].decode("utf8")
            except UnicodeDecodeError:
                return None

        # Decide whether it's a new-style or old-style auth backend.
        if hasattr(self.backend, 'generate_reset_code'):
            user = self._authenticate_oldstyle(environ, username, identity)
        else:
            user = self._authenticate_newstyle(environ, username, identity)

        # Log the error if that failed.
        if user is None:
            err_username = username
            if username != orig_username:
                err_username += ' (%s)' % (orig_username,)
            log_cef('User Authentication Failed', 5, environ, self.config,
                    err_username, AUTH_FAILURE)
            return None

        # Success!  Store any loaded attributes into the identity dict.
        identity.update(user)
        return user["username"]
Example #18
0
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        if 'REMOTE_USER' in environ:
            # already authenticated
            return environ['REMOTE_USER']

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                # Split in such a way as to preserve
                # passwords that contain ':'.
                user_name, password = base64.decodestring(auth).split(':', 1)
            except (binascii.Error, ValueError):
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                log_cef('Username Does Not Match URL', 7, environ, config,
                        user_name, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                raise HTTPBadRequest('Invalid characters specified in ' +
                                     'username', {}, 'Username must be BIDI ' +
                                     'compliant UTF-8')

            # let's try an authentication
            # the authenticate_user API takes a unicode UTF-8 for the password
            try:
                password = password.decode('utf8')
            except UnicodeDecodeError:
                raise HTTPUnauthorized()

            #first we need to figure out if this is old-style or new-style auth
            if hasattr(self.backend, 'generate_reset_code'):

            # XXX to be removed once we get the proper fix see bug #662859
                if (hasattr(self.backend, 'check_node')
                    and self.backend.check_node):
                    user_id = self.backend.authenticate_user(user_name,
                                            password, environ.get('HTTP_HOST'))
                else:
                    user_id = self.backend.authenticate_user(user_name,
                                                             password)
                request.user = User(user_name, user_id)
            else:
                user = User(user_name)
                credentials = {"username": user_name, "password": password}
                user_id = self.backend.authenticate_user(user, credentials,
                                                         ['syncNode'])
                if not user_id:
                    user_id = None
                    user = None
                else:
                    if (self.config.get('auth.check_node')
                        and user.get('syncNode') != environ.get('HTTP_HOST')):
                        user_id = None
                        user = None

                request.user = user

            if user_id is None:
                err_user = user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                        err_user += ' (%s)' % (remote_user_original)
                log_cef('User Authentication Failed', 5, environ, config,
                        err_user, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']

            del environ['HTTP_AUTHORIZATION']
            return user_id
Example #19
0
def forgot_step_2(request, **args):
    """Tries to send the email with a reset code, then lets the user know
    we've done that
    """
    data = {}
    auth = request.registry["auth"]
    username = extract_username(request.params['username'])
    request.user['username'] = username

    user_id = auth.get_user_id(request.user)
    if not user_id:
        request.errors.append(_('Unable to locate your account. '
                                'Please check your username.'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    if not request.registry.settings['app.captcha'].check(request):
        log_cef('Captcha failed on forgot password', 3,
                request.environ,
                request.registry.settings.get('config').get_map(),
                username, signature=CAPTCHA_FAILURE)
        request.errors.append(_('The captcha did not match. '
                                'Please try again'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    try:
        reset = request.registry.settings.get('app.console.reset')
        reset_code = reset.generate_reset_code(request.user, True)
        if not reset_code:
            request.errors.append(_('Getting a reset code failed '
                              'unexpectedly. Please try again later.'))
            logger.error("Could not generate a reset code")
            return render_to_response('console/password_reset1.mako',
                                      forgot_step_1(request), request)
        auth.get_user_info(request.user, ['mail'])
        if not valid_email(request.user['mail']):
            raise NoEmailError()

        maildata = {'forgot_url': '%s/forgot' % request.host_url,
                    'username': username,
                    'code': reset_code}
        template_path = get_template_lookup('console')
        template = \
            template_path.get_template('password_reset_mail.mako')
        body = template.render(**maildata)
        subject = _('Resetting your Mozilla Services password')
        smtp = request.registry.settings.get('config').get_map('smtp')
        #sender has a required position, so we can't pass it in in the
        #dict
        sender = smtp['sender']
        del smtp['sender']
        send_email(sender, request.user['mail'],
                   subject, body, **smtp)

    except AlreadySentError:
        #backend handled the reset code email. Keep going
        pass
    except NoEmailError:
        request.errors.append(_('We do not have an email on file for this '
                          'account and cannot send you a reset code.'))
        return render_to_response('console/password_reset1.mako',
                                  forgot_step_1(request), request)

    return data
    def authenticate_user(self, request, config, username=None):
        """Authenticates a user and returns his id.

        "request" is the request received.
        The function makes sure that the user name found in the headers
        is compatible with the username if provided.

        It returns the user id from the database, if the password is the right
        one.
        """
        environ = request.environ

        # If something further up the stack has already dealt with auth,
        # then things are highly unlikely to work properly.
        if 'REMOTE_USER' in environ:
            msg = 'The webserver appears to have handled authentication '\
                  'internally, which is not compatible with this product.'
            raise HTTPServerError(msg)

        auth = environ.get('HTTP_AUTHORIZATION')
        if auth is not None:
            # for now, only supporting basic authentication
            # let's decipher the base64 encoded value
            if not auth.startswith('Basic '):
                self._log_cef('Authorization header contains unknown protocol',
                              7, environ)
                raise HTTPUnauthorized('Invalid token')

            auth = auth[len('Basic '):].strip()
            try:
                # Split in such a way as to preserve
                # passwords that contain ':'.
                user_name, password = base64.decodestring(auth).split(':', 1)
            except (binascii.Error, ValueError):
                self._log_cef('Authorization header is badly encoded', 7,
                              environ)
                raise HTTPUnauthorized('Invalid token')

            # let's reject the call if the url is not owned by the user
            if (username is not None and user_name != username):
                self._log_cef('Username Does Not Match URL', 7, environ,
                              config, user_name, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # if this is an email, hash it. Save the original for logging and
            #  debugging.
            remote_user_original = user_name
            try:
                user_name = extract_username(user_name)
            except UnicodeError:
                self._log_cef('Username contains invalid characters', 7,
                              environ)
                raise HTTPBadRequest(
                    'Invalid characters specified in ' + 'username', {},
                    'Username must be BIDI ' + 'compliant UTF-8')

            # let's try an authentication
            # the authenticate_user API takes a unicode UTF-8 for the password
            try:
                password = password.decode('utf8')
            except UnicodeDecodeError:
                self._log_cef('Password is not utf-8 encoded', 7, environ)
                raise HTTPUnauthorized()

            #first we need to figure out if this is old-style or new-style auth
            if hasattr(self.backend, 'generate_reset_code'):

                # XXX to be removed once we get the proper fix see bug #662859
                if (hasattr(self.backend, 'check_node')
                        and self.backend.check_node):
                    user_id = self.backend.authenticate_user(
                        user_name, password, environ.get('HTTP_HOST'))
                else:
                    user_id = self.backend.authenticate_user(
                        user_name, password)
                request.user = User(user_name, user_id)
            else:
                user = User(user_name)
                credentials = {"username": user_name, "password": password}
                attrs = []
                check_node = self.config.get('auth.check_node')
                if check_node:
                    attrs.append('syncNode')
                user_id = self.backend.authenticate_user(
                    user, credentials, attrs)
                if not user_id:
                    user_id = None
                    user = None
                else:
                    if (check_node and
                            user.get('syncNode') != environ.get('HTTP_HOST')):
                        self._log_cef('User authenticated to wrong node', 7,
                                      environ)
                        user_id = None
                        user = None

                request.user = user

            if user_id is None:
                err_user = user_name
                if remote_user_original is not None and \
                    user_name != remote_user_original:
                    err_user += ' (%s)' % (remote_user_original)
                self._log_cef('User Authentication Failed', 5, environ, config,
                              err_user, AUTH_FAILURE)
                raise HTTPUnauthorized()

            # we're all clear ! setting up REMOTE_USER
            request.remote_user = environ['REMOTE_USER'] = user_name

            # we also want to keep the password in clear text to reuse it
            # and remove it from the environ
            request.user_password = password
            request._authorization = environ['HTTP_AUTHORIZATION']

            del environ['HTTP_AUTHORIZATION']
            return user_id