예제 #1
0
def test_post_user_profiles_min_fail(app, mocker):
    expected_status = 400
    expected_json = {'error': {
        'first_name': ["Value must be between 1 and 40 characters long."],
        'last_name': ["Value must be between 2 and 40 characters long."],
    }}

    request_mock = mocker.patch('modules.user_profiles.routes_admin.request')
    request_mock.json = {
        'user_id': 9,
        'first_name': "",
        'last_name': "A",
        'joined_at': "2019-02-04T00:00:00+0000",
        'status': UserProfile.STATUS_ENABLED
    }

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock exists() validation
    user_9 = User()
    user_9.id = 9
    query_mock.return_value \
        .get.return_value = user_9

    result = post_user_profiles()

    assert result[1] == expected_status
    assert result[0].json == expected_json
예제 #2
0
def test_post_user_profiles_max_fail(app, mocker):
    expected_status = 400
    expected_json = {'error': {
        'first_name': ["Value must be between 1 and 40 characters long."],
        'last_name': ["Value must be between 2 and 40 characters long."],
    }}

    request_mock = mocker.patch('modules.user_profiles.routes_admin.request')
    request_mock.json = {
        'user_id': 9,
        'first_name': "LRUNzhfsbfrfZ4BT9N6R3SNYVfAAuQdQdTSmrwFew",
        'last_name': "z3Sytm4QrL8g7J4kgugEABnhwXZAnCZmrngUCeeXm",
        'joined_at': "2019-02-04T00:00:00+0000",
        'status': UserProfile.STATUS_ENABLED
    }

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock exists() validation
    user_9 = User()
    user_9.id = 9
    query_mock.return_value \
        .get.return_value = user_9

    result = post_user_profiles()

    assert result[1] == expected_status
    assert result[0].json == expected_json
예제 #3
0
def test_put_user_profile_max_fail(app, mocker):
    expected_status = 400
    expected_json = {'error': {
        'first_name': ["Value must be between 1 and 40 characters long."],
        'last_name': ["Value must be between 2 and 40 characters long."],
    }}

    request_mock = mocker.patch('modules.user_profiles.routes_admin.request')
    request_mock.json = {
        'user_id': 9,
        'first_name': "pSJxpg6GC2qRnekNVDKMkYqNqAbd7X5UzsKuhVzf4",
        'last_name': "J5ATwnHEfD5YqSQNTDcb9bFbaD6ZRZvL3b9ugjyUK",
        'joined_at': "2018-12-09T08:00:00+0000",
        'status': UserProfile.STATUS_DISABLED
    }

    user_profile_2 = UserProfile()
    user_profile_2.id = 2

    user_9 = User()
    user_9.id = 9

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock initial resource query and exists() validation
    query_mock.return_value \
        .get.side_effect = [user_profile_2, user_9]

    result = put_user_profile(2)

    assert result[1] == expected_status
    assert result[0].json == expected_json
