enterprise/providers: WS-Federation (#19583)

* init

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix metadata

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* aight

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* progress

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix timedelta

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* start testing metadata

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add some more tests and schemas

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* test signature

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* attempt to fix signed xml linebreak

https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1258
https://github.com/robrichards/xmlseclibs/issues/28
https://github.com/xmlsec/python-xmlsec/issues/196
Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* format + gen

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update web

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* more validation

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* hmm

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add e2e test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* qol fix in wait_for_url

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add UI

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* acs -> reply url

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* sign_out

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix some XML typing

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* remove verification_kp as its not used

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix reply url

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add ws-fed to tests

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add logout test

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add SAMLSession

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* refactor

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* unrelated type fixes

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add backchannel logout

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* delete import_metadata in wsfed

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* include generated realm

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* Update web/src/admin/providers/wsfed/WSFederationProviderViewPage.ts

Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
Signed-off-by: Jens L. <jens@beryju.org>

* include wtrealm in ui

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Signed-off-by: Jens L. <jens@beryju.org>
Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
This commit is contained in:
Jens L.
2026-01-28 17:43:16 +01:00
committed by GitHub
parent 586ccf3aa3
commit d1fb7dde14
53 changed files with 6032 additions and 69 deletions

View File

@@ -187,6 +187,8 @@ jobs:
glob: tests/e2e/test_provider_saml* tests/e2e/test_source_saml*
- name: ldap
glob: tests/e2e/test_provider_ldap* tests/e2e/test_source_ldap*
- name: ws-fed
glob: tests/e2e/test_provider_ws_fed*
- name: radius
glob: tests/e2e/test_provider_radius*
- name: scim

View File

@@ -0,0 +1,69 @@
"""WSFederationProvider API Views"""
from django.http import HttpRequest
from django.urls import reverse
from rest_framework.fields import SerializerMethodField, URLField
from authentik.core.api.providers import ProviderSerializer
from authentik.core.models import Application
from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.metadata import MetadataProcessor
from authentik.providers.saml.api.providers import SAMLProviderSerializer, SAMLProviderViewSet
class WSFederationProviderSerializer(EnterpriseRequiredMixin, SAMLProviderSerializer):
"""WSFederationProvider Serializer"""
reply_url = URLField(source="acs_url")
url_wsfed = SerializerMethodField()
wtrealm = SerializerMethodField()
def get_url_wsfed(self, instance: WSFederationProvider) -> str:
"""Get WS-Fed url"""
if "request" not in self._context:
return ""
request: HttpRequest = self._context["request"]._request
return request.build_absolute_uri(reverse("authentik_providers_ws_federation:wsfed"))
def get_wtrealm(self, instance: WSFederationProvider) -> str:
try:
return f"goauthentik.io://app/{instance.application.slug}"
except Application.DoesNotExist:
return None
class Meta(SAMLProviderSerializer.Meta):
model = WSFederationProvider
fields = ProviderSerializer.Meta.fields + [
"reply_url",
"assertion_valid_not_before",
"assertion_valid_not_on_or_after",
"session_valid_not_on_or_after",
"property_mappings",
"name_id_mapping",
"authn_context_class_ref_mapping",
"digest_algorithm",
"signature_algorithm",
"signing_kp",
"encryption_kp",
"sign_assertion",
"sign_logout_request",
"default_name_id_policy",
"url_download_metadata",
"url_wsfed",
"wtrealm",
]
extra_kwargs = ProviderSerializer.Meta.extra_kwargs
class WSFederationProviderViewSet(SAMLProviderViewSet):
"""WSFederationProvider Viewset"""
queryset = WSFederationProvider.objects.all()
serializer_class = WSFederationProviderSerializer
filterset_fields = "__all__"
ordering = ["name"]
search_fields = ["name"]
metadata_generator_class = MetadataProcessor
import_metadata = None

View File

@@ -0,0 +1,13 @@
"""WSFed app config"""
from authentik.enterprise.apps import EnterpriseConfig
class AuthentikEnterpriseProviderWSFederatopm(EnterpriseConfig):
"""authentik enterprise ws federation app config"""
name = "authentik.enterprise.providers.ws_federation"
label = "authentik_providers_ws_federation"
verbose_name = "authentik Enterprise.Providers.WS-Federation"
default = True
mountpoint = "application/wsfed/"

View File

@@ -0,0 +1,37 @@
# Generated by Django 5.2.10 on 2026-01-18 23:25
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
("authentik_providers_saml", "0020_samlprovider_logout_method_and_more"),
]
operations = [
migrations.CreateModel(
name="WSFederationProvider",
fields=[
(
"samlprovider_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="authentik_providers_saml.samlprovider",
),
),
],
options={
"verbose_name": "WS-Federation Provider",
"verbose_name_plural": "WS-Federation Providers",
},
bases=("authentik_providers_saml.samlprovider",),
),
]

View File

@@ -0,0 +1,32 @@
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _
from rest_framework.serializers import Serializer
from authentik.providers.saml.models import SAMLProvider
class WSFederationProvider(SAMLProvider):
"""WS-Federation for applications which support WS-Fed."""
@property
def serializer(self) -> type[Serializer]:
from authentik.enterprise.providers.ws_federation.api.providers import (
WSFederationProviderSerializer,
)
return WSFederationProviderSerializer
@property
def icon_url(self) -> str | None:
return static("authentik/sources/wsfed.svg")
@property
def component(self) -> str:
return "ak-provider-wsfed-form"
def __str__(self):
return f"WS-Federation Provider {self.name}"
class Meta:
verbose_name = _("WS-Federation Provider")
verbose_name_plural = _("WS-Federation Providers")

View File

@@ -0,0 +1,39 @@
from authentik.sources.saml.processors.constants import NS_MAP as _map
WS_FED_ACTION_SIGN_IN = "wsignin1.0"
WS_FED_ACTION_SIGN_OUT = "wsignout1.0"
WS_FED_ACTION_SIGN_OUT_CLEANUP = "wsignoutcleanup1.0"
WS_FED_POST_KEY_ACTION = "wa"
WS_FED_POST_KEY_RESULT = "wresult"
WS_FED_POST_KEY_CONTEXT = "wctx"
WSS_TOKEN_TYPE_SAML2 = (
"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" # nosec
)
WSS_KEY_IDENTIFIER_SAML_ID = (
"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID"
)
NS_WS_FED_PROTOCOL = "http://docs.oasis-open.org/wsfed/federation/200706"
NS_WS_FED_TRUST = "http://schemas.xmlsoap.org/ws/2005/02/trust"
NS_WSI = "http://www.w3.org/2001/XMLSchema-instance"
NS_ADDRESSING = "http://www.w3.org/2005/08/addressing"
NS_POLICY = "http://schemas.xmlsoap.org/ws/2004/09/policy"
NS_WSS_SEC = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
NS_WSS_UTILITY = (
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
)
NS_WSS_D3P1 = "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"
NS_MAP = {
**_map,
"fed": NS_WS_FED_PROTOCOL,
"xsi": NS_WSI,
"wsa": NS_ADDRESSING,
"t": NS_WS_FED_TRUST,
"wsu": NS_WSS_UTILITY,
"wsp": NS_POLICY,
"wssec": NS_WSS_SEC,
"d3p1": NS_WSS_D3P1,
}

View File

@@ -0,0 +1,40 @@
from django.urls import reverse
from lxml.etree import SubElement, _Element # nosec
from authentik.enterprise.providers.ws_federation.processors.constants import (
NS_ADDRESSING,
NS_MAP,
NS_WS_FED_PROTOCOL,
NS_WSI,
)
from authentik.providers.saml.processors.metadata import MetadataProcessor as BaseMetadataProcessor
from authentik.sources.saml.processors.constants import NS_SAML_METADATA
class MetadataProcessor(BaseMetadataProcessor):
def add_children(self, entity_descriptor: _Element):
self.add_role_descriptor_sts(entity_descriptor)
super().add_children(entity_descriptor)
def add_endpoint(self, parent: _Element, name: str):
endpoint = SubElement(parent, f"{{{NS_WS_FED_PROTOCOL}}}{name}", nsmap=NS_MAP)
endpoint_ref = SubElement(endpoint, f"{{{NS_ADDRESSING}}}EndpointReference", nsmap=NS_MAP)
address = SubElement(endpoint_ref, f"{{{NS_ADDRESSING}}}Address", nsmap=NS_MAP)
address.text = self.http_request.build_absolute_uri(
reverse("authentik_providers_ws_federation:wsfed")
)
def add_role_descriptor_sts(self, entity_descriptor: _Element):
role_descriptor = SubElement(
entity_descriptor, f"{{{NS_SAML_METADATA}}}RoleDescriptor", nsmap=NS_MAP
)
role_descriptor.attrib[f"{{{NS_WSI}}}type"] = "fed:SecurityTokenServiceType"
role_descriptor.attrib["protocolSupportEnumeration"] = NS_WS_FED_PROTOCOL
signing_descriptor = self.get_signing_key_descriptor()
if signing_descriptor is not None:
role_descriptor.append(signing_descriptor)
self.add_endpoint(role_descriptor, "SecurityTokenServiceEndpoint")
self.add_endpoint(role_descriptor, "PassiveRequestorEndpoint")

View File

@@ -0,0 +1,162 @@
from dataclasses import dataclass
from urllib.parse import urlparse
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from lxml import etree # nosec
from lxml.etree import Element, SubElement, _Element # nosec
from authentik.core.models import Application
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.constants import (
NS_ADDRESSING,
NS_MAP,
NS_POLICY,
NS_WS_FED_TRUST,
NS_WSS_D3P1,
NS_WSS_SEC,
NS_WSS_UTILITY,
WS_FED_ACTION_SIGN_IN,
WS_FED_POST_KEY_ACTION,
WS_FED_POST_KEY_CONTEXT,
WS_FED_POST_KEY_RESULT,
WSS_KEY_IDENTIFIER_SAML_ID,
WSS_TOKEN_TYPE_SAML2,
)
from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.utils import delete_none_values
from authentik.providers.saml.processors.assertion import AssertionProcessor
from authentik.providers.saml.processors.authn_request_parser import AuthNRequest
from authentik.providers.saml.utils.time import get_time_string
@dataclass()
class SignInRequest:
wa: str
wtrealm: str
wreply: str
wctx: str | None
app_slug: str
@staticmethod
def parse(request: HttpRequest) -> SignInRequest:
action = request.GET.get("wa")
if action != WS_FED_ACTION_SIGN_IN:
raise ValueError("Invalid action")
realm = request.GET.get("wtrealm")
if not realm:
raise ValueError("Missing Realm")
parsed = urlparse(realm)
req = SignInRequest(
wa=action,
wtrealm=realm,
wreply=request.GET.get("wreply"),
wctx=request.GET.get("wctx", ""),
app_slug=parsed.path[1:],
)
_, provider = req.get_app_provider()
if not req.wreply.startswith(provider.acs_url):
raise ValueError("Invalid wreply")
return req
def get_app_provider(self):
application = get_object_or_404(Application, slug=self.app_slug)
provider: WSFederationProvider = get_object_or_404(
WSFederationProvider, pk=application.provider_id
)
return application, provider
class SignInProcessor:
provider: WSFederationProvider
request: HttpRequest
sign_in_request: SignInRequest
saml_processor: AssertionProcessor
def __init__(
self, provider: WSFederationProvider, request: HttpRequest, sign_in_request: SignInRequest
):
self.provider = provider
self.request = request
self.sign_in_request = sign_in_request
self.saml_processor = AssertionProcessor(self.provider, self.request, AuthNRequest())
self.saml_processor.provider.audience = self.sign_in_request.wtrealm
def create_response_token(self):
root = Element(f"{{{NS_WS_FED_TRUST}}}RequestSecurityTokenResponse", nsmap=NS_MAP)
root.append(self.response_add_lifetime())
root.append(self.response_add_applies_to())
root.append(self.response_add_requested_security_token())
root.append(
self.response_add_attached_reference(
"RequestedAttachedReference", self.saml_processor._assertion_id
)
)
root.append(
self.response_add_attached_reference(
"RequestedUnattachedReference", self.saml_processor._assertion_id
)
)
token_type = SubElement(root, f"{{{NS_WS_FED_TRUST}}}TokenType")
token_type.text = WSS_TOKEN_TYPE_SAML2
request_type = SubElement(root, f"{{{NS_WS_FED_TRUST}}}RequestType")
request_type.text = "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue"
key_type = SubElement(root, f"{{{NS_WS_FED_TRUST}}}KeyType")
key_type.text = "http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey"
return root
def response_add_lifetime(self) -> _Element:
"""Add Lifetime element"""
lifetime = Element(f"{{{NS_WS_FED_TRUST}}}Lifetime", nsmap=NS_MAP)
created = SubElement(lifetime, f"{{{NS_WSS_UTILITY}}}Created")
created.text = get_time_string()
expires = SubElement(lifetime, f"{{{NS_WSS_UTILITY}}}Expires")
expires.text = get_time_string(
timedelta_from_string(self.provider.session_valid_not_on_or_after)
)
return lifetime
def response_add_applies_to(self) -> _Element:
"""Add AppliesTo element"""
applies_to = Element(f"{{{NS_POLICY}}}AppliesTo")
endpoint_ref = SubElement(applies_to, f"{{{NS_ADDRESSING}}}EndpointReference")
address = SubElement(endpoint_ref, f"{{{NS_ADDRESSING}}}Address")
address.text = self.sign_in_request.wtrealm
return applies_to
def response_add_requested_security_token(self) -> _Element:
"""Add RequestedSecurityToken and child assertion"""
token = Element(f"{{{NS_WS_FED_TRUST}}}RequestedSecurityToken")
token.append(self.saml_processor.get_assertion())
return token
def response_add_attached_reference(self, tag: str, value: str) -> _Element:
ref = Element(f"{{{NS_WS_FED_TRUST}}}{tag}")
sec_token_ref = SubElement(ref, f"{{{NS_WSS_SEC}}}SecurityTokenReference")
sec_token_ref.attrib[f"{{{NS_WSS_D3P1}}}TokenType"] = WSS_TOKEN_TYPE_SAML2
key_identifier = SubElement(sec_token_ref, f"{{{NS_WSS_SEC}}}KeyIdentifier")
key_identifier.attrib["ValueType"] = WSS_KEY_IDENTIFIER_SAML_ID
key_identifier.text = value
return ref
def response(self) -> dict[str, str]:
root = self.create_response_token()
assertion = root.xpath("//saml:Assertion", namespaces=NS_MAP)[0]
self.saml_processor._sign(assertion)
str_token = etree.tostring(root).decode("utf-8") # nosec
return delete_none_values(
{
WS_FED_POST_KEY_ACTION: WS_FED_ACTION_SIGN_IN,
WS_FED_POST_KEY_RESULT: str_token,
WS_FED_POST_KEY_CONTEXT: self.sign_in_request.wctx,
}
)

View File

@@ -0,0 +1,47 @@
from dataclasses import dataclass
from urllib.parse import urlparse
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from authentik.core.models import Application
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.constants import WS_FED_ACTION_SIGN_OUT
@dataclass()
class SignOutRequest:
wa: str
wtrealm: str
wreply: str
app_slug: str
@staticmethod
def parse(request: HttpRequest) -> SignOutRequest:
action = request.GET.get("wa")
if action != WS_FED_ACTION_SIGN_OUT:
raise ValueError("Invalid action")
realm = request.GET.get("wtrealm")
if not realm:
raise ValueError("Missing Realm")
parsed = urlparse(realm)
req = SignOutRequest(
wa=action,
wtrealm=realm,
wreply=request.GET.get("wreply"),
app_slug=parsed.path[1:],
)
_, provider = req.get_app_provider()
if not req.wreply.startswith(provider.acs_url):
raise ValueError("Invalid wreply")
return req
def get_app_provider(self):
application = get_object_or_404(Application, slug=self.app_slug)
provider: WSFederationProvider = get_object_or_404(
WSFederationProvider, pk=application.provider_id
)
return application, provider

View File

@@ -0,0 +1,93 @@
"""WS-Fed Provider signals"""
from urllib.parse import urlencode, urlparse, urlunparse
from django.dispatch import receiver
from django.http import HttpRequest
from django.urls import reverse
from django.utils import timezone
from structlog.stdlib import get_logger
from authentik.core.models import AuthenticatedSession, User
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.constants import (
WS_FED_ACTION_SIGN_OUT_CLEANUP,
WS_FED_POST_KEY_ACTION,
)
from authentik.flows.models import in_memory_stage
from authentik.flows.views.executor import FlowExecutorView
from authentik.providers.iframe_logout import IframeLogoutStageView
from authentik.providers.saml.models import SAMLBindings, SAMLSession
from authentik.providers.saml.views.flows import (
PLAN_CONTEXT_SAML_LOGOUT_IFRAME_SESSIONS,
PLAN_CONTEXT_SAML_RELAY_STATE,
)
from authentik.stages.user_logout.models import UserLogoutStage
from authentik.stages.user_logout.stage import flow_pre_user_logout
LOGGER = get_logger()
@receiver(flow_pre_user_logout)
def handle_ws_fed_iframe_pre_user_logout(
sender, request: HttpRequest, user: User, executor: FlowExecutorView, **kwargs
):
"""Handle WS-Fed iframe logout when user logs out via flow"""
# Only proceed if this is actually a UserLogoutStage
if not isinstance(executor.current_stage, UserLogoutStage):
return
if not user.is_authenticated:
return
auth_session = AuthenticatedSession.from_request(request, user)
if not auth_session:
return
wsfed_sessions = SAMLSession.objects.filter(
session=auth_session,
user=user,
expires__gt=timezone.now(),
expiring=True,
# Only get WS-Federation provider sessions
provider__wsfederationprovider__isnull=False,
).select_related("provider__wsfederationprovider")
if not wsfed_sessions.exists():
LOGGER.debug("No sessions requiring IFrame frontchannel logout")
return
saml_sessions = []
relay_state = request.build_absolute_uri(
reverse("authentik_core:if-flow", kwargs={"flow_slug": executor.flow.slug})
)
# Store return URL in plan context as fallback if SP doesn't echo relay_state
executor.plan.context[PLAN_CONTEXT_SAML_RELAY_STATE] = relay_state
for session in wsfed_sessions:
provider: WSFederationProvider = session.provider.wsfederationprovider
parts = urlparse(str(provider.acs_url))
parts = parts._replace(
query=urlencode({WS_FED_POST_KEY_ACTION: WS_FED_ACTION_SIGN_OUT_CLEANUP})
)
logout_data = {
"url": urlunparse(parts),
"provider_name": provider.name,
"binding": SAMLBindings.REDIRECT,
}
saml_sessions.append(logout_data)
if saml_sessions:
executor.plan.context[PLAN_CONTEXT_SAML_LOGOUT_IFRAME_SESSIONS] = saml_sessions
# Stage already exists, don't reinject it
if not any(
binding.stage.view == IframeLogoutStageView for binding in executor.plan.bindings
):
iframe_stage = in_memory_stage(IframeLogoutStageView)
executor.plan.insert_stage(iframe_stage, index=1)
LOGGER.debug("WSFed iframe sessions gathered")

View File

