8000 Add ability to inspect generated SAML response for SAML Clients with client scope mappings by thomasdarimont · Pull Request #30396 · keycloak/keycloak · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add ability to inspect generated SAML response for SAML Clients with client scope mappings #30396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

thomasdarimont
Copy link
Contributor

Fixes #30328

@mposolda
Copy link
Contributor

@thomasdarimont Would you mind to continue on this PR? I think it can be nice as a feature to Keycloak.

I believe it can be nice to polish a bit (EG. removing comments, make sure that it is shown just for SAML clients and not for OIDC clients etc). And make sure there are not test failures. WDYT?

@thomasdarimont thomasdarimont force-pushed the issue/gh-30328-client-scope-eval-saml-respose branch from 375b4bd to ad75229 Compare July 4, 2025 17:58
@thomasdarimont
Copy link
Contributor Author
thomasdarimont commented Jul 4, 2025

SAML Client Example:
image

Revised Scope Evaluate View for SAML Clients:

  • Removed Scope Selection for clients with protocol == saml
  • Removed AccessToken/IDToken/UserInfo tabs for clients with protocol == saml
  • Added Generated SAML Response tab
  • The SAML response generation also consideres "default" SAML scopes, but optional SAML scopes are not supported
  • To disable a "default" SAML scope mapper, users can set the scope mapper to "optional" or remove the entry.
image

Generated SAML Response with default mappers:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="https://saml-demo-client.apps.acme.test/" ID="ID_ea6d2ab1-d5da-4bde-8d09-12fc597c78bd" IssueInstant="2025-07-04T19:30:22.715Z" Version="2.0">
    <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_ad984553-0a2b-4176-af4a-703cecd9c388" IssueInstant="2025-07-04T19:30:22.715Z" Version="2.0">
        <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">tester</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2025-07-04T19:35:20.715Z" Recipient="https://saml-demo-client.apps.acme.test/"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2025-07-04T19:30:20.715Z" NotOnOrAfter="2025-07-04T19:31:20.715Z">
            <saml:AudienceRestriction>
                <saml:Audience>demo-saml-client</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2025-07-04T19:30:22.715Z" SessionIndex="e9bc353c-3f49-478d-a635-3f9d6a968e37::d5ad160d-6c8d-4c86-8285-8f0fcdcafbe0" SessionNotOnOrAfter="2025-07-05T05:30:22.715Z">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">view-profile</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">uma_authorization</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">offline_access</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">default-roles-saml-scope-eval</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account-links</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">user</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

With custom hardcoded attribute mapper:
image

Generated SAML Response with custom attribute mapper:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="https://saml-demo-client.apps.acme.test/" ID="ID_ea6d2ab1-d5da-4bde-8d09-12fc597c78bd" IssueInstant="2025-07-04T19:30:22.715Z" Version="2.0">
    <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_ad984553-0a2b-4176-af4a-703cecd9c388" IssueInstant="2025-07-04T19:30:22.715Z" Version="2.0">
        <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">tester</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2025-07-04T19:35:20.715Z" Recipient="https://saml-demo-client.apps.acme.test/"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2025-07-04T19:30:20.715Z" NotOnOrAfter="2025-07-04T19:31:20.715Z">
            <saml:AudienceRestriction>
                <saml:Audience>demo-saml-client</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2025-07-04T19:30:22.715Z" SessionIndex="e9bc353c-3f49-478d-a635-3f9d6a968e37::d5ad160d-6c8d-4c86-8285-8f0fcdcafbe0" SessionNotOnOrAfter="2025-07-05T05:30:22.715Z">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute FriendlyName="hardcoded" Name="urn:acme:id:demo:attributes:hardcoded" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">42</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">view-profile</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">uma_authorization</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">offline_access</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">default-roles-saml-scope-eval</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">manage-account-links</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="Role" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">user</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

Example SAML response with custom attribute, but with role mapper set to default:

<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination="https://saml-demo-client.apps.acme.test/" ID="ID_7b9093fc-fb8b-4862-8627-76f689ad3d64" IssueInstant="2025-07-04T19:33:15.515Z" Version="2.0">
    <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
    <samlp:Status>
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </samlp:Status>
    <saml:Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="ID_1d0c3ef1-5ba8-415d-9e2e-308e624f9a40" IssueInstant="2025-07-04T19:33:15.515Z" Version="2.0">
        <saml:Issuer>http://localhost:8081/auth/realms/saml-scope-eval</saml:Issuer>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">tester</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData NotOnOrAfter="2025-07-04T19:38:13.515Z" Recipient="https://saml-demo-client.apps.acme.test/"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2025-07-04T19:33:13.515Z" NotOnOrAfter="2025-07-04T19:34:13.515Z">
            <saml:AudienceRestriction>
                <saml:Audience>demo-saml-client</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AuthnStatement AuthnInstant="2025-07-04T19:33:15.515Z" SessionIndex="0f1d455e-c055-4f35-861f-1669fa2a1615::d5ad160d-6c8d-4c86-8285-8f0fcdcafbe0" SessionNotOnOrAfter="2025-07-05T05:33:15.515Z">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
        <saml:AttributeStatement>
            <saml:Attribute FriendlyName="hardcoded" Name="urn:acme:id:demo:attributes:hardcoded" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
                <saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">42</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
    </saml:Assertion>
</samlp:Response>

For comparison the Scope Evaluate screen for normal OIDC clients:
image

@thomasdarimont thomasdarimont added area/saml Indicates an issue on SAML area area/admin/ui labels Jul 4, 2025
@thomasdarimont thomasdarimont marked this pull request as ready for review July 4, 2025 18:09
@thomasdarimont thomasdarimont requested review from a team as code owners July 4, 2025 18:09
@thomasdarimont
Copy link
Contributor Author

@mposolda I eventually found the time to complete the feature :)

I think this is now ready for review.

Add ability to inspect generated SAML response for SAML Clients with client scope mappings.
We also consider default SAML scopes mappers as well as custom scope mappings.

Fixes keycloak#30328

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
(cherry picked from commit b014dd5251a2db4910d87c8db54b3c329006d742)
Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add ability to inspect generated SAML response for SAML Clients with client scope mappings
2 participants
0