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
Example #2
0
 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
Example #3
0
    def create_user(self, user_name, password, email):
        """Creates a user. Returns a user object on success."""
        if not self.allow_new_users:
            raise BackendError("Creation of new users is disabled")

        # no unicode
        user_name = user_name.encode('utf8')
        password = password.encode('utf8')
        email = email.encode('utf8')

        #First make sure the username isn't taken. There'll still be a race
        #condition, but it's pretty small
        test_user = User()
        test_user['username'] = user_name
        dn = self._get_dn(test_user)
        if dn is not None:
            return False

        user_id = self._get_next_user_id()
        password_hash = ssha(password)
        key = '%s%s' % (random.randint(0, 9999999), user_name)
        key = sha1(key).hexdigest()

        user = {
            'cn': user_name,
            'sn': user_name,
            'uid': user_name,
            'uidNumber': str(user_id),
            'userPassword': password_hash,
            'primaryNode': 'weave:',
            'accountStatus': '1',
            'account-enabled': 'Yes',
            'mail': email,
            'mail-verified': key,
            'objectClass': ['dataStore', 'inetOrgPerson']
        }

        dn = "uidNumber=%i,%s" % (user_id, self.users_root)

        #need a copy with some of the info for the return value
        userobj = User()
        userobj['username'] = user['uid']
        userobj['userid'] = user['uidNumber']
        userobj['mail'] = email
        userobj['dn'] = dn

        #need to turn the user hash into tuples
        user = user.items()

        with self._conn() as conn:
            try:
                res, __ = conn.add_s(dn, user)
            except (ldap.TIMEOUT, ldap.SERVER_DOWN, ldap.OTHER), e:
                self.logger.debug('Could not create the user.')
                raise BackendError(str(e))
    def create_user(self, username, password, email, **extra_fields):
        """Creates a user. Returns True on success."""
        if not self.allow_new_users:
            raise BackendError("Creation of new users is disabled")

        password_hash = sscrypt(password)
        values = {
            'username': username,
            'password': password_hash,
            'mail': email,
        }
        for field in ('userid', 'accountStatus', 'mailVerified', 'syncNode'):
            if field in extra_fields:
                values[field] = extra_fields[field]
        query = insert(users).values(**values)
        try:
            res = safe_execute(self._engine, query)
        except IntegrityError:
            #Name already exists
            return False

        if res.rowcount != 1:
            return False

        #need a copy with some of the info for the return value
        userobj = User()
        userobj['username'] = username
        userobj['userid'] = res.lastrowid
        userobj['mail'] = email

        return userobj
Example #5
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
    def create_user(self, user_name, password, email):
        """Creates a user"""
        if not self.allow_new_users:
            raise BackendError("Creation of new users is disabled")

        user = User()
        if user_name in self._users:
            return False
        id_ = random.randint(1, 2000)
        ids = self._users.values()
        while id_ in ids:
            id_ = random.randint(1, 2000)

        self._users[user_name] = {
            'userid': id_,
            'password': password,
            'mail': email,
            'username': user_name,
            'primaryNode': ''
        }

        user['username'] = user_name
        user['userid'] = id_
        user['mail'] = email
        return user
Example #7
0
def login_as_user():
    username = input("Username: ")
    user = User(username, True if username == 'admin' else False)

    if bool(user.admin):
        show_admin_menu(user)
    else:
        show_user_menu(user)
