def test_should_make_auth(well_known_master: WellKnown, login_html_page: str): session_provider = lambda: mock_session( { 'http://localhost:8080/auth/realms/master/protocol/openid-connect/auth': RequestSpec(response=MockResponse(status_code=200, response=login_html_page), assertion=lambda **kwargs: kwargs['params'] == { 'response_type': 'code', 'client_id': 'account', 'code_challenge_method': 'S256', 'code_challenge': 'W59JjmjRrRjxwZVd1SZW-zfqGilWDldy2gUAMPX8EuE', 'redirect_uri': None }) }, post={ 'http://localhost:8080/auth/realms/master/login-actions/authenticate?session_code=bR4rBd0QNGsd_kGuqiyLEuYuY6FK3Lx9HCYJEltUQBk&execution=de13838a-ee3d-404e-b16d-b0d7aa320844&client_id=account-console&tab_id=GXMjAPR3DsQ': RequestSpec(response=MockResponse(status_code=302), assertion=lambda **kwargs: kwargs['data'] == { 'password': '******', 'username': '******' }) }) kapi = KeyCloakApi(well_known=well_known_master.json, session_provider=session_provider) r = kapi.auth(Client('account', url=''), password='******', username='******') assert r.status_code == 302
def test_should_fail_when_bad_form_on_auth(well_known_master: WellKnown, login_html_page: str): session_provider = lambda: mock_session({ 'http://localhost:8080/auth/realms/master/protocol/openid-connect/auth': RequestSpec(response=MockResponse(status_code=200, response='nothing'), assertion=lambda **kwargs: kwargs['params'] == { 'response_type': 'code', 'client_id': 'account', 'code_challenge_method': 'S256', 'code_challenge': 'W59JjmjRrRjxwZVd1SZW-zfqGilWDldy2gUAMPX8EuE', 'redirect_uri': None }) }) kapi = KeyCloakApi(well_known=well_known_master.json, session_provider=session_provider) with pytest.raises(FailedAuthException) as e: r = kapi.auth(Client('account', url=''), password='******', username='******') assert str(e.value) == "'NoneType' object has no attribute 'attrs'"
def test_should_return_token(well_known_master: WellKnown): session_provider = lambda: mock_session( post={ 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token': RequestSpec(response=MockResponse( status_code=200, response={ 'access_token': 'access_token', 'refresh_token': 'refresh_token' }), assertion=lambda **kwargs: kwargs['data'] == { 'client_id': 'account', 'client_secret': '', 'grant_type': 'password', 'password': '******', 'username': '******' }) }) kapi = KeyCloakApi(well_known=well_known_master.json, session_provider=session_provider) assert kapi.get_token('account', '', 'user', 'pass', 'password') == ('access_token', 'refresh_token')
def test_perform(base_url: str, master_realm: Realm, other_realm: Realm, capsys: CaptureFixture, well_known_list: List[WellKnown]): def assert0(**kwargs) -> bool: print(kwargs) return kwargs['params']['client_id'] in ['client1', 'client2'] client_scanner = ClientScanner(clients=['client1', 'client2'], base_url=base_url, session_provider=lambda: MockSpec( get={ 'http://localhost:8080/auth/realms/master/client1': RequestSpec(response=MockResponse(status_code=200)), 'http://localhost:8080/auth/realms/master/client2': RequestSpec(response=MockResponse(status_code=404)), 'http://localhost:8080/auth/realms/master/protocol/openid-connect/auth': RequestSpec(response=MockResponse(302), assertion=assert0), 'http://localhost:8080/realms/master/clients-registrations/default/client1': RequestSpec(response=MockResponse(200, response={'data': 'coucou'})), 'http://localhost:8080/realms/master/clients-registrations/default/client2': RequestSpec(response=MockResponse(200, response={'data': 'coucou'})) } ).session()) result, vf = client_scanner.perform(realm=master_realm, well_known=well_known_list[0]) capture = capsys.readouterr() print(capture.out) print(capture.err) assert result == {Client('client1', 'http://localhost:8080/auth/realms/master/client1', client_registration=ClientConfig(name='client1', url='http://localhost:8080/realms/master/clients-registrations/default/client1', json={'data': 'coucou'} ) ), Client('client2', None, client_registration=ClientConfig(name='client2', url='http://localhost:8080/realms/master/clients-registrations/default/client2', json={'data': 'coucou'} ) )} assert not vf.has_vuln assert 'Find a client for realm master: client1' in capture.out
def test_client_registration_scanner_should_not_register(master_realm: Realm, well_known_master: WellKnown, credential_set: Set[Credential], well_known_json_master: dict): class TestRandomStr(RandomStr): def random_str(self) -> str: return '456789' class TestClientRegistrationScanner(ClientRegistrationScanner, TestRandomStr): pass session_provider = lambda: MockSpec( get={ 'http://localhost:8080/auth/realms/master/.well-known/openid-configuration': RequestSpec( MockResponse(status_code=200, response=well_known_json_master) ), }, post={ 'http://localhost:8080/auth/realms/master/clients-registrations/openid-connect': RequestSpec(response=MockResponse(status_code=403), assertion=check_request, assertion_value={'json': { "application_type": "web", "redirect_uris": [ "http://callback/callback"], "client_name": "keycloak-client-456789", "logo_uri": "http://callback/logo.png", "jwks_uri": "http://callback/public_keys.jwks" }}), 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token': RequestSpec( response=MockResponse(status_code=403)) }, ).session() mediator = Mediator([ TestClientRegistrationScanner(['http://callback'], base_url='http://localhost:8080', session_provider=session_provider) ]) mediator.send(WrapperTypes.REALM_TYPE, {master_realm}) mediator.send(WrapperTypes.WELL_KNOWN_TYPE, {well_known_master}) mediator.send(WrapperTypes.CREDENTIAL_TYPE, credential_set) assert mediator.scan_results.get(WrapperTypes.CLIENT_REGISTRATION) == set()
def test_client_registration_scanner_should_register(master_realm: Realm, well_known_master: WellKnown, credential_set: Set[Credential], well_known_json_master: dict): class TestRandomStr(RandomStr): def random_str(self) -> str: return '456789' class TestClientRegistrationScanner(ClientRegistrationScanner, TestRandomStr): pass response = { "redirect_uris": ["http://localhost:8080/callback"], "token_endpoint_auth_method": "client_secret_basic", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code", "none"], "client_id": "539ce782-5d15-4256-a5fa-1a46609d056b", "client_secret": "c94f5fc0-0a04-4e2f-aec6-b1f5edad1d44", "client_name": "keycloak-client-456789", "scope": "address phone offline_access microprofile-jwt", "jwks_uri": "http://localhost:8080/public_keys.jwks", "subject_type": "pairwise", "request_uris": ["http://localhost:8080/rf.txt"], "tls_client_certificate_bound_access_tokens": False, "client_id_issued_at": 1622306364, "client_secret_expires_at": 0, "registration_client_uri": "http://localhost:8080/auth/realms/master/clients-registrations/openid-connect/539ce782-5d15-4256-a5fa-1a46609d056b", "backchannel_logout_session_required": False } session_provider = lambda: MockSpec( get={ 'http://localhost:8080/auth/realms/master/.well-known/openid-configuration': RequestSpec( MockResponse(status_code=200, response=well_known_json_master) ), }, post={ 'http://localhost:8080/auth/realms/master/clients-registrations/openid-connect': RequestSpec(response=MockResponse(status_code=201, response=response), assertion=check_request, assertion_value={'json': { "application_type": "web", "redirect_uris": [ "http://callback/callback"], "client_name": "keycloak-client-456789", "logo_uri": "http://callback/logo.png", "jwks_uri": "http://callback/public_keys.jwks" }})}).session() mediator = Mediator([ TestClientRegistrationScanner(['http://callback'], base_url='http://localhost:8080', session_provider=session_provider) ]) mediator.send(WrapperTypes.REALM_TYPE, {master_realm}) mediator.send(WrapperTypes.WELL_KNOWN_TYPE, {well_known_master}) mediator.send(WrapperTypes.CREDENTIAL_TYPE, credential_set) assert mediator.scan_results.get(WrapperTypes.CLIENT_REGISTRATION) == {ClientRegistration( 'http://callback', name='keycloak-client-456789', url='http://localhost:8080/auth/realms/master/clients-registrations/openid-connect/539ce782-5d15-4256-a5fa-1a46609d056b', json=response )}
def full_scan_mock(master_realm_json, other_realm_json, well_known_json_master: dict, well_known_json_other: dict, login_html_page: str) -> MockSpec: token_response = { 'access_token': 'eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3ODM4MGM2ZS1iODhmLTQ5NDQtOGRkZS03NTQyMDNkMjFhODEifQ.eyJleHAiOjE2MjE2NzU5NzIsImlhdCI6MTYyMTYzOTk3MiwianRpIjoiMGU2NDcxOTItMzU5ZS00NmU4LWFkYWQtNTQzNmQyNjMyZjA1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjJjMTZhY2Y1LWMwOTYtNDg5ZC1iYjFjLTU4ZTc0ZTJiZjAzMiIsInR5cCI6IlNlcmlhbGl6ZWQtSUQiLCJzZXNzaW9uX3N0YXRlIjoiZWY3ZjNjZmItMDAzZS00YzViLWEzMWQtYmI0OGFhZjAzNzk3Iiwic3RhdGVfY2hlY2tlciI6ImtKNy05MURtNVEwVXktT1JfVlJnT1d5eF91Wkh3M0ZfczktTVdlUjZRTlEifQ.6yZvyGKEH0NXmLY8nKRQMLsMQYPXq5dYCsIF3LRiOxI', 'refresh_token': 'eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI3ODM4MGM2ZS1iODhmLTQ5NDQtOGRkZS03NTQyMDNkMjFhODEifQ.eyJleHAiOjE2MjE2NzU5NzIsImlhdCI6MTYyMTYzOTk3MiwianRpIjoiMGU2NDcxOTItMzU5ZS00NmU4LWFkYWQtNTQzNmQyNjMyZjA1IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjJjMTZhY2Y1LWMwOTYtNDg5ZC1iYjFjLTU4ZTc0ZTJiZjAzMiIsInR5cCI6IlNlcmlhbGl6ZWQtSUQiLCJzZXNzaW9uX3N0YXRlIjoiZWY3ZjNjZmItMDAzZS00YzViLWEzMWQtYmI0OGFhZjAzNzk3Iiwic3RhdGVfY2hlY2tlciI6ImtKNy05MURtNVEwVXktT1JfVlJnT1d5eF91Wkh3M0ZfczktTVdlUjZRTlEifQ.6yZvyGKEH0NXmLY8nKRQMLsMQYPXq5dYCsIF3LRiOxI' } return MockSpec(get={ 'http://localhost:8080/auth/realms/master/.well-known/openid-configuration': RequestSpec( MockResponse(status_code=200, response=well_known_json_master) ), 'http://localhost:8080/auth/realms/master': RequestSpec( MockResponse(status_code=200, response=master_realm_json)), 'http://localhost:8080/auth/realms/other': RequestSpec( MockResponse(status_code=200, response=other_realm_json)), 'http://localhost:8080/auth/realms/other/.well-known/openid-configuration': RequestSpec( MockResponse(status_code=200, response=well_known_json_other)), 'http://localhost:8080/auth/realms/master/client1': RequestSpec( MockResponse(status_code=200, response='coucou')), 'http://localhost:8080/auth/realms/master/client2': RequestSpec( MockResponse(status_code=200, response='coucou')), 'http://localhost:8080/auth/realms/other/client1': RequestSpec( MockResponse(status_code=200, response='coucou')), 'http://localhost:8080/auth/realms/other/client2': RequestSpec( MockResponse(status_code=200, response='coucou')), 'http://localhost:8080/auth/realms/master/clients-registrations/default/security-admin-console': RequestSpec(MockResponse(status_code=401, response={"error": "invalid_token", "error_description": "Not authorized to view client. Not valid token or client credentials provided."})), 'http://localhost:8080/auth/realms/other/clients-registrations/default/security-admin-console': RequestSpec( MockResponse( status_code=401, response={"error": "invalid_token", "error_description": "Not authorized to view client. Not valid token or client credentials provided."})), 'http://localhost:8080/auth': RequestSpec(MockResponse(status_code=400)), 'http://localhost:8080/auth/realms/master/protocol/openid-connect/auth': RequestSpec(MockResponse(200, response=login_html_page)), 'http://localhost:8080/auth/realms/other/protocol/openid-connect/auth': RequestSpec(MockResponse(200, response=login_html_page)), 'http://localhost:8080/auth/realms/master/protocol/openid-connect/auth?client_id=account-console&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fauth%2Frealms%2Fmaster%2Faccount%2F%23%2F&state=310f298c-f3d8-4c42-8ebc-44484febf84c&response_mode=fragment&response_type=code&scope=openid&nonce=a6be5274-15e4-4ffe-9905-ffb038b20a8e&code_challenge=Nd1svU3YNT0r6eWHkSmNeX_cxgUPQUVzPfZFXRWaJmY&code_challenge_method=S256': RequestSpec(MockResponse( 200, login_html_page)), 'http://localhost:8080/realms/master/clients-registrations/default/client1': RequestSpec( MockResponse(200, response={"id": "899e2dc1-5fc0-4eaf-bedb-f81a3f9e9313", "clientId": "admin-cli", "name": "${client_admin-cli}", "surrogateAuthRequired": False, "enabled": True, "alwaysDisplayInConsole": False, "clientAuthenticatorType": "client-secret", "redirectUris": [], "webOrigins": [], "notBefore": 0, "bearerOnly": False, "consentRequired": False, "standardFlowEnabled": False, "implicitFlowEnabled": False, "directAccessGrantsEnabled": False, "serviceAccountsEnabled": False, "publicClient": False, "frontchannelLogout": False, "protocol": "openid-connect", "attributes": {}, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": False, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "roles", "profile", "email"], "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"]}) ), 'http://localhost:8080/realms/other/clients-registrations/default/client1': RequestSpec( MockResponse(200, response={"id": "899e2dc1-5fc0-4eaf-bedb-f81a3f9e9313", "clientId": "admin-cli", "name": "${client_admin-cli}", "surrogateAuthRequired": False, "enabled": True, "alwaysDisplayInConsole": False, "clientAuthenticatorType": "client-secret", "redirectUris": [], "webOrigins": [], "notBefore": 0, "bearerOnly": False, "consentRequired": False, "standardFlowEnabled": False, "implicitFlowEnabled": False, "directAccessGrantsEnabled": False, "serviceAccountsEnabled": False, "publicClient": False, "frontchannelLogout": False, "protocol": "openid-connect", "attributes": {}, "authenticationFlowBindingOverrides": {}, "fullScopeAllowed": False, "nodeReRegistrationTimeout": 0, "defaultClientScopes": ["web-origins", "roles", "profile", "email"], "optionalClientScopes": ["address", "phone", "offline_access", "microprofile-jwt"]}) ), 'http://localhost:8080/realms/master/clients-registrations/default/client2': RequestSpec( MockResponse(400) ), 'http://localhost:8080/realms/other/clients-registrations/default/client2': RequestSpec( MockResponse(400) ), }, post={ 'http://localhost:8080/master/token': RequestSpec(MockResponse(status_code=200, response=token_response)), 'http://localhost:8080/auth/realms/master/protocol/openid-connect/token': RequestSpec( MockResponse(status_code=200, response=token_response)), 'http://localhost:8080/other/token': RequestSpec(MockResponse(status_code=200, response=token_response)), 'http://localhost:8080/auth/realms/other/protocol/openid-connect/token': RequestSpec( MockResponse(status_code=200, response=token_response)), 'http://localhost:8080/auth/realms/master/login-actions/authenticate?session_code' '=bR4rBd0QNGsd_kGuqiyLEuYuY6FK3Lx9HCYJEltUQBk&execution=de13838a-ee3d-404e-b16d-b0d7aa320844&client_id' '=account-console&tab_id=GXMjAPR3DsQ': RequestSpec(MockResponse( 302, response=None, headers={'Location': '<openid location>'})), 'http://localhost:8080/auth/realms/master/clients-registrations/openid-connect': RequestSpec(response=MockResponse(status_code=201, response={ "redirect_uris": ["http://localhost:8080/callback"], "token_endpoint_auth_method": "client_secret_basic", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code", "none"], "client_id": "539ce782-5d15-4256-a5fa-1a46609d056b", "client_secret": "c94f5fc0-0a04-4e2f-aec6-b1f5edad1d44", "client_name": "keycloak-client-456789", "scope": "address phone offline_access microprofile-jwt", "jwks_uri": "http://localhost:8080/public_keys.jwks", "subject_type": "pairwise", "request_uris": ["http://localhost:8080/rf.txt"], "tls_client_certificate_bound_access_tokens": False, "client_id_issued_at": 1622306364, "client_secret_expires_at": 0, "registration_client_uri": "http://localhost:8080/auth/realms/master/clients-registrations/openid-connect/539ce782-5d15-4256-a5fa-1a46609d056b", "backchannel_logout_session_required": False })), 'http://localhost:8080/auth/realms/other/clients-registrations/openid-connect': RequestSpec(response=MockResponse(status_code=201, response={ "redirect_uris": ["http://localhost:8080/callback"], "token_endpoint_auth_method": "client_secret_basic", "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code", "none"], "client_id": "539ce782-5d15-4256-a5fa-1a46609d056b", "client_secret": "c94f5fc0-0a04-4e2f-aec6-b1f5edad1d44", "client_name": "keycloak-client-456789", "scope": "address phone offline_access microprofile-jwt", "jwks_uri": "http://localhost:8080/public_keys.jwks", "subject_type": "pairwise", "request_uris": ["http://localhost:8080/rf.txt"], "tls_client_certificate_bound_access_tokens": False, "client_id_issued_at": 1622306364, "client_secret_expires_at": 0, "registration_client_uri": "http://localhost:8080/auth/realms/other/clients-registrations/openid-connect/539ce782-5d15-4256-a5fa-1a46609d056b", "backchannel_logout_session_required": False })) })