Publish curated Unraid-AppOps-Gateway source from 68878c3167dacf2b424c16780e60e0d60815e477
This commit is contained in:
1 parent
837c263cd8
commit
551de41e9f
18 files changed
+1183
-58
No files matched your search
@@ -1,5 +1,7 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlmodel import SQLModel, create_engine
|
||||
|
||||
@@ -133,6 +135,7 @@ def test_oidc_template_requires_the_exact_enrolled_role_claim():
|
||||
from backend.app.core.config import settings
|
||||
|
||||
previous = _set_authentik_config()
|
||||
_set_deployment_identity_template()
|
||||
settings.apis['AUTHENTIK_OIDC_AUTHORIZATION_FLOW'] = 'flow-default-auth'
|
||||
settings.apis['AUTHENTIK_OIDC_INVALIDATION_FLOW'] = 'flow-default-invalidation'
|
||||
settings.apis['AUTHENTIK_OIDC_GROUP_CLAIM_MAPPING'] = 'mapping-groups'
|
||||
@@ -151,11 +154,86 @@ def test_oidc_template_requires_the_exact_enrolled_role_claim():
|
||||
_restore_config(previous)
|
||||
|
||||
|
||||
def _set_deployment_identity_template():
|
||||
from backend.app.core.config import settings
|
||||
|
||||
settings.apis.update({
|
||||
'AUTHENTIK_OIDC_OPENID_CLAIM_MAPPING': 'openid-id',
|
||||
'AUTHENTIK_OIDC_EMAIL_CLAIM_MAPPING': 'email-id',
|
||||
'AUTHENTIK_OIDC_PROFILE_CLAIM_MAPPING': 'profile-id',
|
||||
'AUTHENTIK_OIDC_SIGNING_KEY_ID': 'rsa-key-id',
|
||||
})
|
||||
|
||||
|
||||
@pytest.mark.parametrize("failure", [None, "flow", "flow_missing", "flow_duplicate", "mapping", "scope", "signing", "unreachable", "openid_roles", "email_roles", "profile_roles"])
|
||||
def test_enrollment_template_verifies_remote_flows_and_filtered_role_claim(monkeypatch, failure):
|
||||
from backend.app.connectors.authentik import AuthentikConnector
|
||||
from backend.app.core.config import settings
|
||||
|
||||
previous = _set_authentik_config()
|
||||
_set_deployment_identity_template()
|
||||
settings.apis.update({
|
||||
'AUTHENTIK_OIDC_AUTHORIZATION_FLOW': 'authorization-id',
|
||||
'AUTHENTIK_OIDC_INVALIDATION_FLOW': 'invalidation-id',
|
||||
'AUTHENTIK_OIDC_GROUP_CLAIM_MAPPING': 'roles-id',
|
||||
'AUTHENTIK_OIDC_ROLE_CLAIM': 'roles',
|
||||
})
|
||||
expression = 'return {"roles": sorted({group.name for group in request.user.ak_groups.all() if group.name in ["Administrator", "ReadOnly", "SupportAgent"]})}'
|
||||
|
||||
def request(self, path, params=None):
|
||||
if failure == 'unreachable':
|
||||
raise RuntimeError('SECRET_SENTINEL')
|
||||
for scope in ('openid', 'email', 'profile'):
|
||||
if path == f'/propertymappings/provider/scope/{scope}-id/':
|
||||
expressions = {
|
||||
'openid': '# This scope is required by the OpenID-spec, and must as such exist in authentik.\n# The scope by itself does not grant any information\nreturn {}',
|
||||
'email': 'return {\n "email": request.user.email,\n "email_verified": False\n}',
|
||||
'profile': 'return delete_none_values({\n "name": request.user.name,\n "preferred_username": request.user.username,\n})',
|
||||
}
|
||||
return {
|
||||
'pk': f'{scope}-id', 'scope_name': 'wrong' if failure == 'scope' else scope,
|
||||
'managed': f'goauthentik.io/providers/oauth2/scope-{scope}' if scope != 'profile' else None,
|
||||
'expression': 'return {"roles": ["Administrator"]}' if failure == f'{scope}_roles' else expressions[scope],
|
||||
}
|
||||
if path.startswith('/flows/instances/'):
|
||||
raise RuntimeError('HTTP 404: flow detail requires slug, not UUID')
|
||||
return {
|
||||
'/propertymappings/provider/scope/roles-id/': {
|
||||
'pk': 'roles-id', 'scope_name': 'roles',
|
||||
'expression': 'return {"roles": ["Administrator"]}' if failure == 'mapping' else expression,
|
||||
},
|
||||
}[path]
|
||||
|
||||
monkeypatch.setattr(AuthentikConnector, '_request', request)
|
||||
def paged(self, path, params=None):
|
||||
if path == '/flows/instances/':
|
||||
authorization = {'pk': 'authorization-id', 'slug': 'default-provider-authorization-implicit-consent', 'designation': 'authentication' if failure == 'flow' else 'authorization'}
|
||||
flows = [{'pk': 'invalidation-id', 'slug': 'default-provider-invalidation-flow', 'designation': 'invalidation'}]
|
||||
if failure != 'flow_missing':
|
||||
flows.append(authorization)
|
||||
if failure == 'flow_duplicate':
|
||||
flows.append(authorization)
|
||||
return flows
|
||||
assert path == '/crypto/certificatekeypairs/'
|
||||
return [{'pk': 'rsa-key-id', 'key_type': 'ec' if failure == 'signing' else 'rsa', 'private_key_available': True}]
|
||||
monkeypatch.setattr(AuthentikConnector, '_paged', paged)
|
||||
try:
|
||||
result = AuthentikConnector().validate_deployment_oidc_template(
|
||||
role_claim='roles', role_groups=('Administrator', 'SupportAgent', 'ReadOnly'),
|
||||
)
|
||||
assert (result['status'] == 'ready') is (failure is None)
|
||||
assert 'SECRET_SENTINEL' not in str(result)
|
||||
assert 'expression' not in result
|
||||
finally:
|
||||
_restore_config(previous)
|
||||
|
||||
|
||||
def test_typed_oidc_provisioning_is_bounded_and_never_returns_client_secret(monkeypatch):
|
||||
from backend.app.connectors.authentik import AuthentikConnector
|
||||
from backend.app.core.config import settings
|
||||
|
||||
previous = _set_authentik_config()
|
||||
_set_deployment_identity_template()
|
||||
settings.apis['AUTHENTIK_OIDC_AUTHORIZATION_FLOW'] = 'flow-default-auth'
|
||||
settings.apis['AUTHENTIK_OIDC_INVALIDATION_FLOW'] = 'flow-default-invalidation'
|
||||
settings.apis['AUTHENTIK_OIDC_GROUP_CLAIM_MAPPING'] = 'mapping-groups'
|
||||
@@ -195,6 +273,9 @@ def test_typed_oidc_provisioning_is_bounded_and_never_returns_client_secret(monk
|
||||
}
|
||||
assert writes[0][0:2] == ('POST', '/providers/oauth2/')
|
||||
assert writes[0][2]['client_secret'] == secret
|
||||
assert writes[0][2]['redirect_uris'] == [{'matching_mode': 'strict', 'url': 'https://support.itworx.test/signin-oidc'}]
|
||||
assert writes[0][2]['signing_key'] == 'rsa-key-id'
|
||||
assert set(writes[0][2]['property_mappings']) == {'openid-id', 'email-id', 'profile-id', 'mapping-groups'}
|
||||
assert secret not in str(result)
|
||||
_restore_config(previous)
|
||||
|
||||
@@ -204,6 +285,7 @@ def test_typed_oidc_provisioning_removes_new_provider_when_application_create_fa
|
||||
from backend.app.core.config import settings
|
||||
|
||||
previous = _set_authentik_config()
|
||||
_set_deployment_identity_template()
|
||||
settings.apis['AUTHENTIK_OIDC_AUTHORIZATION_FLOW'] = 'flow-default-auth'
|
||||
settings.apis['AUTHENTIK_OIDC_INVALIDATION_FLOW'] = 'flow-default-invalidation'
|
||||
settings.apis['AUTHENTIK_OIDC_GROUP_CLAIM_MAPPING'] = 'mapping-groups'
|
||||
@@ -248,21 +330,40 @@ def test_typed_oidc_provisioning_removes_new_provider_when_application_create_fa
|
||||
_restore_config(previous)
|
||||
|
||||
|
||||
def test_typed_oidc_existing_application_requires_matching_provider_contract(monkeypatch):
|
||||
@pytest.mark.parametrize('damage', [None, 'client', 'regex', 'extra_mapping', 'signing_key', 'issuer'])
|
||||
def test_typed_oidc_existing_application_requires_matching_provider_contract(monkeypatch, damage):
|
||||
from backend.app.connectors.authentik import AuthentikConnector
|
||||
from backend.app.core.config import settings
|
||||
|
||||
previous = _set_authentik_config()
|
||||
_set_deployment_identity_template()
|
||||
settings.apis['AUTHENTIK_OIDC_AUTHORIZATION_FLOW'] = 'flow-default-auth'
|
||||
settings.apis['AUTHENTIK_OIDC_INVALIDATION_FLOW'] = 'flow-default-invalidation'
|
||||
settings.apis['AUTHENTIK_OIDC_GROUP_CLAIM_MAPPING'] = 'mapping-groups'
|
||||
provider = {
|
||||
'pk': 'provider-1', 'client_id': 'wsbc-portal', 'client_type': 'confidential',
|
||||
'redirect_uris': [{'matching_mode': 'strict', 'url': 'https://support.itworx.test/signin-oidc'}],
|
||||
'property_mappings': ['openid-id', 'email-id', 'profile-id', 'mapping-groups'],
|
||||
'authorization_flow': 'flow-default-auth', 'invalidation_flow': 'flow-default-invalidation',
|
||||
'signing_key': 'rsa-key-id', 'issuer_mode': 'per_provider',
|
||||
}
|
||||
if damage == 'client':
|
||||
provider['client_id'] = 'unexpected-client'
|
||||
elif damage == 'regex':
|
||||
provider['redirect_uris'][0]['matching_mode'] = 'regex'
|
||||
elif damage == 'extra_mapping':
|
||||
provider['property_mappings'].append('other-roles')
|
||||
elif damage == 'signing_key':
|
||||
provider['signing_key'] = None
|
||||
elif damage == 'issuer':
|
||||
provider['issuer_mode'] = 'global'
|
||||
monkeypatch.setattr(
|
||||
AuthentikConnector,
|
||||
'_paged',
|
||||
lambda self, path, params=None: {
|
||||
'/core/groups/': [{'name': 'Administrator'}, {'name': 'SupportAgent'}, {'name': 'ReadOnly'}],
|
||||
'/core/applications/': [{'pk': 'application-1', 'slug': 'wsbc-portal', 'meta_launch_url': 'https://support.itworx.test', 'provider': 'provider-1'}],
|
||||
'/providers/oauth2/': [{'pk': 'provider-1', 'client_id': 'unexpected-client', 'client_type': 'confidential', 'redirect_uris': ['https://support.itworx.test/signin-oidc'], 'property_mappings': ['mapping-groups'], 'authorization_flow': 'flow-default-auth', 'invalidation_flow': 'flow-default-invalidation'}],
|
||||
'/providers/oauth2/': [provider],
|
||||
}[path],
|
||||
raising=True,
|
||||
)
|
||||
@@ -279,11 +380,17 @@ def test_typed_oidc_existing_application_requires_matching_provider_contract(mon
|
||||
finally:
|
||||
_restore_config(previous)
|
||||
|
||||
assert result == {
|
||||
assert result == ({
|
||||
'success': True,
|
||||
'status': 'already_managed',
|
||||
'message': 'oidc_application_already_matches_typed_plan',
|
||||
'applicationId': 'application-1',
|
||||
'clientSecretCreated': False,
|
||||
} if damage is None else {
|
||||
'success': False,
|
||||
'status': 'conflict',
|
||||
'message': 'existing_oidc_provider_does_not_match_managed_contract',
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
def test_authentik_health_success_and_auth_failure_redact_token(monkeypatch):
|
||||
|
||||
Reference in new issue
Block a user