@@ -0,0 +1,40 @@
from django.test import TestCase
from lxml import etree # nosec
from authentik.core.models import Application
from authentik.core.tests.utils import RequestFactory, create_test_flow
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.metadata import MetadataProcessor
from authentik.lib.generators import generate_id
from authentik.lib.xml import lxml_from_string
class TestWSFedMetadata(TestCase):
def setUp(self):
self.flow = create_test_flow()
self.provider = WSFederationProvider.objects.create(
name=generate_id(),
authorization_flow=self.flow,
)
self.app = Application.objects.create(
name=generate_id(), slug=generate_id(), provider=self.provider
)
self.factory = RequestFactory()
def test_metadata_generation(self):
request = self.factory.get("/")
metadata_a = MetadataProcessor(self.provider, request).build_entity_descriptor()
metadata_b = MetadataProcessor(self.provider, request).build_entity_descriptor()
self.assertEqual(metadata_a, metadata_b)
def test_schema(self):
"""Test that metadata generation is consistent"""
request = self.factory.get("/")
metadata = lxml_from_string(
MetadataProcessor(self.provider, request).build_entity_descriptor()
)
schema = etree.XMLSchema(
etree.parse(source="schemas/ws-federation.xsd", parser=etree.XMLParser()) # nosec
)
self.assertTrue(schema.validate(metadata))

View File

@@ -0,0 +1,85 @@
import xmlsec
from django.test import TestCase
from guardian.utils import get_anonymous_user
from lxml import etree # nosec
from authentik.core.models import Application
from authentik.core.tests.utils import RequestFactory, create_test_cert, create_test_flow
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.constants import (
NS_MAP,
WS_FED_ACTION_SIGN_IN,
WS_FED_POST_KEY_RESULT,
)
from authentik.enterprise.providers.ws_federation.processors.sign_in import (
SignInProcessor,
SignInRequest,
)
from authentik.lib.generators import generate_id
from authentik.lib.xml import lxml_from_string
class TestWSFedSignIn(TestCase):
def setUp(self):
self.flow = create_test_flow()
self.cert = create_test_cert()
self.provider = WSFederationProvider.objects.create(
name=generate_id(),
authorization_flow=self.flow,
signing_kp=self.cert,
)
self.app = Application.objects.create(
name=generate_id(), slug=generate_id(), provider=self.provider
)
self.factory = RequestFactory()
def test_token_gen(self):
request = self.factory.get("/", user=get_anonymous_user())
proc = SignInProcessor(
self.provider,
request,
SignInRequest(
wa=WS_FED_ACTION_SIGN_IN,
wtrealm="",
wreply="",
wctx=None,
app_slug="",
),
)
token = proc.response()[WS_FED_POST_KEY_RESULT]
root = lxml_from_string(token)
schema = etree.XMLSchema(
etree.parse(source="schemas/ws-trust.xsd", parser=etree.XMLParser()) # nosec
)
self.assertTrue(schema.validate(etree=root), schema.error_log)
def test_signature(self):
request = self.factory.get("/", user=get_anonymous_user())
proc = SignInProcessor(
self.provider,
request,
SignInRequest(
wa=WS_FED_ACTION_SIGN_IN,
wtrealm="",
wreply="",
wctx=None,
app_slug="",
),
)
token = proc.response()[WS_FED_POST_KEY_RESULT]
root = lxml_from_string(token)
xmlsec.tree.add_ids(root, ["ID"])
signature_nodes = root.xpath("//saml:Assertion/ds:Signature", namespaces=NS_MAP)
self.assertEqual(len(signature_nodes), 1)
signature_node = signature_nodes[0]
ctx = xmlsec.SignatureContext()
ctx.key = xmlsec.Key.from_memory(
self.cert.certificate_data,
xmlsec.constants.KeyDataFormatCertPem,
None,
)
ctx.verify(signature_node)

View File

@@ -0,0 +1,18 @@
"""WS Fed provider URLs"""
from django.urls import path
from authentik.enterprise.providers.ws_federation.api.providers import WSFederationProviderViewSet
from authentik.enterprise.providers.ws_federation.views import WSFedEntryView
urlpatterns = [
path(
"",
WSFedEntryView.as_view(),
name="wsfed",
),
]
api_urlpatterns = [
("providers/wsfed", WSFederationProviderViewSet),
]

View File

@@ -0,0 +1,162 @@
from django.http import Http404, HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from structlog.stdlib import get_logger
from authentik.core.models import Application, AuthenticatedSession
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.enterprise.providers.ws_federation.processors.constants import (
WS_FED_ACTION_SIGN_IN,
WS_FED_ACTION_SIGN_OUT,
)
from authentik.enterprise.providers.ws_federation.processors.sign_in import (
SignInProcessor,
SignInRequest,
)
from authentik.enterprise.providers.ws_federation.processors.sign_out import SignOutRequest
from authentik.flows.challenge import (
PLAN_CONTEXT_TITLE,
AutosubmitChallenge,
AutoSubmitChallengeResponse,
)
from authentik.flows.exceptions import FlowNonApplicableException
from authentik.flows.models import in_memory_stage
from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_SSO, FlowPlanner
from authentik.flows.stage import ChallengeStageView, SessionEndStage
from authentik.lib.views import bad_request_message
from authentik.policies.views import PolicyAccessView, RequestValidationError
from authentik.providers.saml.models import SAMLSession
from authentik.stages.consent.stage import (
PLAN_CONTEXT_CONSENT_HEADER,
PLAN_CONTEXT_CONSENT_PERMISSIONS,
)
PLAN_CONTEXT_WS_FED_REQUEST = "authentik/providers/ws_federation/request"
LOGGER = get_logger()
class WSFedEntryView(PolicyAccessView):
req: SignInRequest | SignOutRequest
def pre_permission_check(self):
self.action = self.request.GET.get("wa")
try:
if self.action == WS_FED_ACTION_SIGN_IN:
self.req = SignInRequest.parse(self.request)
elif self.action == WS_FED_ACTION_SIGN_OUT:
self.req = SignOutRequest.parse(self.request)
else:
raise RequestValidationError(
bad_request_message(self.request, "Invalid WS-Federation action")
)
except ValueError as exc:
LOGGER.warning("Invalid WS-Fed request", exc=exc)
raise RequestValidationError(
bad_request_message(self.request, "Invalid WS-Federation request")
) from None
def resolve_provider_application(self):
self.application, self.provider = self.req.get_app_provider()
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
if self.action == WS_FED_ACTION_SIGN_IN:
return self.ws_fed_sign_in()
elif self.action == WS_FED_ACTION_SIGN_OUT:
return self.ws_fed_sign_out()
else:
return HttpResponse("Unsupported WS-Federation action", status=400)
def ws_fed_sign_in(self) -> HttpResponse:
planner = FlowPlanner(self.provider.authorization_flow)
planner.allow_empty_flows = True
try:
plan = planner.plan(
self.request,
{
PLAN_CONTEXT_SSO: True,
PLAN_CONTEXT_APPLICATION: self.application,
PLAN_CONTEXT_CONSENT_HEADER: _("You're about to sign into %(application)s.")
% {"application": self.application.name},
PLAN_CONTEXT_CONSENT_PERMISSIONS: [],
PLAN_CONTEXT_WS_FED_REQUEST: self.req,
},
)
except FlowNonApplicableException:
raise Http404 from None
plan.append_stage(in_memory_stage(WSFedFlowFinalView))
return plan.to_redirect(
self.request,
self.provider.authorization_flow,
)
def ws_fed_sign_out(self) -> HttpResponse:
flow = self.provider.invalidation_flow or self.request.brand.flow_invalidation
planner = FlowPlanner(flow)
planner.allow_empty_flows = True
try:
plan = planner.plan(
self.request,
{
PLAN_CONTEXT_SSO: True,
PLAN_CONTEXT_APPLICATION: self.application,
PLAN_CONTEXT_WS_FED_REQUEST: self.req,
},
)
except FlowNonApplicableException:
raise Http404 from None
plan.append_stage(in_memory_stage(SessionEndStage))
return plan.to_redirect(self.request, flow)
class WSFedFlowFinalView(ChallengeStageView):
response_class = AutoSubmitChallengeResponse
def get(self, request, *args, **kwargs):
if PLAN_CONTEXT_WS_FED_REQUEST not in self.executor.plan.context:
self.logger.warning("No WS-Fed request in context")
return self.executor.stage_invalid()
return super().get(request, *args, **kwargs)
def get_challenge(self, *args, **kwargs):
application: Application = self.executor.plan.context[PLAN_CONTEXT_APPLICATION]
provider: WSFederationProvider = get_object_or_404(
WSFederationProvider, pk=application.provider_id
)
sign_in_req: SignInRequest = self.executor.plan.context[PLAN_CONTEXT_WS_FED_REQUEST]
proc = SignInProcessor(provider, self.request, sign_in_req)
response = proc.response()
saml_processor = proc.saml_processor
# Create SAMLSession to track this login
auth_session = AuthenticatedSession.from_request(self.request, self.request.user)
if auth_session:
# Since samlsessions should only exist uniquely for an active session and a provider
# any existing combination is likely an old, dead session
SAMLSession.objects.filter(
session_index=saml_processor.session_index, provider=provider
).delete()
SAMLSession.objects.update_or_create(
session_index=saml_processor.session_index,
provider=provider,
defaults={
"user": self.request.user,
"session": auth_session,
"name_id": saml_processor.name_id,
"name_id_format": saml_processor.name_id_format,
"expires": saml_processor.session_not_on_or_after_datetime,
"expiring": True,
},
)
return AutosubmitChallenge(
data={
"component": "ak-stage-autosubmit",
"title": self.executor.plan.context.get(
PLAN_CONTEXT_TITLE,
_("Redirecting to {app}...".format_map({"app": application.name})),
),
"url": sign_in_req.wreply,
"attrs": response,
},
)

View File

