Ejemplo n.º 1
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
Ejemplo n.º 2
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
Ejemplo n.º 3
0
def test_create_user_and_add_membership_member_error_skip_auth_mode(session, auth_mock,
                                                                    keycloak_mock):  # pylint:disable=unused-argument
    """Assert that an member cannot be added as anonymous in single_mode mode."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    membership = [TestAnonymousMembership.generate_random_user(USER)]
    with pytest.raises(BusinessException) as exception:
        UserService.create_user_and_add_membership(membership, org.id,
                                                   single_mode=True)
    assert exception.value.code == Error.INVALID_USER_CREDENTIALS.name
Ejemplo n.º 4
0
def test_reset_password(client, jwt, session, keycloak_mock):  # pylint:disable=unused-argument
    """Assert that an anonymous admin can be Patched."""
    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)
    admin = TestAnonymousMembership.generate_random_user(COORDINATOR)
    membership = [member, admin]
    UserService.create_user_and_add_membership(membership,
                                               org.id,
                                               token_info=owner_claims)
    owner_headers = factory_auth_header(jwt=jwt, claims=owner_claims)
    member_username = IdpHint.BCROS.value + '/' + member['username']
    admin_username = IdpHint.BCROS.value + '/' + admin['username']
    admin_claims = TestJwtClaims.get_test_real_user(
        uuid.uuid4(), admin_username, access_ype=AccessType.ANONYMOUS.value)
    admin_headers = factory_auth_header(jwt=jwt, claims=admin_claims)
    member_claims = TestJwtClaims.get_test_real_user(
        uuid.uuid4(), member_username, access_ype=AccessType.ANONYMOUS.value)
    member_headers = factory_auth_header(jwt=jwt, claims=member_claims)
    # set up JWTS for member and admin
    client.post('/api/v1/users',
                headers=admin_headers,
                content_type='application/json')
    client.post('/api/v1/users',
                headers=member_headers,
                content_type='application/json')

    # reset password of admin by owner
    input_data = json.dumps({
        'username': admin_username,
        'password': '******'
    })

    rv = client.patch(f'/api/v1/users/{admin_username}',
                      headers=owner_headers,
                      data=input_data,
                      content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT

    # member cant reset password
    rv = client.patch(f'/api/v1/users/{admin_username}',
                      headers=member_headers,
                      data=input_data,
                      content_type='application/json')
    assert rv.status_code == http_status.HTTP_403_FORBIDDEN

    # admin cant reset password
    rv = client.patch(f'/api/v1/users/{admin_username}',
                      headers=admin_headers,
                      data=input_data,
                      content_type='application/json')
    assert rv.status_code == http_status.HTTP_403_FORBIDDEN
Ejemplo n.º 5
0
def test_create_user_and_add_membership_admin_bulk_mode_unauthorised(session, auth_mock,
                                                                     keycloak_mock):  # pylint:disable=unused-argument
    """Assert that bulk operation cannot be performed by unauthorised users."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    user = factory_user_model()
    factory_membership_model(user.id, org.id)
    membership = [TestAnonymousMembership.generate_random_user(USER)]

    with pytest.raises(HTTPException) as excinfo:
        UserService.create_user_and_add_membership(membership, org.id, token_info=TestJwtClaims.public_user_role)
    assert excinfo.value.code == 403