예제 #4
0
def test_put_user_profile_ok(app, mocker):
    expected_status = 200
    expected_m_length = 9
    expected_m_id = 2
    expected_m_user_id = 9
    expected_m_first_name = "LynneA"
    expected_m_last_name = "HarfordA"
    expected_m_joined_at = "2018-12-09T08:00:00+0000"
    expected_m_status = UserProfile.STATUS_DISABLED
    expected_m_created_at = None
    expected_m_updated_at = None
    # @todo: timezone
    re_datetime = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")

    request_mock = mocker.patch('modules.user_profiles.routes_admin.request')
    request_mock.json = {
        'user_id': expected_m_user_id,
        'first_name': expected_m_first_name,
        'last_name': expected_m_last_name,
        'joined_at': expected_m_joined_at,
        'status': expected_m_status,
    }

    user_profile_2 = UserProfile()
    user_profile_2.id = expected_m_id

    user_9 = User()
    user_9.id = 9

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock initial resource query and exists() validation
    query_mock.return_value \
        .get.side_effect = [user_profile_2, user_9]

    db_mock = mocker.patch('modules.user_profiles.routes_admin.db')
    db_mock.commit.return_value = None

    result = put_user_profile(expected_m_id)

    assert result[1] == expected_status
    assert 'user_profile' in result[0].json
    assert len(result[0].json['user_profile']) == expected_m_length
    assert result[0].json['user_profile']['id'] == expected_m_id
    assert result[0].json['user_profile']['user_id'] == expected_m_user_id
    assert result[0].json['user_profile']['first_name'] == \
        expected_m_first_name
    assert result[0].json['user_profile']['last_name'] == expected_m_last_name
    assert result[0].json['user_profile']['joined_at'] == expected_m_joined_at
    assert result[0].json['user_profile']['status'] == expected_m_status
    assert bool(re_datetime.match(
        result[0].json['user_profile']['status_changed_at']))
    assert result[0].json['user_profile']['created_at'] == \
        expected_m_created_at
    assert result[0].json['user_profile']['updated_at'] == \
        expected_m_updated_at
예제 #5
0
def test_user_auth_token_pass(app, mocker):
    user1 = User()
    user1.id = 1
    token = user1.generate_auth_token()

    # mock db query
    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')
    query_mock.return_value \
        .get.return_value = user1

    assert User.verify_auth_token(token)
예제 #6
0
def test_post_user_profile_ok(app, mocker):
    expected_status = 201
    expected_m_length = 9
    expected_m_id = None
    expected_m_user_id = 9
    expected_m_first_name = "Service"
    expected_m_last_name = "Account"
    expected_m_joined_at = "2019-02-04T00:00:00+0000"
    expected_m_status = UserProfile.STATUS_ENABLED
    expected_m_created_at = None
    expected_m_updated_at = None
    # @todo: timezone
    re_datetime = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")

    request_mock = mocker.patch('modules.user_profiles.routes_admin.request')
    request_mock.json = {
        'user_id': expected_m_user_id,
        'first_name': expected_m_first_name,
        'last_name': expected_m_last_name,
        'joined_at': expected_m_joined_at,
        'status': expected_m_status,
    }

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock exists() validation
    user_9 = User()
    user_9.id = 9
    query_mock.return_value \
        .get.return_value = user_9

    db_mock = mocker.patch('modules.user_profiles.routes_admin.db')
    db_mock.add.return_value = None
    db_mock.commit.return_value = None

    result = post_user_profiles()

    assert result[1] == expected_status
    assert 'user_profile' in result[0].json
    assert len(result[0].json['user_profile']) == expected_m_length
    assert result[0].json['user_profile']['id'] == expected_m_id
    assert result[0].json['user_profile']['user_id'] == expected_m_user_id
    assert result[0].json['user_profile']['first_name'] == \
        expected_m_first_name
    assert result[0].json['user_profile']['last_name'] == expected_m_last_name
    assert result[0].json['user_profile']['joined_at'] == expected_m_joined_at
    assert result[0].json['user_profile']['status'] == expected_m_status
    assert bool(re_datetime.match(
        result[0].json['user_profile']['status_changed_at']))
    assert result[0].json['user_profile']['created_at'] == \
        expected_m_created_at
    assert result[0].json['user_profile']['updated_at'] == \
        expected_m_updated_at
예제 #7
0
def test_get_auth_token_ok(app, mocker):
    expected_status = 200
    expected_r_expiration = 14400
    expected_r_user_id = 2
    expected_r_username = "******"

    user2 = User()
    user2.id = 2
    user2.username = '******'

    g_mock = mocker.patch('modules.users.routes_auth.g')
    g_mock.user = user2

    result = get_auth_token()

    assert result[1] == expected_status
    assert result[0].json['expiration'] == expected_r_expiration
    assert result[0].json['user_id'] == expected_r_user_id
    assert result[0].json['username'] == expected_r_username
    assert 'token' in result[0].json