@@ -10,6 +10,7 @@ TENANT_APPS = [
"authentik.enterprise.providers.radius",
"authentik.enterprise.providers.scim",
"authentik.enterprise.providers.ssf",
"authentik.enterprise.providers.ws_federation",
"authentik.enterprise.reports",
"authentik.enterprise.search",
"authentik.enterprise.stages.authenticator_endpoint_gdtc",

View File

@@ -10,7 +10,7 @@ from django.core.cache import cache
from django.http import HttpRequest, HttpResponseNotFound
from django.templatetags.static import static
from lxml import etree # nosec
from lxml.etree import Element, SubElement # nosec
from lxml.etree import Element, SubElement, _Element # nosec
from requests.exceptions import ConnectionError, HTTPError, RequestException, Timeout
from authentik.lib.utils.dict import get_path_from_dict
@@ -109,7 +109,7 @@ def generate_avatar_from_name(
shape = "circle" if rounded else "rect"
font_weight = "600" if bold else "400"
root_element: Element = Element(f"{{{SVG_XML_NS}}}svg", nsmap=SVG_NS_MAP)
root_element: _Element = Element(f"{{{SVG_XML_NS}}}svg", nsmap=SVG_NS_MAP)
root_element.attrib["width"] = f"{size}px"
root_element.attrib["height"] = f"{size}px"
root_element.attrib["viewBox"] = f"0 0 {size} {size}"

View File

@@ -1,6 +1,6 @@
"""XML Utilities"""
from lxml.etree import XMLParser, fromstring # nosec
from lxml.etree import XMLParser, _Element, fromstring, tostring # nosec
def get_lxml_parser():
@@ -11,3 +11,13 @@ def get_lxml_parser():
def lxml_from_string(text: str):
"""Wrapper around fromstring"""
return fromstring(text, parser=get_lxml_parser()) # nosec
def remove_xml_newlines(parent: _Element, element: _Element):
"""Remove newlines in a given XML element, required for xmlsec
https://github.com/xmlsec/python-xmlsec/issues/196"""
old_element = element
new_node = fromstring(tostring(element, encoding=str).replace("\n", ""))
parent.replace(old_element, new_node)
return new_node

View File

@@ -244,6 +244,8 @@ class SAMLProviderViewSet(UsedByMixin, ModelViewSet):
ordering = ["name"]
search_fields = ["name"]
metadata_generator_class = MetadataProcessor
@extend_schema(
responses={
200: SAMLMetadataSerializer(many=False),
@@ -288,7 +290,7 @@ class SAMLProviderViewSet(UsedByMixin, ModelViewSet):
except ValueError:
raise Http404 from None
try:
proc = MetadataProcessor(provider, request)
proc = self.metadata_generator_class(provider, request)
proc.force_binding = request.query_params.get("force_binding", None)
metadata = proc.build_entity_descriptor()
if "download" in request.query_params:

View File

@@ -8,13 +8,14 @@ import xmlsec
from django.http import HttpRequest
from django.utils.timezone import now
from lxml import etree # nosec
from lxml.etree import Element, SubElement # nosec
from lxml.etree import Element, SubElement, _Element # nosec
from structlog.stdlib import get_logger
from authentik.core.expression.exceptions import PropertyMappingExpressionException
from authentik.events.models import Event, EventAction
from authentik.events.signals import get_login_event
from authentik.lib.utils.time import timedelta_from_string
from authentik.lib.xml import remove_xml_newlines
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.authn_request_parser import AuthNRequest
from authentik.providers.saml.utils import get_random_id
@@ -359,7 +360,7 @@ class AssertionProcessor:
response.append(self.get_assertion())
return response
def _sign(self, element: Element):
def _sign(self, element: _Element):
"""Sign an XML element based on the providers' configured signing settings"""
digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(
self.provider.digest_algorithm, xmlsec.constants.TransformSha1
@@ -389,11 +390,11 @@ class AssertionProcessor:
)
ctx.key = key
try:
ctx.sign(signature_node)
ctx.sign(remove_xml_newlines(element, signature_node))
except xmlsec.Error as exc:
raise InvalidSignature() from exc
def _encrypt(self, element: Element, parent: Element):
def _encrypt(self, element: _Element, parent: _Element):
"""Encrypt SAMLResponse EncryptedAssertion Element"""
# Create a standalone copy so namespace declarations are included in the encrypted content
element_xml = etree.tostring(element)

View File

@@ -5,9 +5,10 @@ from urllib.parse import quote, urlencode
import xmlsec
from lxml import etree # nosec
from lxml.etree import Element
from lxml.etree import Element, _Element
from authentik.core.models import User
from authentik.lib.xml import remove_xml_newlines
from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.utils import get_random_id
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode
@@ -134,7 +135,7 @@ class LogoutRequestProcessor:
"RelayState": self.relay_state or "",
}
def _sign_logout_request(self, logout_request: Element):
def _sign_logout_request(self, logout_request: _Element):
"""Sign the LogoutRequest element"""
signature_algorithm_transform = SIGN_ALGORITHM_TRANSFORM_MAP.get(
self.provider.signature_algorithm, xmlsec.constants.TransformRsaSha1
@@ -154,7 +155,7 @@ class LogoutRequestProcessor:
self._sign(logout_request)
def _sign(self, element: Element):
def _sign(self, element: _Element):
"""Sign an XML element based on the providers' configured signing settings"""
digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(
self.provider.digest_algorithm, xmlsec.constants.TransformSha1
@@ -183,7 +184,7 @@ class LogoutRequestProcessor:
xmlsec.constants.KeyDataFormatCertPem,
)
ctx.key = key
ctx.sign(signature_node)
ctx.sign(remove_xml_newlines(element, signature_node))
def _build_signable_query_string(self, params: dict) -> str:
"""Build query string for signing (order matters per SAML spec)"""

View File

@@ -6,8 +6,9 @@ from hashlib import sha256
import xmlsec # nosec
from django.http import HttpRequest
from django.urls import reverse
from lxml.etree import Element, SubElement, tostring # nosec
from lxml.etree import Element, SubElement, _Element, tostring # nosec
from authentik.lib.xml import remove_xml_newlines
from authentik.providers.saml.models import SAMLProvider
from authentik.providers.saml.utils.encoding import strip_pem_header
from authentik.sources.saml.processors.constants import (
@@ -117,7 +118,7 @@ class MetadataProcessor:
element.attrib["Location"] = url
yield element
def _prepare_signature(self, entity_descriptor: Element):
def _prepare_signature(self, entity_descriptor: _Element):
sign_algorithm_transform = SIGN_ALGORITHM_TRANSFORM_MAP.get(
self.provider.signature_algorithm, xmlsec.constants.TransformRsaSha1
)
@@ -129,7 +130,7 @@ class MetadataProcessor:
)
entity_descriptor.append(signature)
def _sign(self, entity_descriptor: Element):
def _sign(self, entity_descriptor: _Element):
digest_algorithm_transform = DIGEST_ALGORITHM_TRANSLATION_MAP.get(
self.provider.digest_algorithm, xmlsec.constants.TransformSha1
)
@@ -158,17 +159,12 @@ class MetadataProcessor:
xmlsec.constants.KeyDataFormatCertPem,
)
ctx.key = key
ctx.sign(signature_node)
ctx.sign(remove_xml_newlines(assertion, signature_node))
def build_entity_descriptor(self) -> str:
"""Build full EntityDescriptor"""
entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
entity_descriptor.attrib["ID"] = self.xml_id
entity_descriptor.attrib["entityID"] = self.provider.issuer
if self.provider.signing_kp:
self._prepare_signature(entity_descriptor)
def add_children(self, entity_descriptor: _Element):
self.add_idp_sso(entity_descriptor)
def add_idp_sso(self, entity_descriptor: _Element):
idp_sso_descriptor = SubElement(
entity_descriptor, f"{{{NS_SAML_METADATA}}}IDPSSODescriptor"
)
@@ -189,6 +185,17 @@ class MetadataProcessor:
for binding in self.get_sso_bindings():
idp_sso_descriptor.append(binding)
def build_entity_descriptor(self) -> str:
"""Build full EntityDescriptor"""
entity_descriptor = Element(f"{{{NS_SAML_METADATA}}}EntityDescriptor", nsmap=NS_MAP)
entity_descriptor.attrib["ID"] = self.xml_id
entity_descriptor.attrib["entityID"] = self.provider.issuer
if self.provider.signing_kp:
self._prepare_signature(entity_descriptor)
self.add_children(entity_descriptor)
if self.provider.signing_kp:
self._sign(entity_descriptor)

View File

@@ -2,12 +2,14 @@
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.http import HttpRequest
from django.urls import reverse
from django.utils import timezone
from structlog.stdlib import get_logger
from authentik.core.models import AuthenticatedSession, User
from authentik.flows.models import in_memory_stage
from authentik.flows.views.executor import FlowExecutorView
from authentik.providers.iframe_logout import IframeLogoutStageView
from authentik.providers.saml.models import SAMLBindings, SAMLLogoutMethods, SAMLSession
from authentik.providers.saml.native_logout import NativeLogoutStageView
@@ -25,7 +27,9 @@ LOGGER = get_logger()
@receiver(flow_pre_user_logout)
def handle_saml_iframe_pre_user_logout(sender, request, user, executor, **kwargs):
def handle_saml_iframe_pre_user_logout(
sender, request: HttpRequest, user: User, executor: FlowExecutorView, **kwargs
):
"""Handle SAML iframe logout when user logs out via flow"""
# Only proceed if this is actually a UserLogoutStage
@@ -113,7 +117,9 @@ def handle_saml_iframe_pre_user_logout(sender, request, user, executor, **kwargs
@receiver(flow_pre_user_logout)
def handle_flow_pre_user_logout(sender, request, user, executor, **kwargs):
def handle_flow_pre_user_logout(
sender, request: HttpRequest, user: User, executor: FlowExecutorView, **kwargs
):
"""Handle SAML native logout when user logs out via logout flow"""
# Only proceed if this is actually a UserLogoutStage

View File

@@ -191,6 +191,7 @@ SPECTACULAR_SETTINGS = {
"DeviceFactsOSFamily": "authentik.endpoints.facts.OSFamily",
"StageModeEnum": "authentik.endpoints.models.StageMode",
"LicenseSummaryStatusEnum": "authentik.enterprise.models.LicenseUsageStatus",
"SAMLLogoutMethods": "authentik.providers.saml.models.SAMLLogoutMethods",
},
"ENUM_ADD_EXPLICIT_BLANK_NULL_CHOICE": False,
"ENUM_GENERATE_CHOICE_DESCRIPTION": False,

View File

@@ -3,6 +3,7 @@ import warnings
from cryptography.hazmat.backends.openssl.backend import backend
from defusedxml import defuse_stdlib
from xmlsec import base64_default_line_size
from authentik.lib.config import CONFIG
@@ -19,6 +20,7 @@ def setup():
)
defuse_stdlib()
base64_default_line_size(size=8192)
if CONFIG.get_bool("compliance.fips.enabled", False):
backend._enable_fips()

View File

@@ -8,6 +8,7 @@ from django.http import HttpRequest
from lxml import etree # nosec
from lxml.etree import Element # nosec
from authentik.lib.xml import remove_xml_newlines
from authentik.providers.saml.utils import get_random_id
from authentik.providers.saml.utils.encoding import deflate_and_base64_encode
from authentik.providers.saml.utils.time import get_time_string
@@ -120,7 +121,7 @@ class RequestProcessor:
key_info = xmlsec.template.ensure_key_info(signature_node)
xmlsec.template.add_x509_data(key_info)
ctx.sign(signature_node)
ctx.sign(remove_xml_newlines(auth_n_request, signature_node))
return etree.tostring(auth_n_request).decode()

View File

@@ -976,6 +976,46 @@
}
}
},
{
"type": "object",
"required": [
"model",
"identifiers"
],
"properties": {
"model": {
"const": "authentik_providers_ws_federation.wsfederationprovider"
},
"id": {
"type": "string"
},
"state": {
"type": "string",
"enum": [
"absent",
"created",
"must_created",
"present"
],
"default": "present"
},
"conditions": {
"type": "array",
"items": {
"type": "boolean"
}
},
"permissions": {
"$ref": "#/$defs/model_authentik_providers_ws_federation.wsfederationprovider_permissions"
},
"attrs": {
"$ref": "#/$defs/model_authentik_providers_ws_federation.wsfederationprovider"
},
"identifiers": {
"$ref": "#/$defs/model_authentik_providers_ws_federation.wsfederationprovider"
}
}
},
{
"type": "object",
"required": [
@@ -5727,6 +5767,10 @@
"authentik_providers_ssf.view_ssfprovider",
"authentik_providers_ssf.view_stream",
"authentik_providers_ssf.view_streamevent",
"authentik_providers_ws_federation.add_wsfederationprovider",
"authentik_providers_ws_federation.change_wsfederationprovider",
"authentik_providers_ws_federation.delete_wsfederationprovider",
"authentik_providers_ws_federation.view_wsfederationprovider",
"authentik_rbac.access_admin_interface",
"authentik_rbac.add_initialpermissions",
"authentik_rbac.add_role",
@@ -7085,6 +7129,162 @@
}
}
},
"model_authentik_providers_ws_federation.wsfederationprovider": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"title": "Name"
},
"authentication_flow": {
"type": "string",
"format": "uuid",
"title": "Authentication flow",
"description": "Flow used for authentication when the associated application is accessed by an un-authenticated user."
},
"authorization_flow": {
"type": "string",
"format": "uuid",
"title": "Authorization flow",
"description": "Flow used when authorizing this provider."
},
"invalidation_flow": {
"type": "string",
"format": "uuid",
"title": "Invalidation flow",
"description": "Flow used ending the session from a provider."
},
"property_mappings": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"title": "Property mappings"
},
"reply_url": {
"type": "string",
"format": "uri",
"minLength": 1,
"title": "Reply url"
},
"assertion_valid_not_before": {
"type": "string",
"minLength": 1,
"title": "Assertion valid not before",
"description": "Assertion valid not before current time + this value (Format: hours=-1;minutes=-2;seconds=-3)."
},
"assertion_valid_not_on_or_after": {
"type": "string",
"minLength": 1,
"title": "Assertion valid not on or after",
"description": "Assertion not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3)."
},
"session_valid_not_on_or_after": {
"type": "string",
"minLength": 1,
"title": "Session valid not on or after",
"description": "Session not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3)."
},
"name_id_mapping": {
"type": "string",
"format": "uuid",
"title": "NameID Property Mapping",
"description": "Configure how the NameID value will be created. When left empty, the NameIDPolicy of the incoming request will be considered"
},
"authn_context_class_ref_mapping": {
"type": "string",
"format": "uuid",
"title": "AuthnContextClassRef Property Mapping",
"description": "Configure how the AuthnContextClassRef value will be created. When left empty, the AuthnContextClassRef will be set based on which authentication methods the user used to authenticate."
},
"digest_algorithm": {
"type": "string",
"enum": [
"http://www.w3.org/2000/09/xmldsig#sha1",
"http://www.w3.org/2001/04/xmlenc#sha256",
"http://www.w3.org/2001/04/xmldsig-more#sha384",
"http://www.w3.org/2001/04/xmlenc#sha512"
],
"title": "Digest algorithm"
},
"signature_algorithm": {
"type": "string",
"enum": [
"http://www.w3.org/2000/09/xmldsig#rsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
"http://www.w3.org/2000/09/xmldsig#dsa-sha1"
],
"title": "Signature algorithm"
},
"signing_kp": {
"type": "string",
"format": "uuid",
"title": "Signing Keypair",
"description": "Keypair used to sign outgoing Responses going to the Service Provider."
},
"encryption_kp": {
"type": "string",
"format": "uuid",
"title": "Encryption Keypair",
"description": "When selected, incoming assertions are encrypted by the IdP using the public key of the encryption keypair. The assertion is decrypted by the SP using the the private key."
},
"sign_assertion": {
"type": "boolean",
"title": "Sign assertion"
},
"sign_logout_request": {
"type": "boolean",
"title": "Sign logout request"
},
"default_name_id_policy": {
"type": "string",
"enum": [
"urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
"urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName",
"urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName",
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
],
"title": "Default name id policy"
}
},
"required": []
},
"model_authentik_providers_ws_federation.wsfederationprovider_permissions": {
"type": "array",
"items": {
"type": "object",
"required": [
"permission"
],
"properties": {
"permission": {
"type": "string",
"enum": [
"add_wsfederationprovider",
"change_wsfederationprovider",
"delete_wsfederationprovider",
"view_wsfederationprovider"
]
},
"user": {
"type": "integer"
},
"role": {
"type": "string"
}
}
}
},
"model_authentik_reports.dataexport": {
"type": "object",
"properties": {
@@ -8289,6 +8489,7 @@
"authentik.enterprise.providers.radius",
"authentik.enterprise.providers.scim",
"authentik.enterprise.providers.ssf",
"authentik.enterprise.providers.ws_federation",
"authentik.enterprise.reports",
"authentik.enterprise.search",
"authentik.enterprise.stages.authenticator_endpoint_gdtc",
@@ -8417,6 +8618,7 @@
"authentik_providers_microsoft_entra.microsoftentraprovider",
"authentik_providers_microsoft_entra.microsoftentraprovidermapping",
"authentik_providers_ssf.ssfprovider",
"authentik_providers_ws_federation.wsfederationprovider",
"authentik_reports.dataexport",
"authentik_stages_authenticator_endpoint_gdtc.authenticatorendpointgdtcstage",
"authentik_stages_mtls.mutualtlsstage",
@@ -10929,6 +11131,10 @@
"authentik_providers_ssf.view_ssfprovider",
"authentik_providers_ssf.view_stream",
"authentik_providers_ssf.view_streamevent",
"authentik_providers_ws_federation.add_wsfederationprovider",
"authentik_providers_ws_federation.change_wsfederationprovider",
"authentik_providers_ws_federation.delete_wsfederationprovider",
"authentik_providers_ws_federation.view_wsfederationprovider",
"authentik_rbac.access_admin_interface",
"authentik_rbac.add_initialpermissions",
"authentik_rbac.add_role",

View File

@@ -179,7 +179,8 @@ skip = [
"./gen-go-api", # Generated Go API
"./data", # Media files
"./media", # Legacy media files
"**vendored**" # Vendored files
"./schemas/**", # XML Schemas
"**vendored**", # Vendored files
]
dictionary = ".github/codespell-dictionary.txt,-"
ignore-words = ".github/codespell-words.txt"

View File

@@ -19432,6 +19432,433 @@ paths:
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
/providers/wsfed/:
get:
operationId: providers_wsfed_list
description: WSFederationProvider Viewset
parameters:
- in: query
name: acs_url
schema:
type: string
- in: query
name: assertion_valid_not_before
schema:
type: string
- in: query
name: assertion_valid_not_on_or_after
schema:
type: string
- in: query
name: audience
schema:
type: string
- in: query
name: authentication_flow
schema:
type: string
format: uuid
- in: query
name: authn_context_class_ref_mapping
schema:
type: string
format: uuid
- in: query
name: authorization_flow
schema:
type: string
format: uuid
- in: query
name: backchannel_application
schema:
type: string
format: uuid
- in: query
name: default_name_id_policy
schema:
type: string
enum:
- urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName
- urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
- urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
- urn:oasis:names:tc:SAML:2.0:nameid-format:WindowsDomainQualifiedName
- urn:oasis:names:tc:SAML:2.0:nameid-format:persistent
- urn:oasis:names:tc:SAML:2.0:nameid-format:transient
- in: query
name: default_relay_state
schema:
type: string
- in: query
name: digest_algorithm
schema:
type: string
enum:
- http://www.w3.org/2000/09/xmldsig#sha1
- http://www.w3.org/2001/04/xmldsig-more#sha384
- http://www.w3.org/2001/04/xmlenc#sha256
- http://www.w3.org/2001/04/xmlenc#sha512
- in: query
name: encryption_kp
schema:
type: string
format: uuid
- in: query
name: invalidation_flow
schema:
type: string
format: uuid
- in: query
name: is_backchannel
schema:
type: boolean
- in: query
name: issuer
schema:
type: string
- in: query
name: logout_method
schema:
type: string
enum:
- backchannel
- frontchannel_iframe
- frontchannel_native
description: |+
Method to use for logout. Front-channel iframe loads all logout URLs simultaneously in hidden iframes. Front-channel native uses your active browser tab to send post requests and redirect to providers. Back-channel sends logout requests directly from the server without user interaction (requires POST SLS binding).
- $ref: '#/components/parameters/QueryName'
- in: query
name: name_id_mapping
schema:
type: string
format: uuid
- $ref: '#/components/parameters/QueryPaginationOrdering'
- $ref: '#/components/parameters/QueryPaginationPage'
- $ref: '#/components/parameters/QueryPaginationPageSize'
- in: query
name: property_mappings
schema:
type: array
items:
type: string
format: uuid
explode: true
style: form
- $ref: '#/components/parameters/QuerySearch'
- in: query
name: session_valid_not_on_or_after
schema:
type: string
- in: query
name: sign_assertion
schema:
type: boolean
- in: query
name: sign_logout_request
schema:
type: boolean
- in: query
name: sign_response
schema:
type: boolean
- in: query
name: signature_algorithm
schema:
type: string
enum:
- http://www.w3.org/2000/09/xmldsig#dsa-sha1
- http://www.w3.org/2000/09/xmldsig#rsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
- in: query
name: signing_kp
schema:
type: string
format: uuid
- in: query
name: sls_binding
schema:
type: string
enum:
- post
- redirect
description: |+
This determines how authentik sends the logout response back to the Service Provider.
- in: query
name: sls_url
schema:
type: string
- in: query
name: sp_binding
schema:
type: string
title: Service Provider Binding
enum:
- post
- redirect
description: |+
This determines how authentik sends the response back to the Service Provider.
- in: query
name: verification_kp
schema:
type: string
format: uuid
tags:
- providers
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedWSFederationProviderList'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
post:
operationId: providers_wsfed_create
description: WSFederationProvider Viewset
tags:
- providers
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProviderRequest'
required: true
security:
- authentik: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProvider'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
/providers/wsfed/{id}/:
get:
operationId: providers_wsfed_retrieve
description: WSFederationProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProvider'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
put:
operationId: providers_wsfed_update
description: WSFederationProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProviderRequest'
required: true
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProvider'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
patch:
operationId: providers_wsfed_partial_update
description: WSFederationProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedWSFederationProviderRequest'
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/WSFederationProvider'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
delete:
operationId: providers_wsfed_destroy
description: WSFederationProvider Viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
security:
- authentik: []
responses:
'204':
description: No response body
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
/providers/wsfed/{id}/metadata/:
get:
operationId: providers_wsfed_metadata_retrieve
description: Return metadata as XML string
parameters:
- in: query
name: download
schema:
type: boolean
- in: query
name: force_binding
schema:
type: string
enum:
- urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST
- urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect
description: Optionally force the metadata to only include one binding.
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
security:
- authentik: []
- {}
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SAMLMetadata'
application/xml:
schema:
$ref: '#/components/schemas/SAMLMetadata'
description: ''
'404':
description: Provider has no application assigned
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
/providers/wsfed/{id}/preview_user/:
get:
operationId: providers_wsfed_preview_user_retrieve
description: Preview user data for provider
parameters:
- in: query
name: for_user
schema:
type: integer
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PropertyMappingPreview'
description: ''
'400':
description: Bad request
'403':
$ref: '#/components/responses/GenericErrorResponse'
/providers/wsfed/{id}/used_by/:
get:
operationId: providers_wsfed_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this WS-Federation Provider.
required: true
tags:
- providers
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UsedBy'
description: ''
'400':
$ref: '#/components/responses/ValidationErrorResponse'
'403':
$ref: '#/components/responses/GenericErrorResponse'
/rac/connection_tokens/:
get:
operationId: rac_connection_tokens_list
@@ -20126,6 +20553,7 @@ paths:
- authentik_providers_scim.scimmapping
- authentik_providers_scim.scimprovider
- authentik_providers_ssf.ssfprovider
- authentik_providers_ws_federation.wsfederationprovider
- authentik_rbac.initialpermissions
- authentik_rbac.role
- authentik_reports.dataexport
@@ -33319,6 +33747,7 @@ components:
- authentik.enterprise.providers.radius
- authentik.enterprise.providers.scim
- authentik.enterprise.providers.ssf
- authentik.enterprise.providers.ws_federation
- authentik.enterprise.reports
- authentik.enterprise.search
- authentik.enterprise.stages.authenticator_endpoint_gdtc
@@ -41892,6 +42321,7 @@ components:
- authentik_providers_microsoft_entra.microsoftentraprovider
- authentik_providers_microsoft_entra.microsoftentraprovidermapping
- authentik_providers_ssf.ssfprovider
- authentik_providers_ws_federation.wsfederationprovider
- authentik_reports.dataexport
- authentik_stages_authenticator_endpoint_gdtc.authenticatorendpointgdtcstage
- authentik_stages_mtls.mutualtlsstage
@@ -45539,6 +45969,21 @@ components:
- pagination
- results
- autocomplete
PaginatedWSFederationProviderList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/WSFederationProvider'
autocomplete:
$ref: '#/components/schemas/Autocomplete'
required:
- pagination
- results
- autocomplete
PaginatedWebAuthnDeviceList:
type: object
properties:
@@ -48868,7 +49313,7 @@ components:
to the Service Provider.
logout_method:
allOf:
- $ref: '#/components/schemas/SAMLProviderLogoutMethodEnum'
- $ref: '#/components/schemas/SAMLLogoutMethods'
description: Method to use for logout. Front-channel iframe loads all logout
URLs simultaneously in hidden iframes. Front-channel native uses your
active browser tab to send post requests and redirect to providers. Back-channel
@@ -49725,6 +50170,91 @@ components:
$ref: '#/components/schemas/UserTypeEnum'
user_path_template:
type: string
PatchedWSFederationProviderRequest:
type: object
description: WSFederationProvider Serializer
properties:
name:
type: string
minLength: 1
authentication_flow:
type: string
format: uuid
nullable: true
description: Flow used for authentication when the associated application
is accessed by an un-authenticated user.
authorization_flow:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
type: string
format: uuid
reply_url:
type: string
format: uri
minLength: 1
assertion_valid_not_before:
type: string
minLength: 1
description: 'Assertion valid not before current time + this value (Format:
hours=-1;minutes=-2;seconds=-3).'
assertion_valid_not_on_or_after:
type: string
minLength: 1
description: 'Assertion not valid on or after current time + this value
(Format: hours=1;minutes=2;seconds=3).'
session_valid_not_on_or_after:
type: string
minLength: 1
description: 'Session not valid on or after current time + this value (Format:
hours=1;minutes=2;seconds=3).'
name_id_mapping:
type: string
format: uuid
nullable: true
title: NameID Property Mapping
description: Configure how the NameID value will be created. When left empty,
the NameIDPolicy of the incoming request will be considered
authn_context_class_ref_mapping:
type: string
format: uuid
nullable: true
title: AuthnContextClassRef Property Mapping
description: Configure how the AuthnContextClassRef value will be created.
When left empty, the AuthnContextClassRef will be set based on which authentication
methods the user used to authenticate.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:
$ref: '#/components/schemas/SignatureAlgorithmEnum'
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair used to sign outgoing Responses going to the Service
Provider.
encryption_kp:
type: string
format: uuid
nullable: true
title: Encryption Keypair
description: When selected, incoming assertions are encrypted by the IdP
using the public key of the encryption keypair. The assertion is decrypted
by the SP using the the private key.
sign_assertion:
type: boolean
sign_logout_request:
type: boolean
default_name_id_policy:
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
PatchedWebAuthnDeviceRequest:
type: object
description: Serializer for WebAuthn authenticator devices
@@ -50711,6 +51241,7 @@ components:
- authentik_providers_saml.samlprovider
- authentik_providers_scim.scimprovider
- authentik_providers_ssf.ssfprovider
- authentik_providers_ws_federation.wsfederationprovider
type: string
ProviderTypeEnum:
enum:
@@ -51929,6 +52460,12 @@ components:
- redirect
- post
type: string
SAMLLogoutMethods:
enum:
- frontchannel_iframe
- frontchannel_native
- backchannel
type: string
SAMLMetadata:
type: object
description: SAML Provider Metadata serializer
@@ -52183,7 +52720,7 @@ components:
to the Service Provider.
logout_method:
allOf:
- $ref: '#/components/schemas/SAMLProviderLogoutMethodEnum'
- $ref: '#/components/schemas/SAMLLogoutMethods'
description: Method to use for logout. Front-channel iframe loads all logout
URLs simultaneously in hidden iframes. Front-channel native uses your
active browser tab to send post requests and redirect to providers. Back-channel
@@ -52259,12 +52796,6 @@ components:
- file
- invalidation_flow
- name
SAMLProviderLogoutMethodEnum:
enum:
- frontchannel_iframe
- frontchannel_native
- backchannel
type: string
SAMLProviderRequest:
type: object
description: SAMLProvider Serializer
@@ -52383,7 +52914,7 @@ components:
to the Service Provider.
logout_method:
allOf:
- $ref: '#/components/schemas/SAMLProviderLogoutMethodEnum'
- $ref: '#/components/schemas/SAMLLogoutMethods'
description: Method to use for logout. Front-channel iframe loads all logout
URLs simultaneously in hidden iframes. Front-channel native uses your
active browser tab to send post requests and redirect to providers. Back-channel
@@ -56489,6 +57020,240 @@ components:
- id
- timestamp
- version
WSFederationProvider:
type: object
description: WSFederationProvider Serializer
properties:
pk:
type: integer
readOnly: true
title: ID
name:
type: string
authentication_flow:
type: string
format: uuid
nullable: true
description: Flow used for authentication when the associated application
is accessed by an un-authenticated user.
authorization_flow:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
type: string
format: uuid
component:
type: string
description: Get object component so that we know how to edit the object
readOnly: true
assigned_application_slug:
type: string
description: Internal application name, used in URLs.
readOnly: true
assigned_application_name:
type: string
description: Application's display Name.
readOnly: true
assigned_backchannel_application_slug:
type: string
description: Internal application name, used in URLs.
readOnly: true
assigned_backchannel_application_name:
type: string
description: Application's display Name.
readOnly: true
verbose_name:
type: string
description: Return object's verbose_name
readOnly: true
verbose_name_plural:
type: string
description: Return object's plural verbose_name
readOnly: true
meta_model_name:
type: string
description: Return internal model name
readOnly: true
reply_url:
type: string
format: uri
assertion_valid_not_before:
type: string
description: 'Assertion valid not before current time + this value (Format:
hours=-1;minutes=-2;seconds=-3).'
assertion_valid_not_on_or_after:
type: string
description: 'Assertion not valid on or after current time + this value
(Format: hours=1;minutes=2;seconds=3).'
session_valid_not_on_or_after:
type: string
description: 'Session not valid on or after current time + this value (Format:
hours=1;minutes=2;seconds=3).'
name_id_mapping:
type: string
format: uuid
nullable: true
title: NameID Property Mapping
description: Configure how the NameID value will be created. When left empty,
the NameIDPolicy of the incoming request will be considered
authn_context_class_ref_mapping:
type: string
format: uuid
nullable: true
title: AuthnContextClassRef Property Mapping
description: Configure how the AuthnContextClassRef value will be created.
When left empty, the AuthnContextClassRef will be set based on which authentication
methods the user used to authenticate.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:
$ref: '#/components/schemas/SignatureAlgorithmEnum'
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair used to sign outgoing Responses going to the Service
Provider.
encryption_kp:
type: string
format: uuid
nullable: true
title: Encryption Keypair
description: When selected, incoming assertions are encrypted by the IdP
using the public key of the encryption keypair. The assertion is decrypted
by the SP using the the private key.
sign_assertion:
type: boolean
sign_logout_request:
type: boolean
default_name_id_policy:
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
url_download_metadata:
type: string
description: Get metadata download URL
readOnly: true
url_wsfed:
type: string
description: Get WS-Fed url
readOnly: true
wtrealm:
type: string
readOnly: true
required:
- assigned_application_name
- assigned_application_slug
- assigned_backchannel_application_name
- assigned_backchannel_application_slug
- authorization_flow
- component
- invalidation_flow
- meta_model_name
- name
- pk
- reply_url
- url_download_metadata
- url_wsfed
- verbose_name
- verbose_name_plural
- wtrealm
WSFederationProviderRequest:
type: object
description: WSFederationProvider Serializer
properties:
name:
type: string
minLength: 1
authentication_flow:
type: string
format: uuid
nullable: true
description: Flow used for authentication when the associated application
is accessed by an un-authenticated user.
authorization_flow:
type: string
format: uuid
description: Flow used when authorizing this provider.
invalidation_flow:
type: string
format: uuid
description: Flow used ending the session from a provider.
property_mappings:
type: array
items:
type: string
format: uuid
reply_url:
type: string
format: uri
minLength: 1
assertion_valid_not_before:
type: string
minLength: 1
description: 'Assertion valid not before current time + this value (Format:
hours=-1;minutes=-2;seconds=-3).'
assertion_valid_not_on_or_after:
type: string
minLength: 1
description: 'Assertion not valid on or after current time + this value
(Format: hours=1;minutes=2;seconds=3).'
session_valid_not_on_or_after:
type: string
minLength: 1
description: 'Session not valid on or after current time + this value (Format:
hours=1;minutes=2;seconds=3).'
name_id_mapping:
type: string
format: uuid
nullable: true
title: NameID Property Mapping
description: Configure how the NameID value will be created. When left empty,
the NameIDPolicy of the incoming request will be considered
authn_context_class_ref_mapping:
type: string
format: uuid
nullable: true
title: AuthnContextClassRef Property Mapping
description: Configure how the AuthnContextClassRef value will be created.
When left empty, the AuthnContextClassRef will be set based on which authentication
methods the user used to authenticate.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:
$ref: '#/components/schemas/SignatureAlgorithmEnum'
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair used to sign outgoing Responses going to the Service
Provider.
encryption_kp:
type: string
format: uuid
nullable: true
title: Encryption Keypair
description: When selected, incoming assertions are encrypted by the IdP
using the public key of the encryption keypair. The assertion is decrypted
by the SP using the the private key.
sign_assertion:
type: boolean
sign_logout_request:
type: boolean
default_name_id_policy:
$ref: '#/components/schemas/SAMLNameIDPolicyEnum'
required:
- authorization_flow
- invalidation_flow
- name
- reply_url
WebAuthnDevice:
type: object
description: Serializer for WebAuthn authenticator devices
@@ -56570,6 +57335,7 @@ components:
- $ref: '#/components/schemas/SAMLProviderRequest'
- $ref: '#/components/schemas/SCIMProviderRequest'
- $ref: '#/components/schemas/SSFProviderRequest'
- $ref: '#/components/schemas/WSFederationProviderRequest'
discriminator:
propertyName: provider_model
mapping:
@@ -56583,6 +57349,7 @@ components:
authentik_providers_saml.samlprovider: '#/components/schemas/SAMLProviderRequest'
authentik_providers_scim.scimprovider: '#/components/schemas/SCIMProviderRequest'
authentik_providers_ssf.ssfprovider: '#/components/schemas/SSFProviderRequest'
authentik_providers_ws_federation.wsfederationprovider: '#/components/schemas/WSFederationProviderRequest'
securitySchemes:
authentik:
type: http

