Beispiel #1
0
    def post():
        """Post a new user using the request body (which will contain a JWT).

        If the user already exists, update the name.
        """
        token = g.jwt_oidc_token_info

        try:
            request_json = request.get_json(silent=True)
            # For BCeID users validate schema.
            if token.get('loginSource', None) == LoginSource.BCEID.value and request_json is not None:
                valid_format, errors = schema_utils.validate(request_json, 'user')
                if not valid_format:
                    return {'message': schema_utils.serialize(errors)}, http_status.HTTP_400_BAD_REQUEST

            user = UserService.save_from_jwt_token(token, request_json)
            response, status = user.as_dict(), http_status.HTTP_201_CREATED
            # Add the user to public_users group if the user doesn't have public_user group
            KeycloakService.join_users_group(token)
            # If the user doesn't have account_holder role check if user is part of any orgs and add to the group
            if token.get('loginSource', '') in \
                    (LoginSource.BCSC.value, LoginSource.BCROS.value, LoginSource.BCEID.value) \
                    and Role.ACCOUNT_HOLDER.value not in token.get('roles', []) \
                    and len(OrgService.get_orgs(user.identifier, [Status.ACTIVE.value])) > 0:
                KeycloakService.join_account_holders_group()

        except BusinessException as exception:
            response, status = {'code': exception.code, 'message': exception.message}, exception.status_code
        return response, status
Beispiel #2
0
    def post():
        """Post a new user using the request body (which will contain a JWT).

        If the user already exists, update the name.
        """
        token = g.jwt_oidc_token_info

        try:
            request_json = request.get_json(silent=True)
            # For BCeID users validate schema.
            if token.get('loginSource', None) == LoginSource.BCEID.value and request_json is not None:
                valid_format, errors = schema_utils.validate(request_json, 'user')
                if not valid_format:
                    return {'message': schema_utils.serialize(errors)}, http_status.HTTP_400_BAD_REQUEST

            user = UserService.save_from_jwt_token(token, request_json)
            response, status = user.as_dict(), http_status.HTTP_201_CREATED
            # Add the user to public_users group if the user doesn't have public_user group
            if token.get('loginSource', '') != LoginSource.STAFF.value:
                KeycloakService.join_users_group(token)
            # For anonymous users, there are no invitation process for members,
            # so whenever they login perform this check and add them to corresponding groups
            if token.get('loginSource', '') == LoginSource.BCROS.value:
                if len(OrgService.get_orgs(user.identifier, [Status.ACTIVE.value])) > 0:
                    KeycloakService.join_account_holders_group()

        except BusinessException as exception:
            response, status = {'code': exception.code, 'message': exception.message}, exception.status_code
        return response, status
Beispiel #3
0
    def reset(token_info: Dict):
        """Cleanup all the data from all tables create by the provided user id."""
        if Role.TESTER.value in token_info.get('realm_access').get('roles'):  # pylint: disable=too-many-nested-blocks
            user = UserModel.find_by_jwt_token(token_info)
            if user:
                # TODO need to find a way to avoid using protected function
                for model_class in db.Model._decl_class_registry.values():  # pylint:disable=protected-access
                    # skip version classes
                    if not (hasattr(model_class, 'transaction_id')
                            and hasattr(model_class, 'end_transaction_id')):
                        if hasattr(model_class, 'created_by_id'):
                            for model in model_class.query.filter_by(
                                    created_by_id=user.id).all():
                                model.reset()
                        if hasattr(model_class, 'modified_by_id'):
                            for model in model_class.query.filter_by(
                                    modified_by_id=user.id).all():
                                model.reset()
                # check the user is still exists or not
                user = UserModel.find_by_jwt_token(token_info)
                if user:
                    user.modified_by = None
                    user.modified_by_id = None
                    user.reset()

                # Reset opt from keycloak if from BCEID
                login_source = token_info.get('loginSource', None)

                if login_source == LoginSource.BCEID.value:
                    KeycloakService.reset_otp(token_info.get('sub'))