Ejemplo n.º 6
0
def test_create_user_and_add_membership_multiple_error_skip_auth_mode(
        session, auth_mock, keycloak_mock):  # pylint:disable=unused-argument
    """Assert that multiple user cannot be created  in skip_auth mode."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    membership = [
        TestAnonymousMembership.generate_random_user(MEMBER),
        TestAnonymousMembership.generate_random_user(ADMIN)
    ]
    with pytest.raises(BusinessException) as exception:
        UserService.create_user_and_add_membership(
            membership, org.id, TestJwtClaims.public_user_role, skip_auth=True)
    assert exception.value.code == Error.INVALID_USER_CREDENTIALS.name
Ejemplo n.º 7
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(OWNER)]
    UserService.create_user_and_add_membership(membership,
                                               org.id,
                                               skip_auth=True)
    with pytest.raises(BusinessException) as exception:
        UserService.create_user_and_add_membership(membership,
                                                   org.id,
                                                   skip_auth=True)
    assert exception.value.code == Error.FAILED_ADDING_USER_IN_KEYCLOAK.name
Ejemplo n.º 8
0
def test_delete_bcros_valdiations(client, jwt, session, keycloak_mock):
    """Assert different conditions of user deletion."""
    admin_user = TestUserInfo.user_bcros_active
    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)
    owner_claims = TestJwtClaims.get_test_real_user(user.keycloak_guid)
    member = TestAnonymousMembership.generate_random_user(MEMBER)
    admin = TestAnonymousMembership.generate_random_user(ADMIN)
    membership = [member, admin]
    UserService.create_user_and_add_membership(membership, org.id, token_info=owner_claims)
    owner_headers = factory_auth_header(jwt=jwt, claims=owner_claims)
    member_username = IdpHint.BCROS.value + '/' + member['username']
    admin_username = IdpHint.BCROS.value + '/' + admin['username']
    admin_claims = TestJwtClaims.get_test_real_user(uuid.uuid4(), admin_username, access_ype=AccessType.ANONYMOUS.value)
    admin_headers = factory_auth_header(jwt=jwt, claims=admin_claims)
    member_claims = TestJwtClaims.get_test_real_user(uuid.uuid4(), member_username,
                                                     access_ype=AccessType.ANONYMOUS.value)
    member_headers = factory_auth_header(jwt=jwt, claims=member_claims)
    # set up JWTS for member and admin
    client.post('/api/v1/users', headers=admin_headers, content_type='application/json')
    client.post('/api/v1/users', headers=member_headers, content_type='application/json')
    # delete only owner ;failure
    rv = client.delete(f"/api/v1/users/{admin_user['username']}", headers=owner_headers,
                       content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # admin trying to delete member: Failure
    rv = client.delete(f'/api/v1/users/{member_username}', headers=admin_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # member delete admin: failure
    rv = client.delete(f'/api/v1/users/{admin_username}', headers=member_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # a self delete ;should work ;mimics leave team for anonymous user
    rv = client.delete(f'/api/v1/users/{member_username}', headers=member_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT

    rv = client.delete(f'/api/v1/users/{admin_username}', headers=admin_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT

    # add one more admin
    new_owner = TestAnonymousMembership.generate_random_user(OWNER)
    membership = [new_owner]
    UserService.create_user_and_add_membership(membership, org.id, token_info=owner_claims)
    rv = client.delete(f"/api/v1/users/{IdpHint.BCROS.value + '/' + new_owner['username']}", headers=owner_headers,
                       content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT
Ejemplo n.º 9
0
def test_create_user_and_add_same_user_name_error_in_db(
        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)
    user = factory_user_model(TestUserInfo.user_bcros)
    factory_membership_model(user.id, org.id)
    new_members = TestAnonymousMembership.generate_random_user(OWNER)
    new_members['username'] = user.username.replace(f'{IdpHint.BCROS.value}/',
                                                    '')
    membership = [new_members]
    with pytest.raises(BusinessException) as exception:
        UserService.create_user_and_add_membership(membership,
                                                   org.id,
                                                   skip_auth=True)
    assert exception.value.code == Error.DATA_ALREADY_EXISTS.name
Ejemplo n.º 10
0
def test_create_user_and_add_membership_admin_bulk_mode_multiple(
        session, auth_mock, keycloak_mock):  # pylint:disable=unused-argument
    """Assert that an admin can add a group of members."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    user = factory_user_model()
    factory_membership_model(user.id, org.id)
    claims = TestJwtClaims.get_test_real_user(user.keycloak_guid)
    membership = [
        TestAnonymousMembership.generate_random_user(MEMBER),
        TestAnonymousMembership.generate_random_user(ADMIN)
    ]
    users = UserService.create_user_and_add_membership(membership,
                                                       org.id,
                                                       token_info=claims)

    assert len(users['users']) == 2
    assert users['users'][0]['username'] == membership[0]['username']
    assert users['users'][0]['type'] == 'ANONYMOUS'
    assert users['users'][1]['username'] == membership[1]['username']
    assert users['users'][1]['type'] == 'ANONYMOUS'

    members = MembershipModel.find_members_by_org_id(org.id)

    # staff didnt create members..so count is count of owner+other 2 members
    assert len(members) == 3
