コード例 #1
0
 def test_11_admin(self):
     """Test User admin methods"""
     with self.app.app_context():
         filters = {'username': '******'}
         users = User.get_list(filters)
         self.assertEqual(len(users), 1)
         users[0].grant_admin()
         user = User.retrieve(users[0].userid)
         self.assertTrue(user.get_admin())
         user.revoke_admin()
         user = User.retrieve(users[0].userid)
         self.assertFalse(user.get_admin())
コード例 #2
0
 def test_07_update_user(self):
     """Test User.retrieve() method"""
     with self.app.app_context():
         filters = {'username': '******'}
         users = User.get_list(filters)
         self.assertEqual(len(users), 1)
         user = User.retrieve(users[0].userid)
         user.update(lastname='example')
         user = User.retrieve(users[0].userid)
         self.assertEqual(users[0].username, user.username)
         self.assertEqual(user.lastname, 'example')
         user.update(lastname='Example')
コード例 #3
0
 def test_10_lock(self):
     """Test User lock methods"""
     with self.app.app_context():
         filters = {'username': '******'}
         users = User.get_list(filters)
         self.assertEqual(len(users), 1)
         users[0].set_lock()
         user = User.retrieve(users[0].userid)
         self.assertTrue(user.get_lock())
         user.unlock()
         user = User.retrieve(users[0].userid)
         self.assertFalse(user.get_lock())
         self.assertEqual(user.failed_logins, 0)
         self.assertIsNone(user.last_failed_login)
コード例 #4
0
def set_password(userid, data):
    """
    Set new password for User account

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        data - dictionary with Set new password for User attributes, loaded from
            Request body JSON and validated with models.set_password_body_schema
        JWT Baerer Authorization in request.headers - account owner or
            admin privilege required

    Returns:
        Confirmation or Error Message
    """
    user = User.retrieve(userid)
    if not user:
        return('Not Found', 404)

    if current_user.userid != userid and not current_user.get_admin():
        current_app.logger.warning(
            f'set_password(userid={userid}) failed. Userid={current_user.userid} not authorized'
            )
        return make_response('Unauthorized', 401)

    user.set_password(data['password'])

    return('OK', 200)
コード例 #5
0
def update_user(userid, data):
    """
    Update User Resource Representation

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        data - dictionary with partial User Resource attributes, loaded from
            Request body JSON and validated with models.user_schema
        JWT Baerer Authorization in request.headers - account owner or
            admin privilege required

    Returns:
        Confirmation or Error Message
    """
    user = User.retrieve(userid)
    if not user:
        return make_response('Not found', 404)

    if 'username' in data and User.get_list({'username': data['username']}):
        current_app.logger.warning(
            f'create_user() failed. Username={data["username"]} already exists'
            )
        return make_response('Bad request', 400)

    if current_user.userid != userid and not current_user.get_admin():
        current_app.logger.warning(
            f'update_user(userid={userid}) failed. Userid={current_user.userid} not authorized'
            )
        return make_response('Unauthorized', 401)

    user.update(**data)

    return make_response('OK', 200)
コード例 #6
0
def add_user_to_group(groupid, userid):
    """
    Add User to Group

    Args:
        groupid: Path Parameter - Unique ID of Group Resource (int)
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        Confirmation or Error Message
    """
    group = Group.retrieve(groupid)
    if group == None:
        current_app.logger.warning(
            f'add_user_to_group() Group with id={groupid} not found')
        return make_response('Group or User not found', 404)
    user = User.retrieve(userid)
    if user == None:
        current_app.logger.warning(
            f'add_user_to_group() User with id={userid} not found')
        return make_response('Group or User not found', 404)
    if user in group.users:
        return 'User already in the Group', 200
    else:
        group.add_member(user)
        return 'User added to the Group', 201
コード例 #7
0
 def test_09_set_password(self):
     """Test User.set_password() method"""
     with self.app.app_context():
         filters = {'username': '******'}
         users = User.get_list(filters)
         self.assertEqual(len(users), 1)
         users[0].set_password('pass')
         user = User.retrieve(users[0].userid)
         self.assertEqual(user.password, 'pass')
コード例 #8
0
 def test_05_user_retrieve(self):
     """Test User.retrieve() method"""
     with self.app.app_context():
         filters = {'username': '******'}
         users = User.get_list(filters)
         self.assertEqual(len(users), 1)
         user = User.retrieve(users[0].userid)
         self.assertIsNotNone(user)
         self.assertIsInstance(user, User)
         self.assertEqual(users[0].username, user.username)
コード例 #9
0
def retrieve_user(userid):
    """
    Retrieve User Resource Representation

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        X-API-Key in request.headers

    Returns:
        JSON Object with User Resource Representation or Error Message
    """
    user = User.retrieve(userid)
    if user:
        return jsonify(user_schema.dump(user))
    else:
        return("Not Found", 404)