def test_remove_member_removes_group_to_the_user(session, monkeypatch):  # pylint:disable=unused-argument
    """Assert that accepting an invite adds group to the user."""
    # Create a user in keycloak
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user = keycloak_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user.id))

    # Patch token info
    def token_info():  # pylint: disable=unused-argument; mocks of library methods
        return {
            'sub': str(kc_user.id),
            'username': '******',
            'realm_access': {
                'roles': [
                    'edit'
                ]
            },
            'product_code': ProductCode.BUSINESS.value
        }

    monkeypatch.setattr('auth_api.services.keycloak.KeycloakService._get_token_info', token_info)
    org = OrgService.create_org(TestOrgInfo.org1, user_id=user.id)
    # Create another user
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user2 = keycloak_service.get_user_by_username(request.user_name)
    user2 = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user2.id))

    # Add a membership to the user for the org created
    factory_membership_model(user2.id, org.as_dict().get('id'), member_type='COORDINATOR', member_status=4)

    # Add a product to org
    factory_product_model(org.as_dict().get('id'), product_code=ProductCode.BUSINESS.value)

    # Find the membership and update to ACTIVE
    membership = MembershipService.get_membership_for_org_and_user(org.as_dict().get('id'), user2.id)
    active_membership_status = MembershipStatusCodeModel.get_membership_status_by_code(Status.ACTIVE.name)
    updated_fields = {'membership_status': active_membership_status}
    MembershipService(membership).update_membership(updated_fields=updated_fields, token_info=token_info())

    user_groups = keycloak_service.get_user_groups(user_id=kc_user2.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS in groups

    # Find the membership and update to INACTIVE
    active_membership_status = MembershipStatusCodeModel.get_membership_status_by_code(Status.INACTIVE.name)
    updated_fields = {'membership_status': active_membership_status}
    MembershipService(membership).update_membership(updated_fields=updated_fields, token_info=token_info())

    user_groups = keycloak_service.get_user_groups(user_id=kc_user2.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS not in groups
Beispiel #5
0
def test_create_user_add_membership_reenable(session, auth_mock, keycloak_mock,
                                             monkeypatch):  # pylint:disable=unused-argument
    """Assert that an admin can add a member."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    user = factory_user_model()
    factory_membership_model(user.id, org.id)
    factory_product_model(org.id, product_code=ProductCode.DIR_SEARCH.value)
    claims = TestJwtClaims.get_test_real_user(user.keycloak_guid)

    patch_token_info(claims, monkeypatch)
    anon_member = TestAnonymousMembership.generate_random_user(USER)
    membership = [anon_member]
    users = UserService.create_user_and_add_membership(membership, org.id)
    user_name = IdpHint.BCROS.value + '/' + membership[0]['username']
    assert len(users['users']) == 1
    assert users['users'][0]['username'] == user_name
    assert users['users'][0]['type'] == Role.ANONYMOUS_USER.name

    members = MembershipModel.find_members_by_org_id(org.id)

    # staff didnt create members..so count is count of owner+other 1 member
    assert len(members) == 2

    # assert cant be readded
    users = UserService.create_user_and_add_membership(membership, org.id)
    assert users['users'][0]['http_status'] == 409
    assert users['users'][0]['error'] == 'The username is already taken'

    # deactivate everything and try again

    anon_user = UserModel.find_by_username(user_name)
    anon_user.status = Status.INACTIVE.value
    anon_user.save()
    membership_model = MembershipModel.find_membership_by_userid(anon_user.id)
    membership_model.status = Status.INACTIVE.value

    update_user_request = KeycloakUser()
    update_user_request.user_name = membership[0]['username']
    update_user_request.enabled = False
    KeycloakService.update_user(update_user_request)

    org2 = factory_org_model(org_info=TestOrgInfo.org_anonymous_2,
                             org_type_info={'code': 'BASIC'},
                             org_status_info=None,
                             payment_type_info=None)

    factory_membership_model(user.id, org2.id)
    factory_product_model(org2.id, product_code=ProductCode.DIR_SEARCH.value)
    users = UserService.create_user_and_add_membership(membership, org2.id)
    assert users['users'][0]['http_status'] == 409
    assert users['users'][0]['error'] == 'The username is already taken'

    # add to same org.Should work
    users = UserService.create_user_and_add_membership(membership, org.id)
    assert len(users['users']) == 1
    assert users['users'][0][
        'username'] == IdpHint.BCROS.value + '/' + membership[0]['username']
    assert users['users'][0]['type'] == Role.ANONYMOUS_USER.name
Beispiel #6
0
def test_create_user_and_add_same_user_name_error_in_kc(session, auth_mock,
                                                        keycloak_mock):  # pylint:disable=unused-argument
    """Assert that same user name cannot be added twice."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    membership = [TestAnonymousMembership.generate_random_user(ADMIN)]
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    request.user_name = membership[0]['username']
    keycloak_service.add_user(request)
    users = UserService.create_user_and_add_membership(membership, org.id, single_mode=True)
    assert users['users'][0]['http_status'] == 409
    assert users['users'][0]['error'] == 'The username is already taken'
Beispiel #7
0
    def post():
        """Post a new user using the request body (which will contain a JWT).

        If the user already exists, update the name.
        """
        token = g.jwt_oidc_token_info

        try:
            response, status = UserService.save_from_jwt_token(token).as_dict(), http_status.HTTP_201_CREATED
            KeycloakService.join_public_users_group(g.jwt_oidc_token_info)
        except BusinessException as exception:
            response, status = {'code': exception.code, 'message': exception.message}, exception.status_code
        return response, status
Beispiel #8
0
def test_add_back_a_delete_bcros(client, jwt, session, keycloak_mock):
    """Assert different conditions of user deletion."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    user = factory_user_model(user_info=TestUserInfo.user_bcros_active)
    factory_membership_model(user.id, org.id)
    factory_product_model(org.id, product_code=ProductCode.DIR_SEARCH.value)
    owner_claims = TestJwtClaims.get_test_real_user(user.keycloak_guid)
    member = TestAnonymousMembership.generate_random_user(USER)
    membership = [
        member,
        TestAnonymousMembership.generate_random_user(COORDINATOR)
    ]
    UserService.create_user_and_add_membership(membership,
                                               org.id,
                                               token_info=owner_claims)
    headers = factory_auth_header(jwt=jwt, claims=owner_claims)
    member_user_id = IdpHint.BCROS.value + '/' + member.get('username')
    rv = client.delete(f'/api/v1/users/{member_user_id}',
                       headers=headers,
                       content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT
    kc_user = KeycloakService.get_user_by_username(member.get('username'))
    assert kc_user.enabled is False
    user_model = UserService.find_by_username(member_user_id)
    assert user_model.as_dict().get('user_status') == UserStatus.INACTIVE.value
    membership = MembershipModel.find_membership_by_userid(
        user_model.identifier)
    assert membership.status == Status.INACTIVE.value
Beispiel #9
0
    def _create_consumer(cls, name, org, env):
        """Create an API Gateway consumer."""
        consumer_endpoint: str = cls._get_api_consumer_endpoint(env)
        gw_api_key = cls._get_api_gw_key(env)
        email = cls._get_email_id(org.id, env)
        client_rep = generate_client_representation(org.id, current_app.config.get('API_GW_KC_CLIENT_ID_PATTERN'), env)
        KeycloakService.create_client(client_rep)
        service_account = KeycloakService.get_service_account_user(client_rep.get('id'))

        KeycloakService.add_user_to_group(service_account.get('id'),
                                          GROUP_API_GW_USERS if env == 'prod' else GROUP_API_GW_SANDBOX_USERS)
        KeycloakService.add_user_to_group(service_account.get('id'), GROUP_ACCOUNT_HOLDERS)
        # Create a consumer with the keycloak client id and secret
        create_consumer_payload = dict(email=email,
                                       firstName=org.name,
                                       lastName=org.branch_name or 'BCR',
                                       userName=org.name,
                                       clientId=client_rep.get('clientId'),
                                       clientSecret=client_rep.get('secret'),
                                       apiAccess=['ALL_API'],
                                       apiKeyName=name)
        api_key_response = RestService.post(
            f'{consumer_endpoint}/mc/v1/consumers',
            additional_headers={'x-apikey': gw_api_key},
            data=create_consumer_payload,
            generate_token=False
        )
        return api_key_response
Beispiel #10
0
def test_reset_bceid_user(session, auth_mock):  # pylint: disable=unused-argument
    """Assert that reset data from a bceid user."""
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_by_user_info(
        TestJwtClaims.tester_bceid_role)
    keycloak_service.add_user(request, return_if_exists=True)
    user = keycloak_service.get_user_by_username(request.user_name)
    assert user is not None
    user_id = user.id
    user_with_token = TestUserInfo.user_bceid_tester
    user_with_token['keycloak_guid'] = user_id
    user = factory_user_model(user_info=user_with_token)
    org = factory_org_model(user_id=user.id)

    response = ResetDataService.reset(
        TestJwtClaims.get_test_user(user_id, 'BCEID'))
    assert response is None

    found_org = OrgService.find_by_org_id(org.id)
    assert found_org is None
Beispiel #11
0
    def post():
        """Post a new user using the request body (which will contain a JWT).

        If the user already exists, update the name.
        """
        token = g.jwt_oidc_token_info

        try:
            user = UserService.save_from_jwt_token(token)
            response, status = user.as_dict(), http_status.HTTP_201_CREATED
            # Add the user to public_users group if the user doesn't have public_user group
            KeycloakService.join_users_group(g.jwt_oidc_token_info)
            # If the user doesn't have account_holder role check if user is part of any orgs and add to the group
            if token.get('loginSource', '') in (BCSC, BCROS) \
                    and Role.ACCOUNT_HOLDER.value not in token.get('roles', []) \
                    and len(OrgService.get_orgs(user.identifier, [Status.ACTIVE.value])) > 0:
                KeycloakService.join_account_holders_group()

        except BusinessException as exception:
            response, status = {'code': exception.code, 'message': exception.message}, exception.status_code
        return response, status
Beispiel #12
0
def test_delete_does_not_remove_user_from_account_holder_group(session, monkeypatch,
                                                               auth_mock):  # pylint:disable=unused-argument
    """Assert that if the user has multiple Orgs, and deleting one doesn't remove account holders group."""
    # Create a user in keycloak
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user = keycloak_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user.id))

    # Patch token info
    def token_info():  # pylint: disable=unused-argument; mocks of library methods
        return {
            'sub': str(kc_user.id),
            'username': '******',
            'realm_access': {
                'roles': [
                ]
            }
        }

    monkeypatch.setattr('auth_api.services.keycloak.KeycloakService._get_token_info', token_info)
    org1 = OrgService.create_org(TestOrgInfo.org1, user_id=user.id)
    OrgService.create_org(TestOrgInfo.org2, user_id=user.id)
    OrgService.delete_org(org1.as_dict().get('id'), token_info())

    user_groups = keycloak_service.get_user_groups(user_id=kc_user.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS in groups
Beispiel #13
0
def test_create_org_adds_user_to_account_holders_group(session, monkeypatch):  # pylint:disable=unused-argument
    """Assert that an Org creation adds the user to account holders group."""
    # Create a user in keycloak
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user = keycloak_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user.id))

    # Patch token info
    def token_info():  # pylint: disable=unused-argument; mocks of library methods
        return {
            'sub': str(kc_user.id),
            'username': '******',
            'realm_access': {
                'roles': [
                ]
            }
        }

    monkeypatch.setattr('auth_api.services.keycloak.KeycloakService._get_token_info', token_info)
    OrgService.create_org(TestOrgInfo.org1, user_id=user.id)

    user_groups = keycloak_service.get_user_groups(user_id=kc_user.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS in groups
Beispiel #14
0
def test_delete_otp_for_user(session, auth_mock, keycloak_mock):
    """Assert that the otp cant be reset."""
    kc_service = KeycloakService()
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    admin_user = factory_user_model()
    factory_membership_model(admin_user.id, org.id)
    admin_claims = TestJwtClaims.get_test_real_user(admin_user.keycloak_guid)
    membership = [TestAnonymousMembership.generate_random_user(USER)]
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    request.user_name = membership[0]['username']
    keycloak_service.add_user(request)
    user = kc_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_bceid_user_with_kc_guid(user.id))
    factory_membership_model(user.id, org.id)
    UserService.delete_otp_for_user(user.username, admin_claims)
    user1 = kc_service.get_user_by_username(request.user_name)
    assert 'CONFIGURE_TOTP' in json.loads(user1.value()).get('requiredActions')