Ejemplo n.º 11
0
def test_create_user_and_add_transaction_membership_1(session, auth_mock,
                                                      keycloak_mock):  # pylint:disable=unused-argument
    """Assert transactions works fine."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    membership = [TestAnonymousMembership.generate_random_user(ADMIN)]
    with patch('auth_api.models.User.flush',
               side_effect=Exception('mocked error')):
        users = UserService.create_user_and_add_membership(membership,
                                                           org.id,
                                                           single_mode=True)

    user_name = IdpHint.BCROS.value + '/' + membership[0]['username']
    assert len(users['users']) == 1
    assert users['users'][0]['username'] == membership[0]['username']
    assert users['users'][0]['http_status'] == 500
    assert users['users'][0]['error'] == 'Adding User Failed'

    # make sure no records are created
    user = UserModel.find_by_username(user_name)
    assert user is None
    user = UserModel.find_by_username(membership[0]['username'])
    assert user is None
    members = MembershipModel.find_members_by_org_id(org.id)
    # only one member should be there since its a STAFF created org
    assert len(members) == 0
Ejemplo n.º 12
0
def test_create_user_and_add_membership_admin_bulk_mode_multiple(
        session, auth_mock, keycloak_mock, monkeypatch):  # pylint:disable=unused-argument
    """Assert that an admin can add a group of members."""
    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)
    membership = [
        TestAnonymousMembership.generate_random_user(USER),
        TestAnonymousMembership.generate_random_user(COORDINATOR)
    ]

    patch_token_info(claims, monkeypatch)
    users = UserService.create_user_and_add_membership(membership, org.id)

    assert len(users['users']) == 2
    assert users['users'][0][
        'username'] == IdpHint.BCROS.value + '/' + membership[0]['username']
    assert users['users'][0]['type'] == Role.ANONYMOUS_USER.name
    assert users['users'][1][
        'username'] == IdpHint.BCROS.value + '/' + membership[1]['username']
    assert users['users'][1]['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 2 members
    assert len(members) == 3
Ejemplo n.º 13
0
def test_create_user_and_add_same_user_name_error_in_db(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)
    user = factory_user_model(TestUserInfo.user_bcros)
    factory_membership_model(user.id, org.id)
    new_members = TestAnonymousMembership.generate_random_user(ADMIN)
    new_members['username'] = user.username.replace(f'{IdpHint.BCROS.value}/', '')
    membership = [new_members]
    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'
Ejemplo n.º 14
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'
Ejemplo n.º 15
0
def test_reset_password(session, auth_mock, keycloak_mock):  # pylint:disable=unused-argument
    """Assert that the password can be changed."""
    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)
    membership = [TestAnonymousMembership.generate_random_user(USER)]
    users = UserService.create_user_and_add_membership(membership, org.id, token_info=claims)
    user_name = users['users'][0]['username']
    user_info = {'username': user_name, 'password': '******'}
    kc_user = UserService.reset_password_for_anon_user(user_info, user_name, claims)
    # cant assert anything else since password wont be gotten back
    assert kc_user.user_name == user_name.replace(f'{IdpHint.BCROS.value}/', '').lower()
Ejemplo n.º 16
0
def test_reset_password_by_member(session, auth_mock, keycloak_mock):  # pylint:disable=unused-argument
    """Assert that the password cant be changed by 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)
    admin_claims = TestJwtClaims.get_test_real_user(user.keycloak_guid)
    membership = [TestAnonymousMembership.generate_random_user(USER)]
    users = UserService.create_user_and_add_membership(membership, org.id, token_info=admin_claims)
    user_name = users['users'][0]['username']
    user_info = {'username': user_name, 'password': '******'}
    with pytest.raises(HTTPException) as excinfo:
        UserService.reset_password_for_anon_user(user_info, user_name, token_info=TestJwtClaims.public_user_role)
        assert excinfo.exception.code == 403