예제 #8
0
def test_get_auth_token_route_ok(app, mocker, client):
    expected_status = 200
    expected_r_expiration = 14400
    expected_r_user_id = 2
    expected_r_username = "******"

    # mock db query
    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock app key authorization db query
    query_mock.return_value \
        .filter.return_value \
        .one.return_value = AppKey()

    role1 = Role()
    role1.id = 1
    role1.name = 'USER'
    role1.password_reset_days = 365
    role1.password_policy = True
    role1.password_reuse_history = 10

    user2 = User()
    user2.id = 2
    user2.username = expected_r_username
    user2.password = "******"
    user2.roles = [role1]

    # mock user login db query
    query_mock.return_value \
        .filter.return_value \
        .first.return_value = user2

    db_mock = mocker.patch('modules.users.authentication.db')
    db_mock.add.return_value = None
    db_mock.commit.return_value = None

    # mock user login
    auth_mock = mocker.patch('modules.users.Authentication.is_account_locked')
    auth_mock.return_value = False

    credentials = base64.b64encode(
        'user2:user2pass'.encode('ascii')).decode('utf-8')

    response = client.get("/token?app_key=123",
                          headers={"Authorization": f"Basic {credentials}"})

    assert response.status_code == expected_status
    assert response.json['expiration'] == expected_r_expiration
    assert response.json['user_id'] == expected_r_user_id
    assert response.json['username'] == expected_r_username
    assert 'token' in response.json
예제 #9
0
def test_post_user_route_ok(app, mocker, client):
    expected_status = 201
    expected_m_length = 9
    expected_m_id = None
    expected_m_user_id = 9
    expected_m_first_name = "Service"
    expected_m_last_name = "Account"
    expected_m_joined_at = "2019-02-04T00:00:00+0000"
    expected_m_status = UserProfile.STATUS_ENABLED
    expected_m_created_at = None
    expected_m_updated_at = None
    # @todo: timezone
    re_datetime = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$")

    data = {
        'user_id': expected_m_user_id,
        'first_name': expected_m_first_name,
        'last_name': expected_m_last_name,
        'joined_at': expected_m_joined_at,
        'status': expected_m_status,
    }

    query_mock = mocker.patch('flask_sqlalchemy._QueryProperty.__get__')

    # mock app key authorization db query
    query_mock.return_value \
        .filter.return_value \
        .one.return_value = AppKey()

    # mock user login db query
    role2 = Role()
    role2.id = 2
    role2.name = 'SUPER_ADMIN'
    role2.password_reset_days = 365

    admin1 = Administrator()
    admin1.id = 1
    admin1.password = '******'
    admin1.roles = [role2]

    query_mock.return_value \
        .filter.return_value \
        .first.return_value = admin1

    auth_db_mock = mocker.patch('modules.administrators.authentication.db')
    auth_db_mock.add.return_value = None
    auth_db_mock.commit.return_value = None

    # mock exists() validation
    user_9 = User()
    user_9.id = 9
    query_mock.return_value \
        .get.return_value = user_9

    db_mock = mocker.patch('modules.user_profiles.routes_admin.db')
    db_mock.add.return_value = None
    db_mock.commit.return_value = None

    # mock user login
    auth_mock = mocker.patch(
        'modules.administrators.Authentication.is_account_locked')
    auth_mock.return_value = False

    credentials = base64.b64encode(
        'admin1:admin1pass'.encode('ascii')).decode('utf-8')

    response = client.post(
        "/user_profiles?app_key=123",
        json=data,
        headers={"Authorization": f"Basic {credentials}"})

    assert response.status_code == expected_status
    assert 'user_profile' in response.json
    assert len(response.json['user_profile']) == expected_m_length
    assert response.json['user_profile']['id'] == expected_m_id
    assert response.json['user_profile']['user_id'] == expected_m_user_id
    assert response.json['user_profile']['first_name'] == \
        expected_m_first_name
    assert response.json['user_profile']['last_name'] == expected_m_last_name
    assert response.json['user_profile']['joined_at'] == expected_m_joined_at
    assert response.json['user_profile']['status'] == expected_m_status
    assert bool(re_datetime.match(
        response.json['user_profile']['status_changed_at']))
    assert response.json['user_profile']['created_at'] == \
        expected_m_created_at
    assert response.json['user_profile']['updated_at'] == \
        expected_m_updated_at