コード例 #10
0
def read_admin_status(userid):
    """
    Read User account admin privilege status

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        JSON Object with admin status or Error Message
    """
    user = User.retrieve(userid)
    if not user:
        return('Not Found', 404)

    return jsonify({'isAdmin': user.get_admin()})
コード例 #11
0
def remoke_admin_status(userid):
    """
    Revoke admin privilege from User

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        Confirmation or Error Message
    """
    user = User.retrieve(userid)
    if not user:
        return('Not Found', 404)

    user.revoke_admin()
    return('OK', 200)
コード例 #12
0
def clear_lock(userid):
    """
    Clear User lock status

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        Confirmation or Error Message
    """
    user = User.retrieve(userid)
    if not user:
        return('Not Found', 404)

    user.unlock()
    return('OK', 200)
コード例 #13
0
def delete_user(userid):
    """
    Delete User Resource

    Args:
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        Confirmation or Error Message
    """
    user = User.retrieve(userid)
    if user:
        if userid == current_user.userid:
            current_app.logger.warning(
                f'delete_user(userid={userid}) failed. Cannot delete self'
                )
            return make_response('Unauthorized', 401)
        else:
            user.remove()
            return make_response('OK', 200)
    else:
        return make_response('Not found', 404)
コード例 #14
0
def delete_user_from_group(groupid, userid):
    """
    Delete User from Group

    Args:
        groupid: Path Parameter - Unique ID of Group Resource (int)
        userid: Path Parameter - Unique ID of User Resource (int)
        JWT Baerer Authorization in request.headers - admin privilege required

    Returns:
        Confirmation or Error Message
    """
    group = Group.retrieve(groupid)
    if group == None:
        current_app.logger.warning(
            f'add_user_to_group() Group with id={groupid} not found')
        return make_response('Group or User not found', 404)
    user = User.retrieve(userid)
    if user == None:
        current_app.logger.warning(
            f'add_user_to_group() User with id={userid} not found')
        return make_response('Group or User not found', 404)
    group.remove_member(user)
    return 'User deleted from Group', 200