Example #8
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)
 def _create_user(self, username, password, email=None, syncNode=None):
     """Create a user in the DB, and return the user object."""
     if not email:
         email = '*****@*****.**'
     if not syncNode:
         syncNode = 'http://sync1.example.com'
     self.auth.create_user(username, password, email)
     user = self.auth.get_user_info(User(username), ['syncNode'])
     self.auth.admin_update_field(user, 'syncNode', syncNode)
     return user
    def _authenticate_oldstyle(self, environ, username, identity):
        """Authenticate against an old-style auth backend."""
        password = identity.get("password")
        if password is None:
            return None

        if hasattr(self.backend, 'check_node') and self.backend.check_node:
            host = environ.get('HTTP_HOST')
            user_id = self.backend.authenticate_user(username, password, host)
        else:
            user_id = self.backend.authenticate_user(username, password)

        if user_id is None:
            return None
        return User(username, user_id)
    def _dispatch_request_with_match(self, request, match):
        """Dispatch a request according to a URL routing match."""
        function = self._get_function(match['controller'], match['action'])
        if function is None:
            raise HTTPNotFound('Unknown URL %r' % request.path_info)

        # extracting all the info from the headers and the url
        request.sync_info = match

        # creating a user object to be passed around the request, if one hasn't
        # already been set
        if not hasattr(request, 'user'):
            request.user = User()
            if 'username' in request.sync_info:
                request.user['username'] = request.sync_info['username']
            if 'user_id' in request.sync_info:
                request.user['userid'] = request.sync_info['user_id']

        params = self._get_params(request)
        try:
            result = function(request, **params)
        except BackendError as err:
            err.request = request
            err_info = str(err)
            err_trace = traceback.format_exc()
            extra_info = [
                '%s: %s' % (key, value)
                for key, value in self.get_infos(request).items()
            ]
            extra_info = '\n'.join(extra_info)
            error_log = '%s\n%s\n%s' % (err_info, err_trace, extra_info)
            hash = create_hash(error_log)
            self.logger.error(hash)
            self.logger.error(error_log)
            msg = json.dumps("application error: crash id %s" % hash)
            if err.retry_after is not None:
                if err.retry_after == 0:
                    retry_after = None
                else:
                    retry_after = err.retry_after
            else:
                retry_after = self.retry_after

            raise HTTPJsonServiceUnavailable(msg, retry_after=retry_after)

        # create the response object in case we get back a string
        response = self._create_response(request, result, function)
        return response
Example #12
0
def load_emulator_scene():
    print_info_message('\nYou are in emulator mode\n')

    for username in usernames:
        user = User(username)
        for i in range(1, 2):
            # time.sleep(random.random() * 2)
            # if not random.getrandbits(1):
            #     read_message(user)
            publish_message(user)

    try:
        for message in listener.listen():
            if message.get('type') == 'message':
                msg = ChatController.convert_to_message_object(message.get('data'))
                process_message(msg)
    except KeyboardInterrupt:
        pass
    def check(self, request, match):
        """Checks if the current request/match can be viewed.

        For WhoAuthentication this just delegates to the authenticate()
        API method, and uses the challenge() method if the user is not
        authorized for the request.
        """
        # Don't auth if it's not required by the match.
        if match.get('auth') != 'True':
            return

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

        # Authenticate the user.
        api = self._api_factory(request.environ)
        identity = api.authenticate()
        if identity is None:
            self._raise_challenge(request)

        # Check against the username matched from the url, if any.
        username = identity.get("username")
        if match.get("username") not in (None, username):
            cef_kwds = {"signature": AUTH_FAILURE}
            if username is not None:
                cef_kwds["username"] = username
            err = "Username Does Not Match URL"
            self.logger.cef(err, 7, request.environ, self.config, **cef_kwds)
            self._raise_challenge(request)

        # Adjust environ to record the successful auth.
        # The identity must somehow get "userid" and "username" keys,
        # either from the authenticator or from an mdprovider.
        request.environ.pop("HTTP_AUTHORIZATION", None)
        match["user_id"] = identity["userid"]
        request.remote_user = identity["username"]
        request.environ["REMOTE_USER"] = identity["username"]
        request.user = User(identity["username"], identity["userid"])
        request.user.update(identity)
    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 #15
0
    def test_change_password_with_header(self):
        body = 'newpasswordhere'

        # unknown user
        extra = [('X-Weave-Password-Reset', 'key')]
        self.app.post('/user/1.0/_xx_/password', params=body,
                      headers=extra, status=404)

        # bad key
        extra = {'X-Weave-Password-Reset': 'key'}
        res = self.app.post(self.root + '/password', params=body,
                            headers=extra, status=400)
        self.assertEquals(res.body, '10')

        user = User(self.user_name)
        self.auth.get_user_id(user)
        key = str(self.reset.generate_reset_code(user))

        extra = {'X-Weave-Password-Reset': key}
        res = self.app.post(self.root + '/password', params=body,
                            headers=extra)
        self.assertEqual(res.body, 'success')