145
schemas/authorization.xsd Normal file
View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the
implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available;
neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS
specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made
available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users
of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may
cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © OASIS Open 2002-2007. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist
in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the
above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified
in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications,
in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate
it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an AS IS basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'
xmlns:tns='http://docs.oasis-open.org/wsfed/authorization/200706'
targetNamespace='http://docs.oasis-open.org/wsfed/authorization/200706'
elementFormDefault='qualified' >
<xs:import namespace='http://www.w3.org/2001/04/xmlenc#'
schemaLocation='http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd'/>
<!-- Section 9.2 -->
<xs:element name='AdditionalContext' type='tns:AdditionalContextType' />
<xs:complexType name='AdditionalContextType' >
<xs:sequence>
<xs:element name='ContextItem' type='tns:ContextItemType' minOccurs='0' maxOccurs='unbounded' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='ContextItemType' >
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:choice>
<xs:attribute name='Name' type='xs:anyURI' use='required' />
<xs:attribute name='Scope' type='xs:anyURI' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 9.3 -->
<xs:element name='ClaimType' type='tns:ClaimType' />
<xs:complexType name='ClaimType' >
<xs:sequence>
<xs:element name="DisplayName" type="tns:DisplayNameType" minOccurs="0" maxOccurs="1" />
<xs:element name="Description" type="tns:DescriptionType" minOccurs="0" maxOccurs="1" />
<xs:element name="DisplayValue" type="tns:DisplayValueType" minOccurs="0" maxOccurs="1" />
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:element name='EncryptedValue' type='tns:EncryptedValueType' minOccurs='1' maxOccurs='1' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='1' />
<xs:element name='ConstrainedValue' type='tns:ConstrainedValueType' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:choice>
</xs:sequence>
<xs:attribute name='Uri' type='xs:anyURI' use='required' />
<xs:attribute name='Optional' type='xs:boolean' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name="DisplayNameType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="DescriptionType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="DisplayValueType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="EncryptedValueType">
<xs:sequence>
<xs:element ref="xenc:EncryptedData" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="DecryptionCondition" type="xs:anyURI" use="optional"/>
</xs:complexType>
<xs:complexType name="StructuredValueType">
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 9.3.1 -->
<xs:complexType name='ConstrainedValueType'>
<xs:sequence>
<xs:choice minOccurs='1'>
<xs:element name='ValueLessThan' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueLessThanOrEqual' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueGreaterThan' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueGreaterThanOrEqual' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueInRangen' type='tns:ValueInRangeType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueOneOf' type='tns:ConstrainedManyValueType' minOccurs='1' maxOccurs='1'/>
</xs:choice>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='AssertConstraint' type='xs:boolean' use='optional' />
</xs:complexType>
<xs:complexType name='ValueInRangeType'>
<xs:sequence>
<xs:element name='ValueUpperBound' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueLowerBound' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
</xs:sequence>
</xs:complexType>
<xs:complexType name='ConstrainedSingleValueType'>
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='1' />
</xs:choice>
</xs:complexType>
<xs:complexType name='ConstrainedManyValueType'>
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='unbounded' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='unbounded' />
</xs:choice>
</xs:complexType>
</xs:schema>

View File

@@ -0,0 +1,195 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © OASIS Open 2002-2004. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an “AS IS” basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-->
<xsd:schema targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all" version="0.2">
<xsd:import namespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" schemaLocation="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"/>
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/xml.xsd"/>
<xsd:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd"/>
<xsd:complexType name="AttributedString">
<xsd:annotation>
<xsd:documentation>This type represents an element with arbitrary attributes.</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute ref="wsu:Id"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="PasswordString">
<xsd:annotation>
<xsd:documentation>This type is used for password elements per Section 4.1.</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="wsse:AttributedString">
<xsd:attribute name="Type" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="EncodedString">
<xsd:annotation>
<xsd:documentation>This type is used for elements containing stringified binary data.</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="wsse:AttributedString">
<xsd:attribute name="EncodingType" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="UsernameTokenType">
<xsd:annotation>
<xsd:documentation>This type represents a username token per Section 4.1</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="Username" type="wsse:AttributedString"/>
<xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute ref="wsu:Id"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:complexType name="BinarySecurityTokenType">
<xsd:annotation>
<xsd:documentation>A security token that is encoded in binary</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="wsse:EncodedString">
<xsd:attribute name="ValueType" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="KeyIdentifierType">
<xsd:annotation>
<xsd:documentation>A security token key identifier</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="wsse:EncodedString">
<xsd:attribute name="ValueType" type="xsd:anyURI"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="tUsage">
<xsd:annotation>
<xsd:documentation>Typedef to allow a list of usages (as URIs).</xsd:documentation>
</xsd:annotation>
<xsd:list itemType="xsd:anyURI"/>
</xsd:simpleType>
<xsd:attribute name="Usage" type="tUsage">
<xsd:annotation>
<xsd:documentation>This global attribute is used to indicate the usage of a referenced or indicated token within the containing context</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:complexType name="ReferenceType">
<xsd:annotation>
<xsd:documentation>This type represents a reference to an external security token.</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="URI" type="xsd:anyURI"/>
<xsd:attribute name="ValueType" type="xsd:anyURI"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:complexType name="EmbeddedType">
<xsd:annotation>
<xsd:documentation>This type represents a reference to an embedded security token.</xsd:documentation>
</xsd:annotation>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:any processContents="lax"/>
</xsd:choice>
<xsd:attribute name="ValueType" type="xsd:anyURI"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:complexType name="SecurityTokenReferenceType">
<xsd:annotation>
<xsd:documentation>This type is used reference a security token.</xsd:documentation>
</xsd:annotation>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:any processContents="lax"/>
</xsd:choice>
<xsd:attribute ref="wsu:Id"/>
<xsd:attribute ref="wsse:Usage"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:complexType name="SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This complexType defines header block to use for security-relevant data directed at a specific SOAP actor.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The use of "any" is to allow extensibility and different forms of security data.</xsd:documentation>
</xsd:annotation>
</xsd:any>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:complexType name="TransformationParametersType">
<xsd:annotation>
<xsd:documentation>This complexType defines a container for elements to be specified from any namespace as properties/parameters of a DSIG transformation.</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The use of "any" is to allow extensibility from any namespace.</xsd:documentation>
</xsd:annotation>
</xsd:any>
</xsd:sequence>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>
<xsd:element name="UsernameToken" type="wsse:UsernameTokenType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:UsernameToken element per Section 4.1.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="BinarySecurityToken" type="wsse:BinarySecurityTokenType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:BinarySecurityToken element per Section 4.2.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Reference" type="wsse:ReferenceType">
<xsd:annotation>
<xsd:documentation>This element defines a security token reference</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Embedded" type="wsse:EmbeddedType">
<xsd:annotation>
<xsd:documentation>This element defines a security token embedded reference</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="KeyIdentifier" type="wsse:KeyIdentifierType">
<xsd:annotation>
<xsd:documentation>This element defines a key identifier reference</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="SecurityTokenReference" type="wsse:SecurityTokenReferenceType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:SecurityTokenReference per Section 4.3.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Security" type="wsse:SecurityHeaderType">
<xsd:annotation>
<xsd:documentation>This element defines the wsse:Security SOAP header element per Section 4.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="TransformationParameters" type="wsse:TransformationParametersType">
<xsd:annotation>
<xsd:documentation>This element contains properties for transformations from any namespace, including DSIG.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Password" type="wsse:PasswordString"/>
<xsd:element name="Nonce" type="wsse:EncodedString"/>
<xsd:simpleType name="FaultcodeEnum">
<xsd:restriction base="xsd:QName">
<xsd:enumeration value="wsse:UnsupportedSecurityToken"/>
<xsd:enumeration value="wsse:UnsupportedAlgorithm"/>
<xsd:enumeration value="wsse:InvalidSecurity"/>
<xsd:enumeration value="wsse:InvalidSecurityToken"/>
<xsd:enumeration value="wsse:FailedAuthentication"/>
<xsd:enumeration value="wsse:FailedCheck"/>
<xsd:enumeration value="wsse:SecurityTokenUnavailable"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © OASIS Open 2002-2004. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications, in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an “AS IS” basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-->
<xsd:schema targetNamespace="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
elementFormDefault="qualified" attributeFormDefault="unqualified" version="0.1">
<!-- // Fault Codes /////////////////////////////////////////// -->
<xsd:simpleType name="tTimestampFault">
<xsd:annotation>
<xsd:documentation>
This type defines the fault code value for Timestamp message expiration.
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:QName">
<xsd:enumeration value="wsu:MessageExpired"/>
</xsd:restriction>
</xsd:simpleType>
<!-- // Global attributes //////////////////////////////////// -->
<xsd:attribute name="Id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation>
This global attribute supports annotating arbitrary elements with an ID.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attributeGroup name="commonAtts">
<xsd:annotation>
<xsd:documentation>
Convenience attribute group used to simplify this schema.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute ref="wsu:Id" use="optional"/>
<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:attributeGroup>
<!-- // Utility types //////////////////////////////////////// -->
<xsd:complexType name="AttributedDateTime">
<xsd:annotation>
<xsd:documentation>
This type is for elements whose [children] is a psuedo-dateTime and can have arbitrary attributes.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attributeGroup ref="wsu:commonAtts"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="AttributedURI">
<xsd:annotation>
<xsd:documentation>
This type is for elements whose [children] is an anyURI and can have arbitrary attributes.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="xsd:anyURI">
<xsd:attributeGroup ref="wsu:commonAtts"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<!-- // Timestamp header components /////////////////////////// -->
<xsd:complexType name="TimestampType">
<xsd:annotation>
<xsd:documentation>
This complex type ties together the timestamp related elements into a composite type.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="wsu:Created" minOccurs="0"/>
<xsd:element ref="wsu:Expires" minOccurs="0"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="lax"/>
</xsd:choice>
</xsd:sequence>
<xsd:attributeGroup ref="wsu:commonAtts"/>
</xsd:complexType>
<xsd:element name="Timestamp" type="wsu:TimestampType">
<xsd:annotation>
<xsd:documentation>
This element allows Timestamps to be applied anywhere element wildcards are present,
including as a SOAP header.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<!-- global element decls to allow individual elements to appear anywhere -->
<xsd:element name="Expires" type="wsu:AttributedDateTime">
<xsd:annotation>
<xsd:documentation>
This element allows an expiration time to be applied anywhere element wildcards are present.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Created" type="wsu:AttributedDateTime">
<xsd:annotation>
<xsd:documentation>
This element allows a creation time to be applied anywhere element wildcards are present.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>

137
schemas/w3-addr.xsd Normal file
View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
W3C XML Schema defined in the Web Services Addressing 1.0 specification
http://www.w3.org/TR/ws-addr-core
Copyright © 2005 World Wide Web Consortium,
(Massachusetts Institute of Technology, European Research Consortium for
Informatics and Mathematics, Keio University). All Rights Reserved. This
work is distributed under the W3C® Software License [1] in the hope that
it will be useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
[1] http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231
$Id: ws-addr.xsd,v 1.2 2008/07/23 13:38:16 plehegar Exp $
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.w3.org/2005/08/addressing" targetNamespace="http://www.w3.org/2005/08/addressing" blockDefault="#all" elementFormDefault="qualified" finalDefault="" attributeFormDefault="unqualified">
<!-- Constructs from the WS-Addressing Core -->
<xs:element name="EndpointReference" type="tns:EndpointReferenceType"/>
<xs:complexType name="EndpointReferenceType" mixed="false">
<xs:sequence>
<xs:element name="Address" type="tns:AttributedURIType"/>
<xs:element ref="tns:ReferenceParameters" minOccurs="0"/>
<xs:element ref="tns:Metadata" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<xs:element name="ReferenceParameters" type="tns:ReferenceParametersType"/>
<xs:complexType name="ReferenceParametersType" mixed="false">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<xs:element name="Metadata" type="tns:MetadataType"/>
<xs:complexType name="MetadataType" mixed="false">
<xs:sequence>
<xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<xs:element name="MessageID" type="tns:AttributedURIType"/>
<xs:element name="RelatesTo" type="tns:RelatesToType"/>
<xs:complexType name="RelatesToType" mixed="false">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attribute name="RelationshipType" type="tns:RelationshipTypeOpenEnum" use="optional" default="http://www.w3.org/2005/08/addressing/reply"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="RelationshipTypeOpenEnum">
<xs:union memberTypes="tns:RelationshipType xs:anyURI"/>
</xs:simpleType>
<xs:simpleType name="RelationshipType">
<xs:restriction base="xs:anyURI">
<xs:enumeration value="http://www.w3.org/2005/08/addressing/reply"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="ReplyTo" type="tns:EndpointReferenceType"/>
<xs:element name="From" type="tns:EndpointReferenceType"/>
<xs:element name="FaultTo" type="tns:EndpointReferenceType"/>
<xs:element name="To" type="tns:AttributedURIType"/>
<xs:element name="Action" type="tns:AttributedURIType"/>
<xs:complexType name="AttributedURIType" mixed="false">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Constructs from the WS-Addressing SOAP binding -->
<xs:attribute name="IsReferenceParameter" type="xs:boolean"/>
<xs:simpleType name="FaultCodesOpenEnumType">
<xs:union memberTypes="tns:FaultCodesType xs:QName"/>
</xs:simpleType>
<xs:simpleType name="FaultCodesType">
<xs:restriction base="xs:QName">
<xs:enumeration value="tns:InvalidAddressingHeader"/>
<xs:enumeration value="tns:InvalidAddress"/>
<xs:enumeration value="tns:InvalidEPR"/>
<xs:enumeration value="tns:InvalidCardinality"/>
<xs:enumeration value="tns:MissingAddressInEPR"/>
<xs:enumeration value="tns:DuplicateMessageID"/>
<xs:enumeration value="tns:ActionMismatch"/>
<xs:enumeration value="tns:MessageAddressingHeaderRequired"/>
<xs:enumeration value="tns:DestinationUnreachable"/>
<xs:enumeration value="tns:ActionNotSupported"/>
<xs:enumeration value="tns:EndpointUnavailable"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="RetryAfter" type="tns:AttributedUnsignedLongType"/>
<xs:complexType name="AttributedUnsignedLongType" mixed="false">
<xs:simpleContent>
<xs:extension base="xs:unsignedLong">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="ProblemHeaderQName" type="tns:AttributedQNameType"/>
<xs:complexType name="AttributedQNameType" mixed="false">
<xs:simpleContent>
<xs:extension base="xs:QName">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="ProblemIRI" type="tns:AttributedURIType"/>
<xs:element name="ProblemAction" type="tns:ProblemActionType"/>
<xs:complexType name="ProblemActionType" mixed="false">
<xs:sequence>
<xs:element ref="tns:Action" minOccurs="0"/>
<xs:element name="SoapAction" minOccurs="0" type="xs:anyURI"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
</xs:schema>