Beispiel #15
0
    def create_key(cls, org_id: int, request_json: Dict[str, str]):
        """Create a key for the account."""
        current_app.logger.debug('<create_key ')
        env = request_json.get('environment', 'sandbox')
        name = request_json.get('keyName')
        org: OrgModel = OrgModel.find_by_id(org_id)
        # first find if there is a consumer created for this account.
        consumer_endpoint: str = current_app.config.get('API_GW_CONSUMERS_API_URL')
        gw_api_key = current_app.config.get('API_GW_KEY') if env == 'prod' else current_app.config.get(
            'API_GW_NON_PROD_KEY')
        email = cls._get_email_id(org_id)

        if not org.has_api_access:  # If the account doesn't have api access, add it
            client_rep = generate_client_representation(org_id, current_app.config.get('API_GW_KC_CLIENT_ID_PATTERN'))
            KeycloakService.create_client(client_rep)
            service_account = KeycloakService.get_service_account_user(client_rep.get('id'))
            KeycloakService.add_user_to_group(service_account.get('id'), GROUP_API_GW_USERS)
            KeycloakService.add_user_to_group(service_account.get('id'), GROUP_ACCOUNT_HOLDERS)

            # Create a consumer with the keycloak client id and secret
            create_consumer_payload = dict(email=email,
                                           firstName=org.name,
                                           lastName=org.branch_name or 'BCR',
                                           userName=org.name,
                                           clientId=client_rep.get('clientId'),
                                           clientSecret=client_rep.get('secret'),
                                           apiAccess=['ALL_API'],
                                           apiKeyName=name)
            api_key_response = RestService.post(
                f'{consumer_endpoint}/mc/v1/consumers',
                additional_headers={'x-apikey': gw_api_key},
                data=create_consumer_payload,
                generate_token=False
            )
            org.has_api_access = True
            org.save()
        else:
            # Create additional API Key if a consumer exists
            api_key_response = RestService.post(
                f'{consumer_endpoint}/mc/v1/consumers/{email}/apikeys',
                additional_headers={'x-apikey': gw_api_key},
                data=dict(
                    apiAccess=['ALL_API'],
                    apiKeyName=name
                ),
                generate_token=False
            )

        return api_key_response.json()