Example #16
0
    def create_user(self, username, password, email):
        """Creates a user. Returns user on success, false otherwise."""
        if not self.allow_new_users:
            raise BackendError("Creation of new users is disabled")

        payload = {'password': password, 'email': email}
        url = self._generate_url(username)
        status, body = self._proxy('PUT', url, payload)
        if status != 200:
            if body == ERROR_INVALID_WRITE:
                return False
            msg = 'Unable to create the user via sreg. '
            msg += 'Received body:\n%s\n' % str(body)
            msg += 'Received status: %d' % status
            raise BackendError(msg, server=url)

        # the result is the username on success
        if body == username:
            user = User()
            user['username'] = username
            user['email'] = email
            return user
        else:
            return False
Example #17
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)
    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
Example #19
0
def show_ec2_instances(username):
    instance_list = User.get_all_ec2_instances(username)
    if len(instance_list)!=0:
        return render_template("ec2_instances.html",instance_list=instance_list)
    else:
        return render_template("ec2_instances.html")
Example #20
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 #21
0
    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)
class UserController(object):
    def __init__(self, app):
        self.app = app
        self.strict_usernames = app.config.get('auth.strict_usernames', True)
        self.shared_secret = app.config.get('global.shared_secret')
        self.auth = self.app.auth.backend
        self.fallback_node = \
                    self.clean_location(app.config.get('nodes.fallback_node'))

        try:
            self.reset = load_and_configure(app.config, 'reset_codes')
        except Exception:
            logger.debug(traceback.format_exc())
            logger.debug("No reset code library in place")
            self.reset = None

    def user_exists(self, request):
        if request.user.get('username') is None:
            raise HTTPNotFound()
        uid = self.auth.get_user_id(request.user)
        return text_response(int(uid is not None))

    def return_fallback(self):
        if self.fallback_node is None:
            return json_response(None)
        return self.fallback_node

    def clean_location(self, location):
        if location is None:
            return None
        if not location.endswith('/'):
            location += '/'
        if not location.startswith('http'):
            location = 'https://%s' % location
        return location

    def user_node(self, request):
        """Returns the storage node root for the user"""
        # warning:
        # the client expects a string body not a json body
        # except when the node is 'null'

        # IF YOU ARE USING ACTUAL NODE ASSIGNMENT (odds are you're not)
        # There is now a separate assignment module:
        # http://hg.mozilla.org/services/server-node-assignment
        # Install that and point your server at it for
        # the node assignment call

        if request.user.get('username') is None:
            raise HTTPNotFound()

        if not self.auth.get_user_id(request.user):
            raise HTTPNotFound()

        return self.return_fallback()

    def password_reset(self, request, **data):
        """Sends an e-mail for a password reset request."""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        user_id = self.auth.get_user_id(request.user)
        if user_id is None:
            # user not found
            raise HTTPJsonBadRequest(ERROR_INVALID_USER)

        self.auth.get_user_info(request.user, ['mail'])
        if request.user.get('mail') is None:
            raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS)

        self._check_captcha(request, data)

        try:
            # the request looks fine, let's generate the reset code
            code = self.reset.generate_reset_code(request.user)

            data = {
                'host': request.host_url,
                'user_name': request.user['username'],
                'code': code
            }
            body = render_mako('password_reset_mail.mako', **data)

            sender = request.config['smtp.sender']
            host = request.config['smtp.host']
            port = int(request.config['smtp.port'])
            user = request.config.get('smtp.user')
            password = request.config.get('smtp.password')

            subject = 'Resetting your Services password'
            res, msg = send_email(sender, request.user['mail'], subject, body,
                                  host, port, user, password)

            if not res:
                raise HTTPServiceUnavailable(msg)
        except AlreadySentError:
            #backend handled the reset code email. Keep going
            pass

        return text_response('success')

    def delete_password_reset(self, request, **data):
        """Forces a password reset clear"""
        if self.reset is None:
            logger.debug('reset attempted, but no resetcode library installed')
            raise HTTPServiceUnavailable()

        self._check_captcha(request, data)
        self.auth.get_user_id(request.user)
        self.reset.clear_reset_code(request.user)
        log_cef("User requested password reset clear",
                9, request.environ, self.app.config,
                request.user.get('username'), PASSWD_RESET_CLR)
        return text_response('success')

    def _check_captcha(self, request, data):
        # check if captcha info are provided
        if not self.app.config['captcha.use']:
            return

        challenge = data.get('captcha-challenge')
        response = data.get('captcha-response')

        if challenge is not None and response is not None:
            resp = captcha.submit(challenge,
                                  response,
                                  self.app.config['captcha.private_key'],
                                  remoteip=request.remote_addr)
            if not resp.is_valid:
                raise HTTPJsonBadRequest(ERROR_INVALID_CAPTCHA)
        else:
            raise HTTPJsonBadRequest(ERROR_INVALID_CAPTCHA)

    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 change_email(self, request):
        """Changes the user e-mail"""

        # the body is in plain text
        email = request.body

        if not valid_email(email):
            raise HTTPJsonBadRequest(ERROR_NO_EMAIL_ADDRESS)

        if not hasattr(request, 'user_password'):
            raise HTTPBadRequest()

        if not self.auth.update_field(request.user, request.user_password,
                                      'mail', email):
            raise HTTPInternalServerError('User update failed.')

        return text_response(email)

    def change_password(self, request):
        """Changes the user's password

        Takes a classical authentication or a reset code
        """
        # the body is in plain text utf8 string
        new_password = request.body.decode('utf8')

        if not valid_password(request.user.get('username'), new_password):
            raise HTTPBadRequest('Password should be at least 8 '
                                 'characters and not the same as your '
                                 'username')

        key = request.headers.get('X-Weave-Password-Reset')

        if key is not None:
            user_id = self.auth.get_user_id(request.user)

            if user_id is None:
                raise HTTPNotFound()

            if not self.reset.verify_reset_code(request.user, key):
                log_cef('Invalid Reset Code submitted',
                        5,
                        request.environ,
                        self.app.config,
                        request.user['username'],
                        'InvalidResetCode',
                        submitedtoken=key)

                raise HTTPJsonBadRequest(ERROR_INVALID_RESET_CODE)

            if not self.auth.admin_update_password(request.user, new_password,
                                                   key):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')
        else:
            # classical auth
            self.app.auth.authenticate_user(request, self.app.config,
                                            request.user['username'])

            if request.user['userid'] is None:
                log_cef('User Authentication Failed', 5, request.environ,
                        self.app.config, request.user['username'],
                        AUTH_FAILURE)
                raise HTTPUnauthorized()

            if not self.auth.update_password(
                    request.user, request.user_password, new_password):
                raise HTTPInternalServerError('Password change failed '
                                              'unexpectedly.')

        return text_response('success')

    def password_reset_form(self, request, **kw):
        """Returns a form for resetting the password"""
        if 'key' in kw or 'error' in kw:
            # we have a key, let's display the key controlling form
            return render_mako('password_reset_form.mako', **kw)
        elif not request.POST and not request.GET:
            # asking for the first time
            return render_mako('password_ask_reset_form.mako')

        raise HTTPBadRequest()

    def _repost(self, request, error):
        request.POST['error'] = error
        return self.password_reset_form(request, **dict(request.POST))

    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()

        # full form, the actual password reset
        password = request.POST.get('password')
        confirm = request.POST.get('confirm')
        key = request.POST.get('key')

        if key is None:
            raise HTTPJsonBadRequest()

        if user_name is None:
            return self._repost(
                request, 'Username not provided. Please check '
                'the link you used.')

        user = User(user_name)
        user_id = self.auth.get_user_id(user)
        if user_id is None:
            return self._repost(request, 'We are unable to locate your '
                                'account')

        if password is None:
            return self._repost(
                request, 'Password not provided. '
                'Please check the link you used.')

        if password != confirm:
            return self._repost(request, 'Password and confirmation do '
                                'not match')

        if not valid_password(user_name, password):
            return self._repost(
                request, 'Password should be at least 8 '
                'characters and not the same as your '
                'username')

        if not self.reset.verify_reset_code(user, key):
            return self._repost(
                request, 'Key does not match with username. '
                'Please request a new key.')

        # everything looks fine
        if not self.auth.admin_update_password(user, 'password', password):
            return self._repost(request, 'Password change failed '
                                'unexpectedly.')

        self.reset.clear_reset_code(user)
        return render_mako('password_changed.mako')
Example #23
0
 def setup_utils(self):
     self.posts_util = Posts()
     self.friends_util = Friends()
     self.user_util = User()
Example #24
0
 def do_user(self, line):
     """user <username>"""
     User(line, self.db).run()