149
schemas/ws-addr.xsd Normal file
View File

@@ -0,0 +1,149 @@
<?xml version="1.0"?>
<!--
Copyright © 2002-2004 BEA Systems Inc., International Business Machines Corporation,
Microsoft Corporation, Inc, SAP AG, and Sun Microsystems, Inc.. All rights reserved.
Permission to copy, display, perform, modify and distribute the WS-Addressing Specification,
and to authorize others to do the foregoing, in any medium without fee or royalty is hereby
granted for the purpose of developing and evaluating the WS-Addressing Specification.
BEA, IBM, Microsoft, SAP AG, and Sun Microsystems (collectively, the "Authors") each agree
to grant a license to third parties, under royalty-free and otherwise reasonable,
non-discriminatory terms and conditions, to their respective essential patent claims that
they deem necessary to implement the WS-Addressing Specification.
DISCLAIMERS:
THE WS-Addressing Specification IS PROVIDED "AS IS", AND THE AUTHORS MAKE NO REPRESENTATIONS
OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE
CONTENTS OF THE WS-Addressing Specification IS SUITABLE FOR ANY PURPOSE; NOR THAT THE
IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS,
TRADEMARKS OR OTHER RIGHTS.
THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
DAMAGES ARISING OUT OF ANY USE OF THE WS-Addressing Specification OR THE PERFORMANCE OR
IMPLEMENTATION OF THE CONTENTS THEREOF.
You may remove these disclaimers from your modified versions of the WS-Addressing
Specification provided that you effectively disclaim all warranties and liabilities on behalf
of all copyright holders in the copies of any such modified versions you distribute.
The name and trademarks of the Authors may NOT be used in any manner, including advertising
or publicity pertaining to the WS-Addressing Specification or its contents without specific,
written prior permission. Title to copyright in the WS-Addressing Specification will at all
times remain with the Authors.
No other rights are granted by implication, estoppel or otherwise.
-->
<xs:schema targetNamespace="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" elementFormDefault="qualified" blockDefault="#all">
<!-- //////////////////// WS-Addressing //////////////////// -->
<!-- Endpoint reference -->
<xs:element name="EndpointReference" type="wsa:EndpointReferenceType"/>
<xs:complexType name="EndpointReferenceType">
<xs:sequence>
<xs:element name="Address" type="wsa:AttributedURI"/>
<xs:element name="ReferenceProperties" type="wsa:ReferencePropertiesType" minOccurs="0"/>
<xs:element name="ReferenceParameters" type="wsa:ReferenceParametersType" minOccurs="0"/>
<xs:element name="PortType" type="wsa:AttributedQName" minOccurs="0"/>
<xs:element name="ServiceName" type="wsa:ServiceNameType" minOccurs="0"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
If "Policy" elements from namespace "http://schemas.xmlsoap.org/ws/2002/12/policy#policy" are used, they must appear first (before any extensibility elements).
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:complexType>
<xs:complexType name="ReferencePropertiesType">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ReferenceParametersType">
<xs:sequence>
<xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ServiceNameType">
<xs:simpleContent>
<xs:extension base="xs:QName">
<xs:attribute name="PortName" type="xs:NCName"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Message information header blocks -->
<xs:element name="MessageID" type="wsa:AttributedURI"/>
<xs:element name="RelatesTo" type="wsa:Relationship"/>
<xs:element name="To" type="wsa:AttributedURI"/>
<xs:element name="Action" type="wsa:AttributedURI"/>
<xs:element name="From" type="wsa:EndpointReferenceType"/>
<xs:element name="ReplyTo" type="wsa:EndpointReferenceType"/>
<xs:element name="FaultTo" type="wsa:EndpointReferenceType"/>
<xs:complexType name="Relationship">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:attribute name="RelationshipType" type="xs:QName" use="optional"/>
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="RelationshipTypeValues">
<xs:restriction base="xs:QName">
<xs:enumeration value="wsa:Reply"/>
</xs:restriction>
</xs:simpleType>
<!--
June 19, 2007: The ReplyAfter element is deprecated. The name of this element does not match the
name (RetryAfter) used in the specification (http://www.w3.org/Submission/2004/SUBM-ws-addressing-20040810/).
-->
<xs:element name="ReplyAfter" type="wsa:ReplyAfterType"/>
<xs:complexType name="ReplyAfterType">
<xs:simpleContent>
<xs:extension base="xs:nonNegativeInteger">
<xs:anyAttribute namespace="##other"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!--
June 19, 2007: The RetryAfter element has been added to be consistent with the specification
(http://www.w3.org/Submission/2004/SUBM-ws-addressing-20040810/).
-->
<xs:element name="RetryAfter" type="wsa:RetryAfterType"/>
<xs:complexType name="RetryAfterType">
<xs:simpleContent>
<xs:extension base="xs:nonNegativeInteger">
<xs:anyAttribute namespace="##other"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name="FaultSubcodeValues">
<xs:restriction base="xs:QName">
<xs:enumeration value="wsa:InvalidMessageInformationHeader"/>
<xs:enumeration value="wsa:MessageInformationHeaderRequired"/>
<xs:enumeration value="wsa:DestinationUnreachable"/>
<xs:enumeration value="wsa:ActionNotSupported"/>
<xs:enumeration value="wsa:EndpointUnavailable"/>
</xs:restriction>
</xs:simpleType>
<xs:attribute name="Action" type="xs:anyURI"/>
<!-- Common declarations and definitions -->
<xs:complexType name="AttributedQName">
<xs:simpleContent>
<xs:extension base="xs:QName">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="AttributedURI">
<xs:simpleContent>
<xs:extension base="xs:anyURI">
<xs:anyAttribute namespace="##other" processContents="lax"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>

View File

@@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the
implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available;
neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS
specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made
available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users
of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may
cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © OASIS Open 2002-2007. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist
in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the
above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified
in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications,
in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate
it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an AS IS basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'
xmlns:tns='http://docs.oasis-open.org/wsfed/authorization/200706'
targetNamespace='http://docs.oasis-open.org/wsfed/authorization/200706'
elementFormDefault='qualified' >
<xs:import namespace='http://www.w3.org/2001/04/xmlenc#'
schemaLocation='http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/xenc-schema.xsd'/>
<!-- Section 9.2 -->
<xs:element name='AdditionalContext' type='tns:AdditionalContextType' />
<xs:complexType name='AdditionalContextType' >
<xs:sequence>
<xs:element name='ContextItem' type='tns:ContextItemType' minOccurs='0' maxOccurs='unbounded' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='ContextItemType' >
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:choice>
<xs:attribute name='Name' type='xs:anyURI' use='required' />
<xs:attribute name='Scope' type='xs:anyURI' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 9.3 -->
<xs:element name='ClaimType' type='tns:ClaimType' />
<xs:complexType name='ClaimType' >
<xs:sequence>
<xs:element name="DisplayName" type="tns:DisplayNameType" minOccurs="0" maxOccurs="1" />
<xs:element name="Description" type="tns:DescriptionType" minOccurs="0" maxOccurs="1" />
<xs:element name="DisplayValue" type="tns:DisplayValueType" minOccurs="0" maxOccurs="1" />
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:element name='EncryptedValue' type='tns:EncryptedValueType' minOccurs='1' maxOccurs='1' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='1' />
<xs:element name='ConstrainedValue' type='tns:ConstrainedValueType' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:choice>
</xs:sequence>
<xs:attribute name='Uri' type='xs:anyURI' use='required' />
<xs:attribute name='Optional' type='xs:boolean' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name="DisplayNameType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="DescriptionType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="DisplayValueType">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:anyAttribute namespace="##other" processContents="lax" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="EncryptedValueType">
<xs:sequence>
<xs:element ref="xenc:EncryptedData" minOccurs="1" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="DecryptionCondition" type="xs:anyURI" use="optional"/>
</xs:complexType>
<xs:complexType name="StructuredValueType">
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 9.3.1 -->
<xs:complexType name='ConstrainedValueType'>
<xs:sequence>
<xs:choice minOccurs='1'>
<xs:element name='ValueLessThan' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueLessThanOrEqual' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueGreaterThan' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueGreaterThanOrEqual' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueInRangen' type='tns:ValueInRangeType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueOneOf' type='tns:ConstrainedManyValueType' minOccurs='1' maxOccurs='1'/>
</xs:choice>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='AssertConstraint' type='xs:boolean' use='optional' />
</xs:complexType>
<xs:complexType name='ValueInRangeType'>
<xs:sequence>
<xs:element name='ValueUpperBound' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
<xs:element name='ValueLowerBound' type='tns:ConstrainedSingleValueType' minOccurs='1' maxOccurs='1'/>
</xs:sequence>
</xs:complexType>
<xs:complexType name='ConstrainedSingleValueType'>
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='1' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='1' />
</xs:choice>
</xs:complexType>
<xs:complexType name='ConstrainedManyValueType'>
<xs:choice minOccurs='0'>
<xs:element name='Value' type='xs:string' minOccurs='1' maxOccurs='unbounded' />
<xs:element name='StructuredValue' type='tns:StructuredValueType' minOccurs='1' maxOccurs='unbounded' />
</xs:choice>
</xs:complexType>
</xs:schema>

470
schemas/ws-federation.xsd Normal file
View File

@@ -0,0 +1,470 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
OASIS takes no position regarding the validity or scope of any intellectual property or other rights that might be claimed to pertain to the
implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available;
neither does it represent that it has made any effort to identify any such rights. Information on OASIS's procedures with respect to rights in OASIS
specifications can be found at the OASIS website. Copies of claims of rights made available for publication and any assurances of licenses to be made
available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementors or users
of this specification, can be obtained from the OASIS Executive Director.
OASIS invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights which may
cover technology that may be required to implement this specification. Please address the information to the OASIS Executive Director.
Copyright © OASIS Open 2002-2007. All Rights Reserved.
This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist
in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the
above copyright notice and this paragraph are included on all such copies and derivative works. However, this document itself does not be modified
in any way, such as by removing the copyright notice or references to OASIS, except as needed for the purpose of developing OASIS specifications,
in which case the procedures for copyrights defined in the OASIS Intellectual Property Rights document must be followed, or as required to translate
it into languages other than English.
The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.
This document and the information contained herein is provided on an AS IS basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:sp='http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702'
xmlns:tns='http://docs.oasis-open.org/wsfed/federation/200706'
xmlns:wsa='http://www.w3.org/2005/08/addressing'
xmlns:mex='http://schemas.xmlsoap.org/ws/2004/09/mex'
xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
xmlns:md='urn:oasis:names:tc:SAML:2.0:metadata'
xmlns:auth='http://docs.oasis-open.org/wsfed/authorization/200706'
targetNamespace='http://docs.oasis-open.org/wsfed/federation/200706'
elementFormDefault='qualified' >
<xs:import namespace='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
schemaLocation='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' />
<xs:import namespace='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
schemaLocation='oasis-200401-wss-wssecurity-utility-1.0.xsd' />
<xs:import namespace='http://www.w3.org/2005/08/addressing'
schemaLocation='w3-addr.xsd' />
<xs:import namespace='http://schemas.xmlsoap.org/ws/2004/09/mex'
schemaLocation='http://schemas.xmlsoap.org/ws/2004/09/mex/MetadataExchange.xsd' />
<xs:import namespace='urn:oasis:names:tc:SAML:2.0:metadata'
schemaLocation='saml-schema-metadata-2.0.xsd' />
<xs:import namespace='http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702'
schemaLocation='ws-securitypolicy-1.2.xsd'/>
<xs:import namespace='http://docs.oasis-open.org/wsfed/authorization/200706'
schemaLocation='ws-authorization.xsd'/>
<!-- Section 3.1 -->
<!-- Note: Use of this root element is discouraged in favor of use of md:EntitiesDescriptor or md EntityDescriptor -->
<xs:element name='FederationMetadata' type='tns:FederationMetadataType' />
<xs:complexType name='FederationMetadataType' >
<xs:sequence>
<!--
*** Accurate content model is nondeterministic ***
<xs:element name='Federation' type='tns:FederationType' minOccurs='1' maxOccurs='unbounded' />
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
-->
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='FederationType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='FederationID' type='xs:anyURI' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.2.1 -->
<xs:complexType name="WebServiceDescriptorType" abstract="true">
<xs:complexContent>
<xs:extension base="md:RoleDescriptorType">
<xs:sequence>
<xs:element ref="tns:LogicalServiceNamesOffered" minOccurs="0" maxOccurs="1" />
<xs:element ref="tns:TokenTypesOffered" minOccurs="0" maxOccurs="1" />
<xs:element ref="tns:ClaimDialectsOffered" minOccurs="0" maxOccurs="1" />
<xs:element ref="tns:ClaimTypesOffered" minOccurs="0" maxOccurs="1" />
<xs:element ref="tns:ClaimTypesRequested" minOccurs="0" maxOccurs="1" />
<xs:element ref="tns:AutomaticPseudonyms" minOccurs="0" maxOccurs="1"/>
<xs:element ref="tns:TargetScopes" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
<xs:attribute name="ServiceDisplayName" type="xs:string" use="optional"/>
<xs:attribute name="ServiceDescription" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name='LogicalServiceNamesOffered' type='tns:LogicalServiceNamesOfferedType' />
<xs:element name='TokenTypesOffered' type='tns:TokenTypesOfferedType' />
<xs:element name='ClaimDialectsOffered' type='tns:ClaimDialectsOfferedType' />
<xs:element name='ClaimTypesOffered' type='tns:ClaimTypesOfferedType' />
<xs:element name='ClaimTypesRequested' type='tns:ClaimTypesRequestedType' />
<xs:element name="AutomaticPseudonyms" type="xs:boolean"/>
<xs:element name='TargetScopes' type='tns:EndpointType'/>
<!-- Section 3.1.2.2 -->
<xs:complexType name="SecurityTokenServiceType">
<xs:complexContent>
<xs:extension base="tns:WebServiceDescriptorType">
<xs:sequence>
<xs:element ref="tns:SecurityTokenServiceEndpoint" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="tns:SingleSignOutSubscriptionEndpoint" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="tns:SingleSignOutNotificationEndpoint" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="tns:PassiveRequestorEndpoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="SecurityTokenServiceEndpoint" type="tns:EndpointType"/>
<xs:element name="SingleSignOutSubscriptionEndpoint" type="tns:EndpointType"/>
<xs:element name="SingleSignOutNotificationEndpoint" type="tns:EndpointType"/>
<xs:element name="PassiveRequestorEndpoint" type="tns:EndpointType"/>
<!-- Section 3.1.2.3 -->
<xs:complexType name="PseudonymServiceType">
<xs:complexContent>
<xs:extension base="tns:WebServiceDescriptorType">
<xs:sequence>
<xs:element ref="tns:PseudonymServiceEndpoint" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="tns:SingleSignOutNotificationEndpoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="PseudonymServiceEndpoint" type="tns:EndpointType"/>
<!-- Defined above -->
<!-- <xs:element name="SingleSignOutNotificationEndpoint" type="tns:EndpointType"/> -->
<!-- Section 3.1.2.4 -->
<xs:complexType name="AttributeServiceType">
<xs:complexContent>
<xs:extension base="tns:WebServiceDescriptorType">
<xs:sequence>
<xs:element ref="tns:AttributeServiceEndpoint" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="tns:SingleSignOutNotificationEndpoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="AttributeServiceEndpoint" type="tns:EndpointType"/>
<!-- Defined above -->
<!-- <xs:element name="SingleSignOutNotificationEndpoint" type="tns:EndpointType"/> -->
<!-- Section 3.1.2.5 -->
<xs:complexType name="ApplicationServiceType">
<xs:complexContent>
<xs:extension base="tns:WebServiceDescriptorType">
<xs:sequence>
<xs:element ref="tns:ApplicationServiceEndpoint" minOccurs="1" maxOccurs="unbounded"/>
<xs:element ref="tns:SingleSignOutNotificationEndpoint" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="tns:PassiveRequestorEndpoint" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="ApplicationServiceEndpoint" type="tns:EndpointType"/>
<!-- Defined above -->
<!-- <xs:element name="SingleSignOutNotificationEndpoint" type="tns:EndpointType"/> -->
<!-- <xs:element name="PassiveRequestorEndpoint" type="tns:EndpointType"/> -->
<!-- Section 3.1.3 -->
<!-- Defined above -->
<!--<xs:element name='LogicalServiceNamesOffered' type='tns:LogicalServiceNamesOfferedType' />-->
<xs:complexType name='LogicalServiceNamesOfferedType' >
<xs:sequence>
<xs:element name='IssuerName' type='tns:IssuerNameType' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='IssuerNameType' >
<xs:attribute name='Uri' type='xs:anyURI' use='required' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.4 -->
<xs:element name='PsuedonymServiceEndpoints' type='tns:EndpointType' />
<xs:complexType name='EndpointType' >
<xs:sequence>
<xs:element ref='wsa:EndpointReference' minOccurs='1' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
<!-- Section 3.1.5 -->
<xs:element name='AttributeServiceEndpoints' type='tns:EndpointType' />
<!-- Section 3.1.6 -->
<xs:element name='SingleSignOutSubscriptionEndpoints' type='tns:EndpointType' />
<!-- Section 3.1.7 -->
<xs:element name='SingleSignOutNotificationEndpoints' type='tns:EndpointType' />
<!-- Section 3.1.8 -->
<!-- Defined above -->
<!--<xs:element name='TokenTypesOffered' type='tns:TokenTypesOfferedType' />-->
<xs:complexType name='TokenTypesOfferedType' >
<xs:sequence>
<xs:element name='TokenType' type='tns:TokenType' minOccurs='1' maxOccurs='unbounded' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='TokenType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='Uri' type='xs:anyURI' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.9 -->
<!-- Defined above -->
<!-- <xs:element name='ClaimTypesOffered' type='tns:ClaimTypesOfferedType' /> -->
<xs:complexType name='ClaimTypesOfferedType'>
<xs:sequence>
<xs:element ref='auth:ClaimType' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.10 -->
<!-- Defined above -->
<!-- <xs:element name='ClaimTypesRequested' ype='tns:ClaimTypesRequestedType' /> -->
<xs:complexType name='ClaimTypesRequestedType'>
<xs:sequence>
<xs:element ref='auth:ClaimType' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.11 -->
<!-- Defined above -->
<!--<xs:element name='ClaimDialectsOffered' type='tns:ClaimDialectsOfferedType' />-->
<xs:complexType name='ClaimDialectsOfferedType'>
<xs:sequence>
<xs:element name='ClaimDialect' type='tns:ClaimDialectType' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='ClaimDialectType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='Uri' type='xs:anyURI' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 3.1.12 -->
<!-- Defined above -->
<!-- <xs:element name='AutomaticPseudonyms' type='xs:boolean' /> -->
<!-- Section 3.1.13 -->
<xs:element name='PassiveRequestorEnpoints' type='tns:EndpointType'/>
<!-- Section 3.1.14 -->
<!-- Defined above -->
<!--<xs:element name='TargetScopes' type='tns:EndpointType'/>-->
<!-- Section 3.2.4 -->
<xs:element name='FederationMetadataHandler' type='tns:FederationMetadataHandlerType' />
<xs:complexType name='FederationMetadataHandlerType' >
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 4.1 -->
<xs:element name='SignOut' type='tns:SignOutType' />
<xs:complexType name='SignOutType' >
<xs:sequence>
<xs:element ref='tns:Realm' minOccurs='0' />
<xs:element name='SignOutBasis' type='tns:SignOutBasisType' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute ref='wsu:Id' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='SignOutBasisType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 4.2 -->
<xs:element name='Realm' type='xs:anyURI' />
<!-- Section 6.1 -->
<xs:element name='FilterPseudonyms' type='tns:FilterPseudonymsType' />
<xs:complexType name='FilterPseudonymsType' >
<xs:sequence>
<xs:element ref='tns:PseudonymBasis' minOccurs='0' maxOccurs='1' />
<xs:element ref='tns:RelativeTo' minOccurs='0' maxOccurs='1' />
<xs:any namespace='##other' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='PseudonymBasis' type='tns:PseudonymBasisType' />
<xs:complexType name='PseudonymBasisType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='RelativeTo' type='tns:RelativeToType' />
<xs:complexType name='RelativeToType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 6.2 -->
<xs:element name='Pseudonym' type='tns:PseudonymType' />
<xs:complexType name='PseudonymType' >
<xs:sequence>
<!--
*** Accurate content model is nondeterministic ***
<xs:element ref='tns:PseudonymBasis' minOccurs='1' maxOccurs='1' />
<xs:element ref='tns:RelativeTo' minOccurs='1' maxOccurs='1' />
<xs:element ref='wsu:Expires' minOccurs='0' maxOccurs='1' />
<xs:element ref='tns:SecurityToken' minOccurs='0' maxOccurs='unbounded' />
<xs:element ref='tns:ProofToken' minOccurs='0' maxOccurs='unbounded' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
-->
<xs:element ref='tns:PseudonymBasis' minOccurs='1' maxOccurs='1' />
<xs:element ref='tns:RelativeTo' minOccurs='1' maxOccurs='1' />
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='SecurityToken' type='tns:SecurityTokenType' />
<xs:complexType name='SecurityTokenType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='ProofToken' type='tns:ProofTokenType' />
<xs:complexType name='ProofTokenType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='1' maxOccurs='1' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 7.1 -->
<xs:element name='RequestPseudonym' type='tns:RequestPseudonymType' />
<xs:complexType name='RequestPseudonymType' >
<xs:sequence>
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='SingleUse' type='xs:boolean' use='optional' />
<xs:attribute name='Lookup' type='xs:boolean' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 8.1 -->
<xs:element name='ReferenceToken' type='tns:ReferenceTokenType' />
<xs:complexType name='ReferenceTokenType'>
<xs:sequence>
<xs:element name='ReferenceEPR' type='wsa:EndpointReferenceType' minOccurs='1' maxOccurs='unbounded' />
<xs:element name='ReferenceDigest' type='tns:ReferenceDigestType' minOccurs='0' maxOccurs='1' />
<xs:element name='ReferenceType' type='tns:AttributeExtensibleURI' minOccurs='0' maxOccurs='1' />
<xs:element name='SerialNo' type='tns:AttributeExtensibleURI' minOccurs='0' maxOccurs='1' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='ReferenceDigestType' >
<xs:simpleContent>
<xs:extension base='xs:base64Binary' >
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name='AttributeExtensibleURI' >
<xs:simpleContent>
<xs:extension base='xs:anyURI' >
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Section 8.2 -->
<xs:element name='FederationID' type='tns:AttributeExtensibleURI' />
<!-- Section 8.3 -->
<xs:element name='RequestProofToken' type='tns:RequestProofTokenType' />
<xs:complexType name='RequestProofTokenType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 8.4 -->
<xs:element name='ClientPseudonym' type='tns:ClientPseudonymType' />
<xs:complexType name='ClientPseudonymType' >
<xs:sequence>
<xs:element name='PPID' type='tns:AttributeExtensibleString' minOccurs='0' />
<xs:element name='DisplayName' type='tns:AttributeExtensibleString' minOccurs='0' />
<xs:element name='EMail' type='tns:AttributeExtensibleString' minOccurs='0' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:complexType name='AttributeExtensibleString' >
<xs:simpleContent>
<xs:extension base='xs:string' >
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Section 8.5 -->
<xs:element name='Freshness' type='tns:Freshness' />
<xs:complexType name='Freshness'>
<xs:simpleContent>
<xs:extension base='xs:unsignedInt' >
<xs:attribute name='AllowCache' type='xs:boolean' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- Section 14.1 -->
<xs:element name='RequireReferenceToken' type='sp:TokenAssertionType' />
<xs:element name='ReferenceToken11' type='tns:AssertionType' />
<xs:complexType name='AssertionType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- Section 14.2 -->
<xs:element name='WebBinding' type='sp:NestedPolicyType' />
<xs:element name='AuthenticationToken' type='sp:NestedPolicyType' />
<!-- ReferenceToken defined above -->
<xs:element name='RequireSignedTokens' type='tns:AssertionType' />
<xs:element name='RequireBearerTokens' type='tns:AssertionType' />
<xs:element name='RequireSharedCookies' type='tns:AssertionType' />
<!-- Section 14.3 -->
<xs:element name='RequiresGenericClaimDialect' type='tns:AssertionType' />
<xs:element name='IssuesSpecificPolicyFault' type='tns:AssertionType' />
<xs:element name='AdditionalContextProcessed' type='tns:AssertionType' />
</xs:schema>

File diff suppressed because it is too large Load Diff

451
schemas/ws-trust.xsd Normal file
View File

@@ -0,0 +1,451 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright Notice
(c) 2001-2005 Actional Corporation, BEA Systems, Inc.,
Computer Associates International, Inc., International Business Machines Corporation,
Layer 7 Technologies, Microsoft Corporation, Netegrity, Inc., Oblix Inc.,
OpenNetwork Technologies Inc., Ping Identity Corporation, Reactivity Inc.,
RSA Security Inc., and VeriSign Inc.
All rights reserved.
Permission to copy and display the WS-Trust Specification (the "Specification", which
includes WSDL and schema documents), in any medium without fee or royalty
is hereby granted, provided that you include the following on ALL copies of the
Specification, that you make:
1. A link or URL to the Specification at one of the Authors' websites
2. The copyright notice as shown in the Specification.
IBM, Microsoft and Actional, BEA, Computer Associates, Layer 7, Netegrity, Oblix,
OpenNetwork, Ping Identity, Reactivity, and Verisign (collectively, the "Authors") each
agree to grant you a license, under royalty-free and otherwise reasonable,
non-discriminatory terms and conditions, to their respective essential patent claims
that they deem necessary to implement the Specification.
THE SPECIFICATION IS PROVIDED "AS IS," AND THE AUTHORS MAKE
NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT
NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF
THE SPECIFICATION ARE SUITABLE FOR ANY PURPOSE; NOR THAT THE
IMPLEMENTATION OF SUCH CONTENTS WILL NOT INFRINGE ANY THIRD PARTY
PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
THE AUTHORS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL,
INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO ANY
USE OR DISTRIBUTION OF THE SPECIFICATION.
The name and trademarks of the Authors may NOT be used in any manner,
including advertising or publicity pertaining to the Specification or
its contents without specific, written prior permission. Title to
copyright in the Specification will at all times remain with the Authors.
No other rights are granted by implication, estoppel or otherwise.
-->
<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
xmlns:wsp='http://schemas.xmlsoap.org/ws/2004/09/policy'
xmlns:wsa='http://schemas.xmlsoap.org/ws/2004/08/addressing'
xmlns:wst='http://schemas.xmlsoap.org/ws/2005/02/trust'
targetNamespace='http://schemas.xmlsoap.org/ws/2005/02/trust'
elementFormDefault='qualified' >
<xs:import namespace='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
schemaLocation='oasis-200401-wss-wssecurity-secext-1.0.xsd' />
<xs:import namespace='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
schemaLocation='oasis-200401-wss-wssecurity-utility-1.0.xsd' />
<xs:import namespace='http://schemas.xmlsoap.org/ws/2004/09/policy'
schemaLocation='http://schemas.xmlsoap.org/ws/2004/09/policy/ws-policy.xsd' />
<xs:import namespace='http://schemas.xmlsoap.org/ws/2004/08/addressing'
schemaLocation='ws-addr.xsd' />
<!-- WS-Trust Section 5.1 -->
<xs:element name='RequestSecurityToken' type='wst:RequestSecurityTokenType' />
<xs:complexType name='RequestSecurityTokenType' >
<xs:annotation>
<xs:documentation>
Actual content model is non-deterministic, hence wildcard. The following shows intended content model:
<xs:element ref='wst:TokenType' minOccurs='0' />
<xs:element ref='wst:RequestType' />
<xs:element ref='wsp:AppliesTo' minOccurs='0' />
<xs:element ref='wst:Claims' minOccurs='0' />
<xs:element ref='wst:Entropy' minOccurs='0' />
<xs:element ref='wst:Lifetime' minOccurs='0' />
<xs:element ref='wst:AllowPostdating' minOccurs='0' />
<xs:element ref='wst:Renewing' minOccurs='0' />
<xs:element ref='wst:OnBehalfOf' minOccurs='0' />
<xs:element ref='wst:Issuer' minOccurs='0' />
<xs:element ref='wst:AuthenticationType' minOccurs='0' />
<xs:element ref='wst:KeyType' minOccurs='0' />
<xs:element ref='wst:KeySize' minOccurs='0' />
<xs:element ref='wst:SignatureAlgorithm' minOccurs='0' />
<xs:element ref='wst:Encryption' minOccurs='0' />
<xs:element ref='wst:EncryptionAlgorithm' minOccurs='0' />
<xs:element ref='wst:CanonicalizationAlgorithm' minOccurs='0' />
<xs:element ref='wst:ProofEncryption' minOccurs='0' />
<xs:element ref='wst:UseKey' minOccurs='0' />
<xs:element ref='wst:SignWith' minOccurs='0' />
<xs:element ref='wst:EncryptWith' minOccurs='0' />
<xs:element ref='wst:DelegateTo' minOccurs='0' />
<xs:element ref='wst:Forwardable' minOccurs='0' />
<xs:element ref='wst:Delegatable' minOccurs='0' />
<xs:element ref='wsp:Policy' minOccurs='0' />
<xs:element ref='wsp:PolicyReference' minOccurs='0' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='Context' type='xs:anyURI' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='TokenType' type='xs:anyURI' />
<xs:element name='RequestType' type='wst:RequestTypeOpenEnum' />
<xs:simpleType name='RequestTypeOpenEnum' >
<xs:union memberTypes='wst:RequestTypeEnum xs:anyURI' />
</xs:simpleType>
<xs:simpleType name='RequestTypeEnum' >
<xs:restriction base='xs:anyURI' >
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/Issue' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/Renew' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/Cancel' />
</xs:restriction>
</xs:simpleType>
<!-- WS-Trust Section 5.2 -->
<xs:element name='RequestSecurityTokenResponse' type='wst:RequestSecurityTokenResponseType' />
<xs:complexType name='RequestSecurityTokenResponseType' >
<xs:annotation>
<xs:documentation>
Actual content model is non-deterministic, hence wildcard. The following shows intended content model:
<xs:element ref='wst:TokenType' minOccurs='0' />
<xs:element ref='wst:RequestType' />
<xs:element ref='wst:RequestedSecurityToken' minOccurs='0' />
<xs:element ref='wsp:AppliesTo' minOccurs='0' />
<xs:element ref='wst:RequestedAttachedReference' minOccurs='0' />
<xs:element ref='wst:RequestedUnattachedReference' minOccurs='0' />
<xs:element ref='wst:RequestedProofToken' minOccurs='0' />
<xs:element ref='wst:Entropy' minOccurs='0' />
<xs:element ref='wst:Lifetime' minOccurs='0' />
<xs:element ref='wst:Status' minOccurs='0' />
<xs:element ref='wst:AllowPostdating' minOccurs='0' />
<xs:element ref='wst:Renewing' minOccurs='0' />
<xs:element ref='wst:OnBehalfOf' minOccurs='0' />
<xs:element ref='wst:Issuer' minOccurs='0' />
<xs:element ref='wst:AuthenticationType' minOccurs='0' />
<xs:element ref='wst:Authenticator' minOccurs='0' />
<xs:element ref='wst:KeyType' minOccurs='0' />
<xs:element ref='wst:KeySize' minOccurs='0' />
<xs:element ref='wst:SignatureAlgorithm' minOccurs='0' />
<xs:element ref='wst:Encryption' minOccurs='0' />
<xs:element ref='wst:EncryptionAlgorithm' minOccurs='0' />
<xs:element ref='wst:CanonicalizationAlgorithm' minOccurs='0' />
<xs:element ref='wst:ProofEncryption' minOccurs='0' />
<xs:element ref='wst:UseKey' minOccurs='0' />
<xs:element ref='wst:SignWith' minOccurs='0' />
<xs:element ref='wst:EncryptWith' minOccurs='0' />
<xs:element ref='wst:DelegateTo' minOccurs='0' />
<xs:element ref='wst:Forwardable' minOccurs='0' />
<xs:element ref='wst:Delegatable' minOccurs='0' />
<xs:element ref='wsp:Policy' minOccurs='0' />
<xs:element ref='wsp:PolicyReference' minOccurs='0' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='Context' type='xs:anyURI' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='RequestedSecurityToken' type='wst:RequestedSecurityTokenType' />
<xs:complexType name='RequestedSecurityTokenType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<!-- WS-Trust Section 5.3 -->
<xs:element name='BinarySecret' type='wst:BinarySecretType' />
<xs:complexType name='BinarySecretType' >
<xs:simpleContent>
<xs:extension base='xs:base64Binary' >
<xs:attribute name='Type' type='wst:BinarySecretTypeOpenEnum' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:simpleType name='BinarySecretTypeEnum' >
<xs:restriction base='xs:anyURI' >
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/AsymmetricKey' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce' />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='BinarySecretTypeOpenEnum' >
<xs:union memberTypes='wst:BinarySecretTypeEnum xs:anyURI' />
</xs:simpleType>
<!-- WS-Trust Section 6.1 -->
<xs:element name='Claims' type='wst:ClaimsType' />
<xs:complexType name='ClaimsType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:attribute name='Dialect' type='xs:anyURI' use='optional' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='Entropy' type='wst:EntropyType' />
<xs:complexType name='EntropyType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<xs:element name='Lifetime' type='wst:LifetimeType' />
<xs:complexType name='LifetimeType' >
<xs:sequence>
<xs:element ref='wsu:Created' minOccurs='0' />
<xs:element ref='wsu:Expires' minOccurs='0' />
</xs:sequence>
</xs:complexType>
<!-- WS-Trust Section 6.2 -->
<xs:element name='ComputedKey' type='wst:ComputedKeyOpenEnum' />
<xs:simpleType name='ComputedKeyEnum' >
<xs:restriction base='xs:anyURI' >
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/CK/HASH' />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='ComputedKeyOpenEnum' >
<xs:union memberTypes='wst:ComputedKeyEnum xs:anyURI' />
</xs:simpleType>
<xs:element name='RequestedAttachedReference' type='wst:RequestedReferenceType' />
<xs:element name='RequestedUnattachedReference' type='wst:RequestedReferenceType' />
<xs:complexType name='RequestedReferenceType' >
<xs:sequence>
<xs:element ref='wsse:SecurityTokenReference' />
</xs:sequence>
</xs:complexType>
<xs:element name='RequestedProofToken' type='wst:RequestedProofTokenType' />
<xs:complexType name='RequestedProofTokenType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<!-- WS-Trust Section 6.3 -->
<xs:element name='RequestSecurityTokenResponseCollection' type='wst:RequestSecurityTokenResponseCollectionType' />
<xs:complexType name='RequestSecurityTokenResponseCollectionType' >
<xs:sequence>
<xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:complexType>
<!-- WS-Trust Section 6.4 -->
<xs:element name='IssuedTokens' type='wst:RequestSecurityTokenResponseCollectionType' />
<!-- WS-Trust Section 7 -->
<xs:element name='RenewTarget' type='wst:RenewTargetType' />
<xs:complexType name='RenewTargetType' >
<xs:sequence>
<xs:any namespace='##other' minOccurs='1' maxOccurs='1' />
</xs:sequence>
</xs:complexType>
<xs:element name='AllowPostdating' type='wst:AllowPostdatingType' />
<xs:complexType name='AllowPostdatingType' />
<xs:element name='Renewing' type='wst:RenewingType' />
<xs:complexType name='RenewingType' >
<xs:attribute name='Allow' type='xs:boolean' use='optional' />
<xs:attribute name='OK' type='xs:boolean' use='optional' />
</xs:complexType>
<!-- WS-Trust Section 8 -->
<xs:element name='CancelTarget' type='wst:CancelTargetType' />
<xs:complexType name='CancelTargetType' >
<xs:sequence>
<xs:any namespace='##other' minOccurs='1' maxOccurs='1' />
</xs:sequence>
</xs:complexType>
<xs:element name='RequestedTokenCancelled' type='wst:RequestedTokenCancelledType' />
<xs:complexType name='RequestedTokenCancelledType' />
<!-- WS-Trust Section 9 -->
<xs:element name='Status' type='wst:StatusType' />
<xs:complexType name='StatusType' >
<xs:sequence>
<xs:element name='Code' type='wst:StatusCodeOpenEnum' />
<xs:element name='Reason' type='xs:string' minOccurs='0' />
</xs:sequence>
</xs:complexType>
<xs:simpleType name='StatusCodeEnum' >
<xs:restriction base='xs:anyURI' >
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/status/valid' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/status/invalid' />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='StatusCodeOpenEnum' >
<xs:union memberTypes='wst:StatusCodeEnum xs:anyURI' />
</xs:simpleType>
<!-- WS-Trust Section 10.2 -->
<xs:element name='SignChallenge' type='wst:SignChallengeType' />
<xs:element name='SignChallengeResponse' type='wst:SignChallengeType' />
<xs:complexType name='SignChallengeType' >
<xs:sequence>
<xs:element ref='wst:Challenge' />
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
<xs:anyAttribute namespace='##any' processContents='lax' />
</xs:complexType>
<xs:element name='Challenge' type='xs:string'/>
<!-- WS-Trust Section 10.3 -->
<xs:element name='BinaryExchange' type='wst:BinaryExchangeType' />
<xs:complexType name='BinaryExchangeType' >
<xs:simpleContent>
<xs:extension base='xs:string' >
<xs:attribute name='ValueType' type='xs:anyURI' use='required' />
<xs:attribute name='EncodingType' type='xs:anyURI' use='required' />
<xs:anyAttribute namespace='##other' processContents='lax' />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!-- WS-Trust Section 10.4 -->
<xs:element name='RequestKET' type='wst:RequestKETType' />
<xs:complexType name='RequestKETType' />
<xs:element name='KeyExchangeToken' type='wst:KeyExchangeTokenType' />
<xs:complexType name='KeyExchangeTokenType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<!-- WS-Trust Section 10.9 -->
<xs:element name='Authenticator' type='wst:AuthenticatorType' />
<xs:complexType name='AuthenticatorType' >
<xs:sequence>
<xs:element ref='wst:CombinedHash' minOccurs='0' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<xs:element name='CombinedHash' type='xs:base64Binary' />
<!-- WS-Trust Section 11.1 -->
<xs:element name='OnBehalfOf' type='wst:OnBehalfOfType' />
<xs:complexType name='OnBehalfOfType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<xs:element name='Issuer' type='wsa:EndpointReferenceType' />
<!-- WS-Trust Section 11.2 -->
<xs:element name='AuthenticationType' type='xs:anyURI' />
<xs:element name='KeyType' type='wst:KeyTypeOpenEnum' />
<xs:simpleType name='KeyTypeEnum' >
<xs:restriction base='xs:anyURI' >
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/PublicKey' />
<xs:enumeration value='http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey' />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='KeyTypeOpenEnum' >
<xs:union memberTypes='wst:KeyTypeEnum xs:anyURI' />
</xs:simpleType>
<xs:element name='KeySize' type='xs:unsignedInt' />
<xs:element name='SignatureAlgorithm' type='xs:anyURI' />
<xs:element name='EncryptionAlgorithm' type='xs:anyURI' />
<xs:element name='CanonicalizationAlgorithm' type='xs:anyURI' />
<xs:element name='ComputedKeyAlgorithm' type='xs:anyURI' />
<xs:element name='Encryption' type='wst:EncryptionType' />
<xs:complexType name='EncryptionType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<xs:element name='ProofEncryption' type='wst:ProofEncryptionType' />
<xs:complexType name='ProofEncryptionType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<xs:element name='UseKey' type='wst:UseKeyType' />
<xs:complexType name='UseKeyType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' minOccurs='0' />
</xs:sequence>
<xs:attribute name='Sig' type='xs:anyURI' use='optional' />
</xs:complexType>
<xs:element name='SignWith' type='xs:anyURI' />
<xs:element name='EncryptWith' type='xs:anyURI' />
<!-- WS-Trust Section 11.3 -->
<xs:element name='DelegateTo' type='wst:DelegateToType' />
<xs:complexType name='DelegateToType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
<xs:element name='Forwardable' type='xs:boolean' />
<xs:element name='Delegatable' type='xs:boolean' />
<!-- WS-Trust Section 11.5 -->
<xs:element name='Participants' type='wst:ParticipantsType' />
<xs:complexType name='ParticipantsType' >
<xs:sequence>
<xs:element name='Primary' type='wst:ParticipantType' minOccurs='0' />
<xs:element name='Participant' type='wst:ParticipantType' minOccurs='0' maxOccurs='unbounded' />
<xs:any namespace='##other' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
</xs:sequence>
</xs:complexType>
<xs:complexType name='ParticipantType' >
<xs:sequence>
<xs:any namespace='##any' processContents='lax' />
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@@ -0,0 +1,218 @@
"""test WSFed Provider flow"""
from json import dumps
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as ec
from authentik.blueprints.tests import apply_blueprint, reconcile_app
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert
from authentik.enterprise.providers.ws_federation.models import WSFederationProvider
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id
from authentik.providers.saml.models import SAMLPropertyMapping
from tests.e2e.utils import SeleniumTestCase, retry
class TestProviderWSFed(SeleniumTestCase):
"""test WS Federation flow"""
def setup_client(self, provider: WSFederationProvider, app: Application, **kwargs):
metadata_url = (
self.url(
"authentik_api:wsfederationprovider-metadata",
pk=provider.pk,
)
+ "?download"
)
self.run_container(
image="ghcr.io/beryju/wsfed-test-sp:v0.1.2",
ports={
"8080": "8080",
},
environment={
"WSFED_TEST_SP_WTREALM": f"goauthentik.io://app/{app.slug}",
"WSFED_TEST_SP_METADATA": metadata_url,
**kwargs,
},
)
@retry()
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
"default/flow-default-invalidation-flow.yaml",
)
@apply_blueprint(
"default/flow-default-provider-authorization-implicit-consent.yaml",
"default/flow-default-provider-invalidation.yaml",
)
@apply_blueprint(
"system/providers-saml.yaml",
)
@reconcile_app("authentik_crypto")
def test_sp_initiated_implicit(self):
"""test WSFed Provider flow SP-initiated flow (implicit consent)"""
# Bootstrap all needed objects
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-implicit-consent"
)
invalidation_flow = Flow.objects.get(slug="default-provider-invalidation-flow")
provider = WSFederationProvider.objects.create(
name=generate_id(),
acs_url="http://localhost:8080",
authorization_flow=authorization_flow,
invalidation_flow=invalidation_flow,
signing_kp=create_test_cert(),
)
provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save()
app = Application.objects.create(
name="WSFed",
slug=generate_id(),
provider=provider,
)
self.setup_client(provider, app)
self.driver.get("http://localhost:8080")
self.login()
self.wait_for_url("http://localhost:8080/")
body = self.parse_json_content(self.driver.find_element(By.CSS_SELECTOR, "pre"))
snippet = dumps(body, indent=2)[:500].replace("\n", " ")
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"),
self.user.name,
f"Claim 'name' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"),
self.user.username,
f"Claim 'windowsaccountname' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.goauthentik.io/2021/02/saml/username"),
self.user.username,
f"Claim 'saml/username' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.goauthentik.io/2021/02/saml/uid"),
str(self.user.pk),
f"Claim 'saml/uid' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"),
self.user.email,
f"Claim 'emailaddress' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"),
self.user.email,
f"Claim 'upn' mismatch at {self.driver.current_url}: {snippet}",
)
self.driver.get("http://localhost:8080/Logout")
should_url = self.url(
"authentik_core:if-flow",
flow_slug=invalidation_flow.slug,
)
self.wait.until(
lambda driver: driver.current_url.startswith(should_url),
f"URL {self.driver.current_url} doesn't match expected URL {should_url}",
)
@retry()
@apply_blueprint(
"default/flow-default-authentication-flow.yaml",
"default/flow-default-invalidation-flow.yaml",
)
@apply_blueprint(
"default/flow-default-provider-authorization-explicit-consent.yaml",
)
@apply_blueprint(
"system/providers-saml.yaml",
)
@reconcile_app("authentik_crypto")
def test_sp_initiated_explicit(self):
"""test WSFed Provider flow SP-initiated flow (explicit consent)"""
# Bootstrap all needed objects
authorization_flow = Flow.objects.get(
slug="default-provider-authorization-explicit-consent"
)
provider = WSFederationProvider.objects.create(
name=generate_id(),
acs_url="http://localhost:8080",
authorization_flow=authorization_flow,
signing_kp=create_test_cert(),
)
provider.property_mappings.set(SAMLPropertyMapping.objects.all())
provider.save()
app = Application.objects.create(
name="WSFed",
slug=generate_id(),
provider=provider,
)
self.setup_client(provider, app)
self.driver.get("http://localhost:8080")
self.login()
self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "ak-flow-executor")))
flow_executor = self.get_shadow_root("ak-flow-executor")
consent_stage = self.get_shadow_root("ak-stage-consent", flow_executor)
self.assertIn(
app.name,
consent_stage.find_element(By.CSS_SELECTOR, "[data-test-id='stage-heading']").text,
"Consent stage header mismatch",
)
consent_stage.find_element(
By.CSS_SELECTOR,
"[type=submit]",
).click()
self.wait_for_url("http://localhost:8080/")
body = self.parse_json_content(self.driver.find_element(By.CSS_SELECTOR, "pre"))
snippet = dumps(body, indent=2)[:500].replace("\n", " ")
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"),
self.user.name,
f"Claim 'name' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname"),
self.user.username,
f"Claim 'windowsaccountname' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.goauthentik.io/2021/02/saml/username"),
self.user.username,
f"Claim 'saml/username' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.goauthentik.io/2021/02/saml/uid"),
str(self.user.pk),
f"Claim 'saml/uid' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"),
self.user.email,
f"Claim 'emailaddress' mismatch at {self.driver.current_url}: {snippet}",
)
self.assertEqual(
body.get("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"),
self.user.email,
f"Claim 'upn' mismatch at {self.driver.current_url}: {snippet}",
)