예제 #10
0
def test_user_auth_token_fail(app):
    assert not User.verify_auth_token('badtoken')
예제 #11
0
def test_user_check_password_fail(app):
    user = User()
    user.password = '******'

    assert not user.check_password('testPass2')
예제 #12
0
def test_user_check_password_pass(app):
    user = User()
    user.password = '******'

    assert user.check_password('testPass1')
예제 #13
0
def put_password_reset():
    """Updates the current user's password using a reset code.

    :returns: JSON string of a `true` value; status code
    :rtype: (str, int)
    """
    # pylint: disable=too-many-branches

    # initialize user
    user = None

    # prep regex
    re_password = re.compile(UserAccountSchema.re_password)

    # validate data
    errors = {}
    if 'code' not in request.json or not request.json['code']:
        if 'code' not in errors:
            errors['code'] = []
        errors['code'].append("Missing data for required field.")
    if 'email' not in request.json or not request.json['email']:
        if 'email' not in errors:
            errors['email'] = []
        errors['email'].append("Missing data for required field.")

    if request.json.get('email'):
        temp_user = User(email=request.json.get('email'))
        if temp_user:
            user = User.query.filter(
                User.status == User.STATUS_ENABLED,
                User.roles.any(Role.id == 1),
                User.email_digest == temp_user.email_digest).first()
        if not user:
            if 'email' not in errors:
                errors['email'] = []
            errors['email'].append("Email address not found.")
    if user and request.json.get('code'):
        password_reset = PasswordReset.query.filter(
            PasswordReset.status == PasswordReset.STATUS_ENABLED,
            PasswordReset.code == request.json.get('code'),
            PasswordReset.user_id == user.id,
            PasswordReset.is_used == False,  # noqa; pylint: disable=singleton-comparison
            (PasswordReset.requested_at + timedelta(seconds=3600)) >=
            datetime.now()).first()
        if not password_reset:
            if 'code' not in errors:
                errors['code'] = []
            errors['code'].append("Invalid reset code.")

    if 'password1' not in request.json or not request.json['password1']:
        if 'password1' not in errors:
            errors['password1'] = []
        errors['password1'].append("Missing data for required field.")
    if ('password1' in request.json
            and not re_password.match(request.json['password1'])):
        if 'password1' not in errors:
            errors['password1'] = []
        errors['password1'].append("Please choose a more complex password.")

    if 'password2' not in request.json or not request.json['password2']:
        if 'password2' not in errors:
            errors['password2'] = []
        errors['password2'].append("Missing data for required field.")
    if 'password1' in request.json and 'password2' in request.json:
        if request.json['password1'] != request.json['password2']:
            if 'password2' not in errors:
                errors['password2'] = []
            errors['password2'].append("New passwords must match.")

    if errors:
        return jsonify({"error": errors}), 400

    # save password reset record
    password_reset.is_used = True

    # save user
    user.password = request.json.get('password1')
    db.session.commit()

    # response
    return jsonify({'success': 'true'}), 200