コード例 #15
0
    def test_1_login(self):
        """Test Login operation"""
        # This test assumes that 'admin' and 'lindas' are in Users,
        # both have password 'pass', are unlocked and can login
        # 'admin' must have following values:
        # username : admin
        # firstname : Admin
        # lastname : User
        # email: [email protected]
        # phone : 123-444-5555
        # Test assumes user 'locked' is in Database with password 'pass',
        # is locked and unable to login
        # Test assumes there is no user 'admin1' in Database
        # Test assumes application configuration parameters
        # MAX_FAILED_LOGIN_ATTEMPTS and JWT_ACCESS_TOKEN_EXPIRES are set
        #
        # Test successful login operation - 200
        admin_login_data = {'username': '******', 'password': '******'}
        resp = self.client.post('/login', json=admin_login_data)
        self.assertEqual(resp.status_code, 200)
        # Assert response data is JSON
        self.assertTrue(resp.is_json)
        resp_data = resp.get_json()
        # Assert Response JSON has expected fields
        self.assertSetEqual({'jwtToken', 'userHref'}, set(resp_data.keys()))
        # Decode and check returned JWT
        with self.app.app_context():
            decoded_token = flask_jwt_extended.decode_token(
                resp_data['jwtToken'])
        # Assert JWT has 'identity', 'iat' and 'exp' fields
        self.assertIn('identity', decoded_token)
        self.assertIn('iat', decoded_token)
        self.assertIn('exp', decoded_token)
        # Assert DB object with userid==decoded_token['identity'] is in fact 'admin'
        with self.app.app_context():
            user = User.retrieve(decoded_token['identity'])
        self.assertEqual(user.username, 'admin')
        # Assert JWT expiration 'exp' is set to Application Config value
        config_jwt_exp = self.app.config['JWT_ACCESS_TOKEN_EXPIRES']
        if type(config_jwt_exp) is int:
            self.assertEqual(decoded_token['exp'] - decoded_token['iat'],
                             config_jwt_exp)
        elif type(config_jwt_exp) is datetime.timedelta:
            self.assertEqual(
                datetime.timedelta(seconds=decoded_token['exp'] -
                                   decoded_token['iat']), config_jwt_exp)
        else:
            # We have unsupported type of JWT_ACCESS_TOKEN_EXPIRES.
            # flask_jwt_extended.create_token() should fail in this case,
            # resulting in failure of first Login operation.
            # Code below should not get reached
            self.fail(
                msg=
                f'Config parameter JWT_ACCESS_TOKEN_EXPIRES has unexpected type {type(config_jwt_exp)}'
            )
        # Assert 'userHref' is 'admin' User URI
        resp1 = self.client.get(
            resp_data['userHref'],
            headers={'X-API-Key': self.app.config['API_KEY']})
        self.assertEqual(resp1.status_code, 200)
        resp1_data = resp1.get_json()
        expected_admin_data = {
            'userid': user.userid,
            'username': '******',
            'firstname': 'Admin',
            'lastname': 'User',
            'contactInfo': {
                'email': '*****@*****.**',
                'phone': '123-444-5555'
            }
        }
        self.assertDictEqual(resp1_data, expected_admin_data)

        # Test correct username and incorrect password - 401
        bad_pass_login_data = {'username': '******', 'password': '******'}
        resp = self.client.post('/login', json=bad_pass_login_data)
        self.assertEqual(resp.status_code, 401)
        # Assert no JSON in response data
        self.assertFalse(resp.is_json)
        self.assertIsNone(resp.get_json())

        # Test incorrect username - 401
        bad_username_login_data = {'username': '******', 'password': '******'}
        resp = self.client.post('/login', json=bad_username_login_data)
        self.assertEqual(resp.status_code, 401)
        # Assert no JSON in response data
        self.assertFalse(resp.is_json)
        self.assertIsNone(resp.get_json())

        # Test locked account - 401
        locked_login_data = {'username': '******', 'password': '******'}
        resp = self.client.post('/login', json=locked_login_data)
        self.assertEqual(resp.status_code, 401)
        # Assert no JSON in response data
        self.assertFalse(resp.is_json)
        self.assertIsNone(resp.get_json())

        # Test incorrect Request body data - 400
        bad_login_data = [{
            'user': '******',
            'password': '******'
        }, {
            'username': '******'
        }, {
            'username': '******',
            'password': 5
        }, {
            'username': "******",
            'password': ''
        }]
        for data in bad_login_data:
            resp = self.client.post('/login', json=data)
            self.assertEqual(resp.status_code,
                             400,
                             msg=f'bad_login_data={bad_login_data}')
            # Assert no JSON in response data
            self.assertFalse(resp.is_json,
                             msg=f'bad_login_data={bad_login_data}')
            self.assertIsNone(resp.get_json(),
                              msg=f'bad_login_data={bad_login_data}')

        # Test invalid JSON format data
        bad_json = '{"username": "******", "password": "******"'
        resp = self.client.post('/login',
                                data=bad_json,
                                headers={'Content-Type': 'application/json'})
        self.assertEqual(resp.status_code, 400)
        # Assert no JSON in response data
        self.assertFalse(resp.is_json)
        self.assertIsNone(resp.get_json())

        # Test 'text/plain' Request body format - 415
        text_data = 'random text'
        resp = self.client.post('/login', data=text_data)
        self.assertEqual(resp.status_code, 415)
        # Assert no JSON in response data
        self.assertFalse(resp.is_json)
        self.assertIsNone(resp.get_json())

        # Test User account lock due to unsuccessful logins
        # Reset LOCK_TIMEOUT to very short period
        lock_timeout_config = self.app.config['LOCK_TIMEOUT']
        temporary_lock_timeout = 1
        self.app.config['LOCK_TIMEOUT'] = datetime.timedelta(
            seconds=temporary_lock_timeout)
        # Confirm User lindas is unlocked and can log in
        lindas_login_data = {'username': '******', 'password': '******'}
        resp = self.client.post('/login', json=lindas_login_data)
        self.assertEqual(resp.status_code, 200)
        # Make MAX_FAILED_LOGIN_ATTEMPTS failed login attempts
        # User account should not get locked yet
        incorrect_data = {'username': '******', 'password': '******'}
        for i in range(self.app.config['MAX_FAILED_LOGIN_ATTEMPTS']):
            resp = self.client.post('/login', json=incorrect_data)
            self.assertEqual(resp.status_code, 401, msg=f'i={i}')
        # Make correct login to verify that account is not locked
        # and to clear failed logins counter
        resp = self.client.post('/login', json=lindas_login_data)
        self.assertEqual(resp.status_code, 200)
        # Make MAX_FAILED_LOGIN_ATTEMPTS + 1 failed login attempts
        # User account should get locked in the end
        for i in range(self.app.config['MAX_FAILED_LOGIN_ATTEMPTS'] + 1):
            resp = self.client.post('/login', json=incorrect_data)
            self.assertEqual(resp.status_code, 401, msg=f'i={i}')
        # Assert User cannot login now
        resp = self.client.post('/login', json=lindas_login_data)
        self.assertEqual(resp.status_code, 401)
        # Sleep for temporary lock timeout (1 sec)
        time.sleep(temporary_lock_timeout)
        # Assert lindas can login again now
        resp = self.client.post('/login', json=lindas_login_data)
        self.assertEqual(resp.status_code, 200)
        # Restore LOCK_TIMEOUT
        self.app.config['LOCK_TIMEOUT'] = lock_timeout_config
コード例 #16
0
def load_current_user(identity):
    """Load User object for JWTManager, using Token's identity"""
    return User.retrieve(identity)