View File

@@ -164,11 +164,20 @@ class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase):
def wait_for_url(self, desired_url: str):
"""Wait until URL is `desired_url`."""
self.wait.until(
lambda driver: driver.current_url == desired_url,
f"URL {self.driver.current_url} doesn't match expected URL {desired_url}. "
f"HTML: {self.driver.page_source[:1000]}",
)
def waiter(driver: WebDriver):
current = driver.current_url
return current == desired_url
# We catch and re-throw the exception from `wait.until`, as we can supply it
# an error message, however that message is evaluated when we call `.until()`,
# not when the error is thrown, so the URL in the error message will be incorrect.
try:
self.wait.until(waiter)
except TimeoutException as exc:
raise TimeoutException(
f"URL {self.driver.current_url} doesn't match expected URL {desired_url}. "
f"HTML: {self.driver.page_source[:1000]}"
) from exc
def url(self, view: str, query: dict | None = None, **kwargs) -> str:
"""reverse `view` with `**kwargs` into full URL using live_server_url"""

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23 23">
<path fill="#000000" d="M1 1h10v10H1z"/>
<path fill="#000000" d="M12 1h10v10H12z"/>
<path fill="#000000" d="M1 12h10v10H1z"/>
<path fill="#000000" d="M12 12h10v10H12z"/>
</svg>