Beispiel #16
0
def test_create_org_adds_user_to_account_holders_group(session, monkeypatch):  # pylint:disable=unused-argument
    """Assert that an Org creation adds the user to account holders group."""
    # Create a user in keycloak
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user = keycloak_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user.id))

    patch_token_info({'sub': user.keycloak_guid}, monkeypatch)
    OrgService.create_org(TestOrgInfo.org1, user_id=user.id)

    user_groups = keycloak_service.get_user_groups(user_id=kc_user.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS in groups
Beispiel #17
0
def test_delete_does_not_remove_user_from_account_holder_group(session, monkeypatch,
                                                               auth_mock):  # pylint:disable=unused-argument
    """Assert that if the user has multiple Orgs, and deleting one doesn't remove account holders group."""
    # Create a user in keycloak
    keycloak_service = KeycloakService()
    request = KeycloakScenario.create_user_request()
    keycloak_service.add_user(request, return_if_exists=True)
    kc_user = keycloak_service.get_user_by_username(request.user_name)
    user = factory_user_model(TestUserInfo.get_user_with_kc_guid(kc_guid=kc_user.id))

    patch_token_info({'sub': user.keycloak_guid}, monkeypatch)
    patch_pay_account_delete(monkeypatch)
    org1 = OrgService.create_org(TestOrgInfo.org1, user_id=user.id)
    OrgService.create_org(TestOrgInfo.org2, user_id=user.id)
    OrgService.delete_org(org1.as_dict().get('id'))

    user_groups = keycloak_service.get_user_groups(user_id=kc_user.id)
    groups = []
    for group in user_groups:
        groups.append(group.get('name'))
    assert GROUP_ACCOUNT_HOLDERS in groups
Beispiel #18
0
    'source': 'PASSCODE'
}