예제 #14
0
def post_password_request_reset_code():
    """Creates a password reset code for the current user, send via email.

    :returns: JSON string of a `true` value; status code
    :rtype: (str, int)
    """

    # initialize user
    user = None

    # validate data
    errors = {}
    if 'email' not in request.json or not request.json['email']:
        if 'email' not in errors:
            errors['email'] = []
        errors['email'].append("Missing data for required field.")
    if request.json.get('email'):
        temp_user = User(email=request.json.get('email'))
        if temp_user:
            user = User.query.filter(
                User.status == User.STATUS_ENABLED,
                User.roles.any(Role.id == 1),
                User.email_digest == temp_user.email_digest).first()
        if not user:
            if 'email' not in errors:
                errors['email'] = []
            errors['email'].append("Email address not found.")

    if errors:
        return jsonify({"error": errors}), 400

    # generate random seed
    now = datetime.now()
    unixtime = time.mktime(now.timetuple())
    hash_object = hashlib.sha256((str(unixtime) + str(os.getpid()) +
                                  User.CRYPT_DIGEST_SALT).encode('utf-8'))
    random_seed = hash_object.hexdigest()

    # save reset request
    password_reset = PasswordReset(user_id=user.id,
                                   code=RandomString.user_code(8, random_seed),
                                   is_used=False,
                                   requested_at=datetime.now(),
                                   ip_address=request.environ.get(
                                       'HTTP_X_REAL_IP', request.remote_addr),
                                   status=PasswordReset.STATUS_ENABLED,
                                   status_changed_at=datetime.now())
    db.session.add(password_reset)
    db.session.commit()

    # email notification
    notify = Notify(current_app.config['ENV'], db)
    response = notify.send(
        user,
        Notify.CHANNEL_EMAIL,
        'password-reset-code',
        name=user.profile.first_name if user.profile else 'User',
        code=password_reset.code)

    # response
    return jsonify({'success': 'true', 'sent': response}), 201
예제 #15
0
def post_user_account_step1():
    """User registration step 1.

    :returns: JSON string of the user's account information; status code
    :rtype: (str, int)
    """

    # pre-validate data
    errors = unique({}, User, User.username,
                    str(request.json.get('username')).lower().strip()
                    if request.json.get('username', None) else None)

    errors = unique_email(
        errors, User, User.email,
        str(request.json.get('email')).lower().strip() if request.json.get(
            'email', None) else None)

    errors, tos = exists(errors,
                         TermsOfService,
                         'tos_id',
                         request.json.get('tos_id', None),
                         missing_error="Please agree to the terms of service.")

    if (request.json.get('password', None)
            and request.json.get('password2', None)):
        if request.json.get('password') != request.json.get('password2'):
            errors['password2'] = ["Passwords must match."]

    # validate data
    try:
        data = UserAccountSchema(exclude=(
            'first_name',
            'last_name',
        )).load(request.json)
    except ValidationError as err:
        errors = dict(list(errors.items()) + list(err.messages.items()))

    # return any errors
    if errors:
        return jsonify({"error": errors}), 400

    # save user
    user = User(username=data['username'].lower().strip(),
                email=data['email'].lower().strip(),
                password=data['password'],
                is_verified=False,
                status=User.STATUS_ENABLED,
                status_changed_at=datetime.now())

    user_role = Role.query.filter(Role.name == 'USER').first()
    if user_role:
        user.roles.append(user_role)

    db.session.add(user)

    # save user terms of service
    user_tos = UserTermsOfService(user=user,
                                  terms_of_service=tos,
                                  accept_date=datetime.now(),
                                  ip_address=request.environ.get(
                                      'HTTP_X_REAL_IP', request.remote_addr))
    db.session.add(user_tos)

    # save password history
    pass_history = UserPasswordHistory(user=user,
                                       password=user.password,
                                       set_date=datetime.now())
    db.session.add(pass_history)

    db.session.commit()

    # prep output
    output = {
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'password_changed_at': user.password_changed_at,
        'is_verified': user.is_verified,
        'first_name': None,
        'last_name': None,
        'joined_at': None,
    }

    # response
    return jsonify({'user_account': UserAccountSchema().dump(output)}), 201