After

Width:  |  Height:  |  Size: 254 B

View File

@@ -6,7 +6,7 @@ import { ApplicationWizardProviderForm } from "./ApplicationWizardProviderForm.j
import { type AkCryptoCertificateSearch } from "#admin/common/ak-crypto-certificate-search";
import { renderForm } from "#admin/providers/saml/SAMLProviderFormForm";
import { SAMLBindingsEnum, SAMLProvider, SAMLProviderLogoutMethodEnum } from "@goauthentik/api";
import { SAMLBindingsEnum, SAMLLogoutMethods, SAMLProvider } from "@goauthentik/api";
import { msg } from "@lit/localize";
import { customElement, state } from "@lit/reactive-element/decorators.js";
@@ -26,18 +26,18 @@ export class ApplicationWizardProviderSamlForm extends ApplicationWizardProvider
protected hasPostBinding = false;
@state()
protected logoutMethod: string = SAMLProviderLogoutMethodEnum.FrontchannelIframe;
protected logoutMethod: string = SAMLLogoutMethods.FrontchannelIframe;
get formValues() {
const values = super.formValues;
// If SLS binding is redirect, ensure logout method is not backchannel
if (
values.slsBinding === SAMLBindingsEnum.Redirect &&
values.logoutMethod === SAMLProviderLogoutMethodEnum.Backchannel
values.logoutMethod === SAMLLogoutMethods.Backchannel
) {
return {
...values,
logoutMethod: SAMLProviderLogoutMethodEnum.FrontchannelIframe,
logoutMethod: SAMLLogoutMethods.FrontchannelIframe,
};
}
return values;
@@ -65,9 +65,9 @@ export class ApplicationWizardProviderSamlForm extends ApplicationWizardProvider
// If switching to redirect binding, change logout method from backchannel if needed
if (
target.value === SAMLBindingsEnum.Redirect &&
this.logoutMethod === SAMLProviderLogoutMethodEnum.Backchannel
this.logoutMethod === SAMLLogoutMethods.Backchannel
) {
this.logoutMethod = SAMLProviderLogoutMethodEnum.FrontchannelIframe;
this.logoutMethod = SAMLLogoutMethods.FrontchannelIframe;
}
};

View File

@@ -10,6 +10,7 @@ import "#admin/providers/radius/RadiusProviderForm";
import "#admin/providers/saml/SAMLProviderForm";
import "#admin/providers/scim/SCIMProviderForm";
import "#admin/providers/ssf/SSFProviderFormPage";
import "#admin/providers/wsfed/WSFederationProviderForm";
import "#elements/buttons/SpinnerButton/index";
import "#elements/forms/DeleteBulkForm";
import "#elements/forms/ModalForm";

View File

