def _authenticate_newstyle(self, environ, username, identity):
     """Authenticate against a new-style auth backend."""
     user = User(username)
     if not self.backend.authenticate_user(user, identity, ['syncNode']):
         user = None
     else:
         if self.config.get('auth.check_node'):
             if user.get('syncNode') != environ.get('HTTP_HOST'):
                 user = None
     return user
コード例 #2
0
ファイル: backendauth.py プロジェクト: rfk/moz-server-core
 def _authenticate_newstyle(self, environ, username, identity):
     """Authenticate against a new-style auth backend."""
     user = User(username)
     if not self.backend.authenticate_user(user, identity, ['syncNode']):
         user = None
     else:
         if self.config.get('auth.check_node'):
             if user.get('syncNode') != environ.get('HTTP_HOST'):
                 user = None
     return user
コード例 #3
0
ファイル: test_user.py プロジェクト: rfk/moz-server-core
    def _tests(self, mgr):

        # Clean it up first if needed.
        user1_del = User()
        user1_del['username'] = '******'
        user2_del = User()
        user2_del['username'] = '******'

        mgr.delete_user(user1_del)
        mgr.delete_user(user2_del)

        # Create some initial users.
        user1 = mgr.create_user('user1', u'password1', '*****@*****.**')
        user1_id = user1['userid']
        user2 = mgr.create_user('user2', u'pásswørd1', '*****@*****.**')
        user2_id = user2['userid']
        user3 = User()
        user3['username'] = '******'

        # Make sure it can't create an existing user.
        self.assertEquals(mgr.create_user('user1', 'password1',
                                          '*****@*****.**'),
                          False)

        # Check it can successfully authenticate existing users.
        credentials1 = {"username": "******", "password": "******"}
        credentials2 = {"username": "******", "password": u"pásswørd1"}
        self.assertEquals(mgr.authenticate_user(user1, credentials1), user1_id)
        self.assertEquals(mgr.authenticate_user(user2, credentials2), user2_id)

        # Check that using a raw password works, but gives DeprecationWarning.
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("default")
            self.assertEquals(mgr.authenticate_user(user1, "password1"),
                              user1_id)
            self.assertEquals(len(w), 1)
            self.assertTrue("dict of credentials" in str(w[0].message))

        # Make sure that empty credentials doesn't do bad things.
        self.assertEquals(mgr.authenticate_user(user2, {}),
                          None)

        # Start with an unpopulated User object.
        user1_new = User()
        self.assertEquals(user1_new.get('username', None), None)
        self.assertEquals(user1_new.get('mail', None), None)

        # We should be able to populate it by authenticating.
        self.assertEquals(mgr.authenticate_user(user1_new, credentials1),
                          user1_id)
        self.assertEquals(user1_new['username'], 'user1')
        self.assertEquals(user1_new['userid'], user1_id)
        self.assertEquals(user1_new.get('mail', None), None)

        # If the User object is already populated, then it will only
        # authenticate correctly using that user's credentials.
        user2_new = User()
        user2_new["username"] = "******"
        self.assertEquals(mgr.authenticate_user(user2_new, credentials1),
                          None)
        self.assertEquals(user2_new['username'], 'user2')
        self.assertEquals(mgr.authenticate_user(user2_new, credentials2),
                          user2_id)
        self.assertEquals(user2_new['username'], 'user2')

        # We can load additional fields explicitly.
        user1_new = mgr.get_user_info(user1_new, ['mail', 'syncNode'])
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')
        self.assertEquals(user1_new.get('primaryNode', ''), '')

        # We can't update a field using invalid credentials.
        badcreds = {"username": "******", "password": "******"}
        self.assertFalse(mgr.update_field(user1_new, badcreds,
                                          'mail', '*****@*****.**'))
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')

        # We can't update a field using someone else's credentials.
        self.assertFalse(mgr.update_field(user1_new, credentials2,
                                          'mail', '*****@*****.**'))
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')

        # But it'll work using the proper credentials.
        self.assertTrue(mgr.update_field(user1_new, credentials1,
                                          'mail', '*****@*****.**'))
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')

        # And it'll work using the admin interface.
        self.assertTrue(mgr.admin_update_field(user1_new, 'mail',
                                               '*****@*****.**'))
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')

        # Updating a nonexistent user should fail.
        self.assertFalse(mgr.admin_update_field(user3, 'mail', 'foo'))

        # Did those changes persist?
        user1_new = User()
        self.assertEquals(user1_new.get('mail', None), None)
        user1_new['username'] = '******'
        user1_new = mgr.get_user_info(user1_new, ['mail', 'syncNode'])
        self.assertEquals(user1_new.get('mail', None), '*****@*****.**')

        # Changing password requires proper credentials.
        self.assertFalse(mgr.update_password(user1_new, badcreds,
                                             'password2'))
        self.assertFalse(mgr.update_password(user1_new, credentials2,
                                             'password2'))
        self.assertTrue(mgr.update_password(user1_new, credentials1,
                                            'password2'))

        # The password change affects future authentications.
        self.assertEquals(mgr.authenticate_user(user1, credentials1), None)
        credentials1["password"] = "******"
        self.assertEquals(mgr.authenticate_user(user1, credentials1), user1_id)

        # Use the admin interface to change password without credentials.
        self.assertTrue(mgr.admin_update_password(user1_new, 'password3'))
        self.assertEquals(mgr.authenticate_user(user1, credentials1),
                          None)
        credentials1["password"] = "******"
        self.assertEquals(mgr.authenticate_user(user1, credentials1), user1_id)

        # Users can be deleted, but only once.
        self.assertTrue(mgr.delete_user(user1))
        self.assertFalse(mgr.delete_user(user1))

        # Users can't log in after deletion, other users aren't affected.
        self.assertEquals(mgr.authenticate_user(user1, credentials1),
                          None)
        self.assertEquals(mgr.authenticate_user(user2, credentials2),
                          user2_id)
コード例 #4
0
ファイル: wsgiauth.py プロジェクト: rfk/moz-server-core
    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
    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