ADD_USER_REQUEST_SAME_EMAIL = {
    'username': '******',
    'password': '******',
    'firstname': '112',
    'lastname': 'test',
    'email': '*****@*****.**',
    'enabled': True,
    'user_type': ['/test', '/basic/editor'],
    'corp_type': 'CP',
    'source': 'PASSCODE'
}

keycloak_service = KeycloakService()


def test_keycloak_add_user(session):
    """Add user to Keycloak. Assert return a user with the same username as the username in request."""
    user = keycloak_service.add_user(ADD_USER_REQUEST)
    assert user.get('username') == ADD_USER_REQUEST.get('username')
    keycloak_service.delete_user_by_username(ADD_USER_REQUEST.get('username'))


def test_keycloak_add_user_duplicate_email(session):
    """Add user with duplicate email. Assert response is None, error code is data conflict."""
    keycloak_service.add_user(ADD_USER_REQUEST)
    response = None
    try:
        response = keycloak_service.add_user(ADD_USER_REQUEST_SAME_EMAIL)
import json
import uuid
from random import randint

from auth_api import status as http_status
from auth_api.schemas import utils as schema_utils
from auth_api.services.keycloak import KeycloakService
from auth_api.utils.constants import IdpHint

from config import get_named_config
from tests.utilities.factory_scenarios import BulkUserTestScenario, TestJwtClaims, \
    TestOrgInfo
from tests.utilities.factory_utils import (factory_auth_header,
                                           factory_invitation_anonymous)

KEYCLOAK_SERVICE = KeycloakService()

CONFIG = get_named_config('testing')


def test_add_user(client, jwt, session):  # pylint:disable=unused-argument
    """Assert that a user can be POSTed."""
    headers = factory_auth_header(jwt=jwt,
                                  claims=TestJwtClaims.public_user_role)
    rv = client.post('/api/v1/users',
                     headers=headers,
                     content_type='application/json')
    assert rv.status_code == http_status.HTTP_201_CREATED
    assert schema_utils.validate(rv.json, 'anonymous_user_response')