Ejemplo n.º 17
0
def test_create_user_and_add_membership_owner_skip_auth_mode(session, auth_mock,
                                                             keycloak_mock):  # pylint:disable=unused-argument
    """Assert that an owner can be added as anonymous."""
    org = factory_org_model(org_info=TestOrgInfo.org_anonymous)
    membership = [TestAnonymousMembership.generate_random_user(ADMIN)]
    users = UserService.create_user_and_add_membership(membership, org.id, single_mode=True)
    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

    members = MembershipModel.find_members_by_org_id(org.id)

    # only one member should be there since its a STAFF created org
    assert len(members) == 1
    assert members[0].membership_type_code == ADMIN
Ejemplo n.º 18
0
def test_delete_bcros_valdiations(client, jwt, session, keycloak_mock, monkeypatch):
    """Assert different conditions of user deletion."""
    admin_user = TestUserInfo.user_bcros_active
    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)

    patch_token_info(owner_claims, monkeypatch)
    member = TestAnonymousMembership.generate_random_user(USER)
    admin = TestAnonymousMembership.generate_random_user(COORDINATOR)
    membership = [member, admin]
    UserService.create_user_and_add_membership(membership, org.id)
    owner_headers = factory_auth_header(jwt=jwt, claims=owner_claims)
    member_username = IdpHint.BCROS.value + '/' + member['username']
    admin_username = IdpHint.BCROS.value + '/' + admin['username']
    admin_claims = TestJwtClaims.get_test_real_user(uuid.uuid4(), admin_username, access_ype=AccessType.ANONYMOUS.value,
                                                    roles=[Role.ANONYMOUS_USER.value])
    admin_headers = factory_auth_header(jwt=jwt, claims=admin_claims)
    member_claims = TestJwtClaims.get_test_real_user(uuid.uuid4(), member_username,
                                                     access_ype=AccessType.ANONYMOUS.value,
                                                     roles=[Role.ANONYMOUS_USER.value])

    member_headers = factory_auth_header(jwt=jwt, claims=member_claims)

    # set up JWTS for member and admin
    patch_token_info(admin_claims, monkeypatch)
    client.post('/api/v1/users', headers=admin_headers, content_type='application/json',
                data=json.dumps({'isLogin': True}))

    patch_token_info(member_claims, monkeypatch)
    client.post('/api/v1/users', headers=member_headers, content_type='application/json',
                data=json.dumps({'isLogin': True}))

    patch_token_info(owner_claims, monkeypatch)
    # delete only owner ;failure
    rv = client.delete(f"/api/v1/users/{admin_user['username']}", headers=owner_headers,
                       content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # admin trying to delete member: Failure
    patch_token_info(admin_claims, monkeypatch)
    rv = client.delete(f'/api/v1/users/{member_username}', headers=admin_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # member delete admin: failure
    patch_token_info(member_claims, monkeypatch)
    rv = client.delete(f'/api/v1/users/{admin_username}', headers=member_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_401_UNAUTHORIZED

    # a self delete ;should work ;mimics leave team for anonymous user
    patch_token_info(member_claims, monkeypatch)
    rv = client.delete(f'/api/v1/users/{member_username}', headers=member_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT

    patch_token_info(admin_claims, monkeypatch)
    rv = client.delete(f'/api/v1/users/{admin_username}', headers=admin_headers, content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT

    # add one more admin
    patch_token_info(owner_claims, monkeypatch)
    new_owner = TestAnonymousMembership.generate_random_user(ADMIN)
    membership = [new_owner]
    UserService.create_user_and_add_membership(membership, org.id)
    patch_token_info(owner_claims, monkeypatch)
    rv = client.delete(f"/api/v1/users/{IdpHint.BCROS.value + '/' + new_owner['username']}", headers=owner_headers,
                       content_type='application/json')
    assert rv.status_code == http_status.HTTP_204_NO_CONTENT