@@ -8,6 +8,7 @@ import "#admin/providers/radius/RadiusProviderViewPage";
import "#admin/providers/saml/SAMLProviderViewPage";
import "#admin/providers/scim/SCIMProviderViewPage";
import "#admin/providers/ssf/SSFProviderViewPage";
import "#admin/providers/wsfed/WSFederationProviderViewPage";
import "#elements/EmptyState";
import "#elements/buttons/SpinnerButton/ak-spinner-button";
@@ -86,6 +87,8 @@ export class ProviderViewPage extends AKElement {
></ak-provider-microsoft-entra-view>`;
case "ak-provider-ssf-form":
return html`<ak-provider-ssf-view ${spread(props)}></ak-provider-ssf-view>`;
case "ak-provider-wsfed-form":
return html`<ak-provider-wsfed-view ${spread(props)}></ak-provider-wsfed-view>`;
default:
return html`<p>Invalid provider type ${this.provider?.component}</p>`;
}

View File

@@ -5,12 +5,7 @@ import { DEFAULT_CONFIG } from "#common/api/config";
import { type AkCryptoCertificateSearch } from "#admin/common/ak-crypto-certificate-search";
import { BaseProviderForm } from "#admin/providers/BaseProviderForm";
import {
ProvidersApi,
SAMLBindingsEnum,
SAMLProvider,
SAMLProviderLogoutMethodEnum,
} from "@goauthentik/api";
import { ProvidersApi, SAMLBindingsEnum, SAMLLogoutMethods, SAMLProvider } from "@goauthentik/api";
import { customElement, state } from "lit/decorators.js";
@@ -26,8 +21,7 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
protected hasPostBinding = false;
@state()
protected logoutMethod: SAMLProviderLogoutMethodEnum =
SAMLProviderLogoutMethodEnum.FrontchannelIframe;
protected logoutMethod: SAMLLogoutMethods = SAMLLogoutMethods.FrontchannelIframe;
public override reset(): void {
super.reset();
@@ -35,7 +29,7 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
this.hasSigningKp = false;
this.hasSlsUrl = false;
this.hasPostBinding = false;
this.logoutMethod = SAMLProviderLogoutMethodEnum.FrontchannelIframe;
this.logoutMethod = SAMLLogoutMethods.FrontchannelIframe;
}
async loadInstance(pk: number): Promise<SAMLProvider> {
@@ -45,8 +39,7 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
this.hasSigningKp = !!provider.signingKp;
this.hasSlsUrl = !!provider.slsUrl;
this.hasPostBinding = provider.slsBinding === SAMLBindingsEnum.Post;
this.logoutMethod =
provider.logoutMethod ?? SAMLProviderLogoutMethodEnum.FrontchannelIframe;
this.logoutMethod = provider.logoutMethod ?? SAMLLogoutMethods.FrontchannelIframe;
return provider;
}
@@ -54,9 +47,9 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
// If SLS binding is redirect, ensure logout method is not backchannel
if (
data.slsBinding === SAMLBindingsEnum.Redirect &&
data.logoutMethod === SAMLProviderLogoutMethodEnum.Backchannel
data.logoutMethod === SAMLLogoutMethods.Backchannel
) {
data.logoutMethod = SAMLProviderLogoutMethodEnum.FrontchannelIframe;
data.logoutMethod = SAMLLogoutMethods.FrontchannelIframe;
}
if (this.instance) {
@@ -92,15 +85,15 @@ export class SAMLProviderFormPage extends BaseProviderForm<SAMLProvider> {
// If switching to redirect binding, change logout method from backchannel if needed
if (
target.value === SAMLBindingsEnum.Redirect &&
this.logoutMethod === SAMLProviderLogoutMethodEnum.Backchannel
this.logoutMethod === SAMLLogoutMethods.Backchannel
) {
this.logoutMethod = SAMLProviderLogoutMethodEnum.FrontchannelIframe;
this.logoutMethod = SAMLLogoutMethods.FrontchannelIframe;
}
};
const setLogoutMethod = (ev: Event) => {
const target = ev.target as HTMLInputElement;
this.logoutMethod = target.value as SAMLProviderLogoutMethodEnum;
this.logoutMethod = target.value as SAMLLogoutMethods;
};
return renderForm({

View File

@@ -22,10 +22,10 @@ import {
PropertymappingsApi,
PropertymappingsProviderSamlListRequest,
SAMLBindingsEnum,
SAMLLogoutMethods,
SAMLNameIDPolicyEnum,
SAMLPropertyMapping,
SAMLProvider,
SAMLProviderLogoutMethodEnum,
ValidationError,
} from "@goauthentik/api";
@@ -79,16 +79,16 @@ function renderHasSlsUrl(
const logoutMethodOptions: RadioOption<string>[] = [
{
label: msg("Front-channel (Iframe)"),
value: SAMLProviderLogoutMethodEnum.FrontchannelIframe,
value: SAMLLogoutMethods.FrontchannelIframe,
default: true,
},
{
label: msg("Front-channel (Native)"),
value: SAMLProviderLogoutMethodEnum.FrontchannelNative,
value: SAMLLogoutMethods.FrontchannelNative,
},
{
label: msg("Back-channel (POST)"),
value: SAMLProviderLogoutMethodEnum.Backchannel,
value: SAMLLogoutMethods.Backchannel,
disabled: !hasPostBinding,
},
];

View File

@@ -47,7 +47,7 @@ import PFList from "@patternfly/patternfly/components/List/list.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
interface SAMLPreviewAttribute {
export interface SAMLPreviewAttribute {
attributes: {
Name: string;
Value: string[];

View File

@@ -0,0 +1,372 @@
import "#admin/common/ak-crypto-certificate-search";
import "#components/ak-text-input";
import "#elements/ak-dual-select/ak-dual-select-dynamic-selected-provider";
import "#elements/ak-dual-select/ak-dual-select-provider";
import "#elements/forms/FormGroup";
import "#elements/forms/HorizontalFormElement";
import "#elements/forms/SearchSelect/index";
import "#elements/utils/TimeDeltaHelp";
import "#components/ak-radio-input";
import "#components/ak-switch-input";
import "#admin/common/ak-flow-search/ak-flow-search";
import "#elements/forms/Radio";
import { DEFAULT_CONFIG } from "#common/api/config";
import AkCryptoCertificateSearch from "#admin/common/ak-crypto-certificate-search";
import { BaseProviderForm } from "#admin/providers/BaseProviderForm";
import {
propertyMappingsProvider,
propertyMappingsSelector,
} from "#admin/providers/saml/SAMLProviderFormHelpers";
import {
digestAlgorithmOptions,
signatureAlgorithmOptions,
} from "#admin/providers/saml/SAMLProviderOptions";
import {
FlowsInstancesListDesignationEnum,
PropertymappingsApi,
PropertymappingsProviderSamlListRequest,
ProvidersApi,
SAMLNameIDPolicyEnum,
SAMLPropertyMapping,
WSFederationProvider,
} from "@goauthentik/api";
import { msg } from "@lit/localize";
import { html, nothing, TemplateResult } from "lit";
import { customElement, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
/**
* Form page for SSF Authentication Method
*
* @element ak-provider-ssf-form
*
*/
@customElement("ak-provider-wsfed-form")
export class WSFederationProviderForm extends BaseProviderForm<WSFederationProvider> {
@state()
protected hasSigningKp = false;
async loadInstance(pk: number): Promise<WSFederationProvider> {
const provider = await new ProvidersApi(DEFAULT_CONFIG).providersWsfedRetrieve({
id: pk,
});
this.hasSigningKp = !!provider.signingKp;
return provider;
}
async send(data: WSFederationProvider): Promise<WSFederationProvider> {
if (this.instance) {
return new ProvidersApi(DEFAULT_CONFIG).providersWsfedUpdate({
id: this.instance.pk,
wSFederationProviderRequest: data,
});
}
return new ProvidersApi(DEFAULT_CONFIG).providersWsfedCreate({
wSFederationProviderRequest: data,
});
}
renderForm(): TemplateResult {
const provider = this.instance;
return html`<ak-text-input
name="name"
label=${msg("Provider Name")}
placeholder=${msg("Type a provider name...")}
spellcheck="false"
value=${ifDefined(provider?.name)}
required
></ak-text-input>
<ak-form-element-horizontal
name="authorizationFlow"
label=${msg("Authorization flow")}
required
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authorization}
.currentFlow=${this.instance?.authorizationFlow}
required
></ak-flow-search>
<p class="pf-c-form__helper-text">
${msg("Flow used when authorizing this this.instance?.")}
</p>
</ak-form-element-horizontal>
<ak-form-group open label="${msg("Protocol settings")}">
<div class="pf-c-form">
<ak-text-input
name="replyUrl"
label=${msg("Reply URL")}
placeholder=${msg("https://...")}
input-hint="code"
inputmode="url"
value="${ifDefined(this.instance?.replyUrl)}"
required
></ak-text-input>
</div>
</ak-form-group>
<ak-form-group label="${msg("Advanced flow settings")}">
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Authentication flow")}
name="authenticationFlow"
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Authentication}
.currentFlow=${this.instance?.authenticationFlow}
></ak-flow-search>
<p class="pf-c-form__helper-text">
${msg(
"Flow used when a user access this provider and is not authenticated.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Invalidation flow")}
name="invalidationFlow"
required
>
<ak-flow-search
flowType=${FlowsInstancesListDesignationEnum.Invalidation}
.currentFlow=${this.instance?.invalidationFlow}
defaultFlowSlug="default-provider-invalidation-flow"
required
></ak-flow-search>
<p class="pf-c-form__helper-text">
${msg("Flow used when logging out of this this.instance?.")}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group label="${msg("Advanced protocol settings")}">
<div class="pf-c-form">
<ak-form-element-horizontal
label=${msg("Signing Certificate")}
name="signingKp"
>
<ak-crypto-certificate-search
.certificate=${this.instance?.signingKp}
@input=${(ev: InputEvent) => {
const target = ev.target as AkCryptoCertificateSearch;
if (!target) return;
this.hasSigningKp = !!target.selectedKeypair;
}}
singleton
></ak-crypto-certificate-search>
<p class="pf-c-form__helper-text">
${msg(
"Certificate used to sign outgoing Responses going to the Service this.instance?.",
)}
</p>
</ak-form-element-horizontal>
${this.hasSigningKp
? html`<ak-switch-input
name="signAssertion"
label=${msg("Sign assertions")}
?checked=${this.instance?.signAssertion ?? true}
help=${msg(
"When enabled, the assertion element of the SAML response will be signed.",
)}
>
</ak-switch-input>
<ak-switch-input
name="signLogoutRequest"
label=${msg("Sign logout requests")}
?checked=${this.instance?.signLogoutRequest ?? false}
help=${msg("When enabled, SAML logout requests will be signed.")}
>
</ak-switch-input>`
: nothing}
<ak-form-element-horizontal
label=${msg("Encryption Certificate")}
name="encryptionKp"
>
<ak-crypto-certificate-search
.certificate=${this.instance?.encryptionKp}
></ak-crypto-certificate-search>
<p class="pf-c-form__helper-text">
${msg(
"When selected, assertions will be encrypted using this keypair.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Property mappings")}
name="propertyMappings"
>
<ak-dual-select-dynamic-selected
.provider=${propertyMappingsProvider}
.selector=${propertyMappingsSelector(this.instance?.propertyMappings)}
available-label=${msg("Available User Property Mappings")}
selected-label=${msg("Selected User Property Mappings")}
></ak-dual-select-dynamic-selected>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("NameID Property Mapping")}
name="nameIdMapping"
>
<ak-search-select
.fetchObjects=${async (
query?: string,
): Promise<SAMLPropertyMapping[]> => {
const args: PropertymappingsProviderSamlListRequest = {
ordering: "saml_name",
};
if (query !== undefined) {
args.search = query;
}
const items = await new PropertymappingsApi(
DEFAULT_CONFIG,
).propertymappingsProviderSamlList(args);
return items.results;
}}
.renderElement=${(item: SAMLPropertyMapping): string => {
return item.name;
}}
.value=${(
item: SAMLPropertyMapping | undefined,
): string | undefined => {
return item?.pk;
}}
.selected=${(item: SAMLPropertyMapping): boolean => {
return this.instance?.nameIdMapping === item.pk;
}}
blankable
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${msg(
"Configure how the NameID value will be created. When left empty, the NameIDPolicy of the incoming request will be respected.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("AuthnContextClassRef Property Mapping")}
name="authnContextClassRefMapping"
>
<ak-search-select
.fetchObjects=${async (
query?: string,
): Promise<SAMLPropertyMapping[]> => {
const args: PropertymappingsProviderSamlListRequest = {
ordering: "saml_name",
};
if (query !== undefined) {
args.search = query;
}
const items = await new PropertymappingsApi(
DEFAULT_CONFIG,
).propertymappingsProviderSamlList(args);
return items.results;
}}
.renderElement=${(item: SAMLPropertyMapping): string => {
return item.name;
}}
.value=${(
item: SAMLPropertyMapping | undefined,
): string | undefined => {
return item?.pk;
}}
.selected=${(item: SAMLPropertyMapping): boolean => {
return this.instance?.authnContextClassRefMapping === item.pk;
}}
blankable
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${msg(
"Configure how the AuthnContextClassRef value will be created. When left empty, the AuthnContextClassRef will be set based on which authentication methods the user used to authenticate.",
)}
</p>
</ak-form-element-horizontal>
<ak-text-input
name="sessionValidNotOnOrAfter"
label=${msg("Session valid not on or after")}
value="${this.instance?.sessionValidNotOnOrAfter || "minutes=86400"}"
required
help=${msg("Session not valid on or after current time + this value.")}
></ak-text-input>
<ak-form-element-horizontal
label=${msg("Default NameID Policy")}
required
name="defaultNameIdPolicy"
>
<select class="pf-c-form-control">
<option
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
?selected=${provider?.defaultNameIdPolicy ===
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatPersistent}
>
${msg("Persistent")}
</option>
<option
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
?selected=${provider?.defaultNameIdPolicy ===
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatEmailAddress}
>
${msg("Email address")}
</option>
<option
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
?selected=${provider?.defaultNameIdPolicy ===
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatWindowsDomainQualifiedName}
>
${msg("Windows")}
</option>
<option
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
?selected=${provider?.defaultNameIdPolicy ===
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml11NameidFormatX509SubjectName}
>
${msg("X509 Subject")}
</option>
<option
value=${SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
?selected=${provider?.defaultNameIdPolicy ===
SAMLNameIDPolicyEnum.UrnOasisNamesTcSaml20NameidFormatTransient}
>
${msg("Transient")}
</option>
</select>
<p class="pf-c-form__helper-text">
${msg(
"Configure the default NameID Policy used by IDP-initiated logins and when an incoming assertion doesn't specify a NameID Policy (also applies when using a custom NameID Mapping).",
)}
</p>
</ak-form-element-horizontal>
<ak-radio-input
name="digestAlgorithm"
label=${msg("Digest algorithm")}
.options=${digestAlgorithmOptions}
.value=${this.instance?.digestAlgorithm}
required
>
</ak-radio-input>
<ak-radio-input
name="signatureAlgorithm"
label=${msg("Signature algorithm")}
.options=${signatureAlgorithmOptions}
.value=${this.instance?.signatureAlgorithm}
required
>
</ak-radio-input>
</div>
</ak-form-group> `;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-provider-wsfed-form": WSFederationProviderForm;
}
}

View File

@@ -0,0 +1,511 @@
import "#admin/providers/RelatedApplicationButton";
import "#admin/providers/wsfed/WSFederationProviderForm";
import "#admin/rbac/ObjectPermissionsPage";
import "#components/events/ObjectChangelog";
import "#elements/CodeMirror";
import "#elements/EmptyState";
import "#elements/Tabs";
import "#elements/buttons/ActionButton/index";
import "#elements/buttons/ModalButton";
import "#elements/buttons/SpinnerButton/index";
import { DEFAULT_CONFIG } from "#common/api/config";
import { EVENT_REFRESH } from "#common/constants";
import { MessageLevel } from "#common/messages";
import { AKElement } from "#elements/Base";
import { showMessage } from "#elements/messages/MessageContainer";
import { SlottedTemplateResult } from "#elements/types";
import renderDescriptionList from "#components/DescriptionList";
import { SAMLPreviewAttribute } from "#admin/providers/saml/SAMLProviderViewPage";
import {
CertificateKeyPair,
CoreApi,
CoreUsersListRequest,
CryptoApi,
ProvidersApi,
RbacPermissionsAssignedByRolesListModelEnum,
SAMLMetadata,
User,
WSFederationProvider,
} from "@goauthentik/api";
import { msg } from "@lit/localize";
import { CSSResult, html, nothing, PropertyValues, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFBanner from "@patternfly/patternfly/components/Banner/banner.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
import PFContent from "@patternfly/patternfly/components/Content/content.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import PFForm from "@patternfly/patternfly/components/Form/form.css";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFList from "@patternfly/patternfly/components/List/list.css";
import PFPage from "@patternfly/patternfly/components/Page/page.css";
import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css";
@customElement("ak-provider-wsfed-view")
export class WSFederationProviderViewPage extends AKElement {
@property({ type: Number })
public providerID: number | null = null;
@state()
protected provider: WSFederationProvider | null = null;
@state()
protected preview: SAMLPreviewAttribute | null = null;
@state()
protected metadata: SAMLMetadata | null = null;
@state()
protected signer: CertificateKeyPair | null = null;
@state()
protected verifier: CertificateKeyPair | null = null;
@state()
protected previewUser: User | null = null;
static styles: CSSResult[] = [
PFButton,
PFPage,
PFGrid,
PFContent,
PFCard,
PFList,
PFDescriptionList,
PFForm,
PFFormControl,
PFBanner,
];
constructor() {
super();
this.addEventListener(EVENT_REFRESH, () => {
if (!this.provider?.pk) return;
this.fetchProvider(this.provider.pk);
});
}
fetchPreview(): void {
new ProvidersApi(DEFAULT_CONFIG)
.providersWsfedPreviewUserRetrieve({
id: this.provider?.pk || 0,
forUser: this.previewUser?.pk,
})
.then((preview) => {
this.preview = preview.preview as SAMLPreviewAttribute;
});
}
fetchCertificate(kpUuid: string) {
return new CryptoApi(DEFAULT_CONFIG).cryptoCertificatekeypairsRetrieve({ kpUuid });
}
fetchSigningCertificate(kpUuid: string) {
this.fetchCertificate(kpUuid).then((kp) => {
this.signer = kp;
this.requestUpdate("signer");
});
}
fetchProvider(id: number) {
new ProvidersApi(DEFAULT_CONFIG).providersWsfedRetrieve({ id }).then((prov) => {
this.provider = prov;
// Clear existing signing certificate if the provider has none
if (!this.provider.signingKp) {
this.signer = null;
} else {
this.fetchSigningCertificate(this.provider.signingKp);
}
});
}
protected override willUpdate(changedProperties: PropertyValues<this>) {
if (changedProperties.has("providerID") && this.providerID) {
this.fetchProvider(this.providerID);
}
}
renderRelatedObjects(): TemplateResult {
const relatedObjects = [];
if (this.provider?.assignedApplicationName) {
relatedObjects.push(
html`<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${msg("Metadata")}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<a
class="pf-c-button pf-m-primary"
target="_blank"
href=${ifDefined(this.provider?.urlDownloadMetadata)}
>
${msg("Download")}
</a>
<ak-action-button
class="pf-m-secondary"
.apiRequest=${() => {
if (!navigator.clipboard) {
return Promise.resolve(
showMessage({
level: MessageLevel.info,
message: this.provider?.urlDownloadMetadata || "",
}),
);
}
return navigator.clipboard.writeText(
this.provider?.urlDownloadMetadata || "",
);
}}
>
${msg("Copy download URL")}
</ak-action-button>
</div>
</dd>
</div>`,
);
}
if (this.signer) {
relatedObjects.push(
html`<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("Download signing certificate")}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<a
class="pf-c-button pf-m-primary"
href=${this.signer.certificateDownloadUrl}
>${msg("Download")}</a
>
</div>
</dd>
</div>`,
);
}
return html` <div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">${msg("Related objects")}</div>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-2-col">
${relatedObjects.length > 0 ? relatedObjects : html`-`}
</dl>
</div>
</div>`;
}
render(): SlottedTemplateResult {
if (!this.provider) {
return nothing;
}
return html`<main part="main">
<ak-tabs part="tabs">
<div
role="tabpanel"
tabindex="0"
slot="page-overview"
id="page-overview"
aria-label="${msg("Overview")}"
>
${this.renderTabOverview()}
</div>
${this.renderTabMetadata()}
<div
role="tabpanel"
tabindex="0"
slot="page-preview"
id="page-preview"
aria-label="${msg("Preview")}"
@activate=${() => {
this.fetchPreview();
}}
>
${this.renderTabPreview()}
</div>
<div
role="tabpanel"
tabindex="0"
slot="page-changelog"
id="page-changelog"
aria-label="${msg("Changelog")}"
class="pf-c-page__main-section pf-m-no-padding-mobile"
>
<div class="pf-c-card">
<div class="pf-c-card__body">
<ak-object-changelog
targetModelPk=${this.provider?.pk || ""}
targetModelName=${this.provider?.metaModelName || ""}
>
</ak-object-changelog>
</div>
</div>
</div>
<ak-rbac-object-permission-page
role="tabpanel"
tabindex="0"
slot="page-permissions"
id="page-permissions"
aria-label="${msg("Permissions")}"
model=${RbacPermissionsAssignedByRolesListModelEnum.AuthentikProvidersWsFederationWsfederationprovider}
objectPk=${this.provider.pk}
></ak-rbac-object-permission-page>
</ak-tabs>
</main>`;
}
renderTabOverview(): SlottedTemplateResult {
if (!this.provider) {
return nothing;
}
return html`${
this.provider?.assignedApplicationName
? nothing
: html`<div slot="header" class="pf-c-banner pf-m-warning">
${msg("Warning: Provider is not used by an Application.")}
</div>`
}
<div class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter">
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__body">
${renderDescriptionList(
[
[msg("Name"), this.provider.name],
[
msg("Assigned to application"),
html`<ak-provider-related-application
.provider=${this.provider}
></ak-provider-related-application>`,
],
[msg("Reply URL"), this.provider.replyUrl],
],
{ threecolumn: true },
)}
</div>
<div class="pf-c-card__footer">
<ak-forms-modal>
<span slot="submit">${msg("Update")}</span>
<span slot="header">${msg("Update WS-Federation Provider")}</span>
<ak-provider-wsfed-form slot="form" .instancePk=${this.provider.pk || 0}>
</ak-provider-wsfed-form>
<button slot="trigger" class="pf-c-button pf-m-primary">
${msg("Edit")}
</button>
</ak-forms-modal>
</div>
</div>
${this.renderRelatedObjects()}
${
this.provider.assignedApplicationName
? html` <div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">
${msg("WS-Federation Configuration")}
</div>
<div class="pf-c-card__body">
<form class="pf-c-form">
<div class="pf-c-form__group">
<label class="pf-c-form__label">
<span class="pf-c-form__label-text"
>${msg("WS-Federation URL")}</span
>
</label>
<input
class="pf-c-form-control"
readonly
type="text"
value="${ifDefined(this.provider.urlWsfed)}"
/>
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label">
<span class="pf-c-form__label-text"
>${msg("Realm (wtrealm)")}</span
>
</label>
<input
class="pf-c-form-control"
readonly
type="text"
value="${ifDefined(this.provider.wtrealm)}"
/>
</div>
</form>
</div>
</div>`
: nothing
}
</div>
</div>`;
}
renderTabMetadata(): SlottedTemplateResult {
if (!this.provider) {
return nothing;
}
return html`
${this.provider.assignedApplicationName
? html` <div
role="tabpanel"
tabindex="0"
slot="page-metadata"
id="page-metadata"
aria-label="${msg("Metadata")}"
@activate=${() => {
new ProvidersApi(DEFAULT_CONFIG)
.providersWsfedMetadataRetrieve({
id: this.provider?.pk || 0,
})
.then((metadata) => (this.metadata = metadata));
}}
>
<div
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"
>
<div class="pf-c-card pf-l-grid__item pf-m-12-col">
<div class="pf-c-card__title">${msg("WS-Federation Metadata")}</div>
<div class="pf-c-card__body">
<a
class="pf-c-button pf-m-primary"
target="_blank"
href=${this.provider.urlDownloadMetadata}
>
${msg("Download")}
</a>
<ak-action-button
class="pf-m-secondary"
.apiRequest=${() => {
if (!navigator.clipboard) {
return Promise.resolve(
showMessage({
level: MessageLevel.info,
message:
this.provider?.urlDownloadMetadata || "",
}),
);
}
return navigator.clipboard.writeText(
this.provider?.urlDownloadMetadata || "",
);
}}
>
${msg("Copy download URL")}
</ak-action-button>
</div>
<div class="pf-c-card__footer">
<ak-codemirror
mode="xml"
readonly
value="${ifDefined(this.metadata?.metadata)}"
></ak-codemirror>
</div>
</div>
</div>
</div>`
: nothing}
`;
}
renderTabPreview(): SlottedTemplateResult {
if (!this.preview) {
return html`<ak-empty-state loading></ak-empty-state>`;
}
return html` <div
class="pf-c-page__main-section pf-m-no-padding-mobile pf-l-grid pf-m-gutter"
>
<div class="pf-c-card">
<div class="pf-c-card__title">${msg("Example WS-Federation attributes")}</div>
<div class="pf-c-card__body">
${renderDescriptionList([
[
msg("Preview for user"),
html`
<ak-search-select
.fetchObjects=${async (query?: string): Promise<User[]> => {
const args: CoreUsersListRequest = {
ordering: "username",
};
if (query !== undefined) {
args.search = query;
}
const users = await new CoreApi(
DEFAULT_CONFIG,
).coreUsersList(args);
return users.results;
}}
.renderElement=${(user: User): string => {
return user.username;
}}
.renderDescription=${(user: User): TemplateResult => {
return html`${user.name}`;
}}
.value=${(user: User | undefined): number | undefined => {
return user?.pk;
}}
.selected=${(user: User): boolean => {
return user.pk === this.previewUser?.pk;
}}
blankable
@ak-change=${(ev: CustomEvent) => {
this.previewUser = ev.detail.value;
this.fetchPreview();
}}
>
</ak-search-select>
`,
],
])}
</div>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-2-col-on-lg">
<div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text"
>${msg("NameID attribute")}</span
>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
${this.preview?.nameID}
</div>
</dd>
</div>
</dl>
</div>
<div class="pf-c-card__body">
<dl class="pf-c-description-list pf-m-2-col-on-lg">
${this.preview?.attributes.map((attr) => {
return html` <div class="pf-c-description-list__group">
<dt class="pf-c-description-list__term">
<span class="pf-c-description-list__text">${attr.Name}</span>
</dt>
<dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text">
<ul class="pf-c-list">
${attr.Value.map((value) => {
return html` <li><pre>${value}</pre></li> `;
})}
</ul>
</div>
</dd>
</div>`;
})}
</dl>
</div>
</div>
</div>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-provider-wsfed-view": WSFederationProviderViewPage;
}
}