Chuyển đến nội dung chính

Bài 7: SAML Clients và Protocol Mappers

Tạo và cấu hình SAML 2.0 clients, SAML bindings (POST, Redirect, Artifact), assertions configuration, XML signature và encryption, Entity Descriptor import, IDP Initiated Login. Protocol Mappers cho OIDC và SAML, Lightweight Access Tokens, Pairwise Subject Identifier.

🔒 DevSecOps — Bài 7 Bài 7: SAML Clients và Protocol Mappers

Keycloak từ Cơ bản đến Nâng cao

Phần 2: SSO Protocols - OpenID Connect và SAML

xdev.asia

1. Tổng quan SAML 2.0 trong Keycloak

SAML 2.0 (Security Assertion Markup Language) là giao thức xác thực dựa trên XML, được sử dụng rộng rãi trong enterprise — đặc biệt khi tích hợp với hệ thống legacy, SaaS applications (Salesforce, ServiceNow, AWS), hoặc các tổ chức chính phủ.

SAML 2.0 vs OpenID Connect

Đặc điểmSAML 2.0OpenID Connect
Định dạngXMLJSON (JWT)
TransportHTTP Redirect, POST, ArtifactHTTP REST
TokenSAML Assertion (XML)JWT
Kích thướcLớn hơn (XML verbose)Nhỏ gọn (JSON)
Mobile supportKém (XML parsing nặng)Tốt (JSON native)
Use case chínhEnterprise SSO, legacy systemsModern web/mobile apps
ComplexityCaoThấp hơn
LogoutSLO (Single Logout)RP-Initiated, Backchannel, Front-channel

Khi nào dùng SAML?

  • Tích hợp với SaaS applications yêu cầu SAML (Salesforce, Google Workspace, AWS)

  • Liên kết với IdP hoặc SP chỉ hỗ trợ SAML

  • Yêu cầu tuân thủ standards của tổ chức chính phủ

  • Migration từ hệ thống ADFS, Shibboleth

Thuật ngữ SAML

Thuật ngữMô tảTương đương OIDC
Identity Provider (IdP)Bên xác thực user (Keycloak)OpenID Provider (OP)
Service Provider (SP)Bên yêu cầu xác thực (ứng dụng)Relying Party (RP)
AssertionXML document chứa thông tin xác thựcID Token
AuthnRequestYêu cầu xác thực từ SP → IdPAuthorization Request
ACS URLAssertion Consumer Service URLRedirect URI
Entity IDUnique identifier cho SP/IdPClient ID / Issuer
MetadataXML mô tả endpoints, certificatesWell-Known Configuration
NameIDUser identifier trong assertionsub claim
Attribute StatementUser attributes trong assertionClaims trong JWT

2. Tạo SAML 2.0 Client

2.1 Tạo qua Admin Console

  1. Truy cập Admin Console → chọn realm → Clients → Create client

  2. General Settings:

    • Client type: SAML
    • Client ID: URL-based Entity ID, ví dụ https://myapp.example.com/saml/metadata
    • Name: My SAML Application
  3. Click Next và Save

2.2 Import từ Entity Descriptor (Metadata)

Cách nhanh nhất để tạo SAML client — import metadata XML từ Service Provider:

  1. Truy cập Clients → Import client

  2. Upload file metadata XML hoặc paste URL metadata

  3. Keycloak tự động populate: Entity ID, ACS URL, SLO URL, certificates, bindings

Ví dụ metadata XML của Service Provider:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
    entityID="https://myapp.example.com/saml/metadata">
  <md:SPSSODescriptor
      AuthnRequestsSigned="true"
      WantAssertionsSigned="true"
      protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
&lt;md:KeyDescriptor use="signing"&gt;
  &lt;ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&gt;
    &lt;ds:X509Data&gt;
      &lt;ds:X509Certificate&gt;MIICzDCCAbSg...&lt;/ds:X509Certificate&gt;
    &lt;/ds:X509Data&gt;
  &lt;/ds:KeyInfo&gt;
&lt;/md:KeyDescriptor&gt;

&lt;md:KeyDescriptor use="encryption"&gt;
  &lt;ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&gt;
    &lt;ds:X509Data&gt;
      &lt;ds:X509Certificate&gt;MIICzDCCAbSg...&lt;/ds:X509Certificate&gt;
    &lt;/ds:X509Data&gt;
  &lt;/ds:KeyInfo&gt;
&lt;/md:KeyDescriptor&gt;

&lt;md:SingleLogoutService
    Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Location="https://myapp.example.com/saml/slo"/&gt;

&lt;md:NameIDFormat&gt;
  urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
&lt;/md:NameIDFormat&gt;

&lt;md:AssertionConsumerService
    Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
    Location="https://myapp.example.com/saml/acs"
    index="0"
    isDefault="true"/&gt;

</md:SPSSODescriptor> </md:EntityDescriptor>

2.3 Lấy Keycloak IdP Metadata

Service Provider cần metadata của Keycloak (IdP) để cấu hình. Metadata URL:

GET https://<keycloak-host>/realms/<realm-name>/protocol/saml/descriptor

Metadata bao gồm: Entity ID, SSO endpoints, SLO endpoints, signing/encryption certificates.

3. SAML Client Settings chi tiết

3.1 Tab Settings

SettingMô tảGiá trị khuyến nghị
Client ID (Entity ID)SAML Entity ID — unique identifier cho SPURL format: https://app.example.com/saml
NameTên hiển thịTên ứng dụng
Client Signature RequiredSP phải ký AuthnRequestON (production)
Force POST BindingBắt buộc dùng POST binding cho responsesON
Front Channel LogoutLogout qua browser redirectON
Force Name ID FormatBắt buộc Name ID format cụ thểTùy yêu cầu
Name ID FormatFormat of NameIDemail hoặc persistent
Include AuthnStatementBao gồm AuthnStatement trong assertionON
Sign DocumentsKý toàn bộ SAML responseON
Sign AssertionsKý assertion bên trong responseON (khuyến nghị)

3.2 SAML Bindings

SAML hỗ trợ nhiều binding — cách thức truyền tải SAML messages giữa SP và IdP:

BindingMô tảUse case
HTTP-POSTMessage gửi qua HTML form auto-submitDefault cho assertions (lớn)
HTTP-RedirectMessage gửi qua URL query parameterAuthnRequest (nhỏ)
ArtifactChỉ gửi artifact reference, SP lấy assertion qua backchannelHigh-security, large assertions

Cấu hình Bindings trong client settings:

SettingMô tả
Master SAML Processing URLURL chung cho tất cả SAML bindings
Assertion Consumer Service POST Binding URLACS URL cho POST binding
Assertion Consumer Service Redirect Binding URLACS URL cho Redirect binding
Assertion Consumer Service Artifact Binding URLACS URL cho Artifact binding
Logout Service POST Binding URLSLO URL cho POST binding
Logout Service Redirect Binding URLSLO URL cho Redirect binding
Logout Service Artifact Binding URLSLO URL cho Artifact binding
# Ví dụ cấu hình bindings
Master SAML Processing URL: https://myapp.example.com/saml
Assertion Consumer Service POST Binding URL: https://myapp.example.com/saml/acs
Logout Service POST Binding URL: https://myapp.example.com/saml/slo

Artifact Binding chi tiết:

Artifact binding khác biệt so với POST/Redirect — thay vì gửi toàn bộ assertion qua browser, Keycloak chỉ gửi một artifact (reference ID). SP sau đó gọi trực tiếp (backchannel) đến Keycloak để lấy actual assertion.

┌──────────┐     ┌──────────┐     ┌──────────┐
│  Browser │     │    SP    │     │ Keycloak │
└────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │
     │  1. Login      │                │
     │───────────────>│                │
     │  2. AuthnRequest               │
     │<──────────────────────────────>│
     │  3. Authentication              │
     │<──────────────────────────────>│
     │  4. Artifact (POST/Redirect)   │
     │<──────────────────────────────│
     │───────────────>│                │
     │                │ 5. ArtifactResolve (backchannel SOAP)
     │                │───────────────>│
     │                │ 6. ArtifactResponse (assertion)
     │                │<──────────────│
     │  7. Authenticated               │
     │<───────────────│                │

Artifact binding an toàn hơn vì assertion không đi qua browser — hữu ích khi assertion chứa sensitive data.

3.3 XML Signature và Encryption

Signing Configuration:

SettingMô tả
Signature AlgorithmAlgorithm ký XML: RSA_SHA256 (khuyến nghị), RSA_SHA512, DSA_SHA1
SAML Signature Key NameKey name trong signature: KEY_ID, CERT_SUBJECT, NONE
Canonicalization MethodXML canonicalization: EXCLUSIVE (khuyến nghị)

Encryption Configuration:

Bật Encrypt Assertions để mã hóa assertion — chỉ SP với private key tương ứng mới giải mã được:

  • Upload SP's encryption certificate trong tab Keys

  • Encryption Algorithm: AES128, AES256 (khuyến nghị)

# Keycloak sẽ mã hóa assertion bằng SP's public key
# Flow: Sign assertion → Encrypt signed assertion → Send to SP
# SP: Decrypt assertion → Verify signature → Extract user info

3.4 Tab Keys

Quản lý certificates cho SAML client:

  • Signing Key: Certificate mà SP dùng để ký AuthnRequest — Keycloak dùng để verify

  • Encryption Key: Certificate mà Keycloak dùng để encrypt assertions — SP dùng private key để decrypt

Import certificate từ file PEM, JKS, hoặc PKCS12:

# Generate self-signed certificate cho SP
openssl req -x509 -newkey rsa:2048 \
  -keyout sp-private.pem -out sp-certificate.pem \
  -days 365 -nodes \
  -subj "/CN=myapp.example.com"

Import sp-certificate.pem vào Keycloak client Keys tab

4. SAML Assertions Configuration

4.1 Name ID Format

Name ID xác định cách Keycloak gửi user identifier trong assertion:

FormatMô tảUse case
urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddressEmail addressPhổ biến nhất
urn:oasis:names:tc:SAML:2.0:nameid-format:persistentID persistent duy nhất cho mỗi SPKhông muốn reveal email
urn:oasis:names:tc:SAML:2.0:nameid-format:transientID tạm thời, thay đổi mỗi sessionPrivacy-sensitive
urn:oasis:names:tc:SAML:1.1:nameid-format:unspecifiedUsername hoặc Keycloak user IDLinh hoạt

4.2 Assertion Lifespan

Cấu hình trong Realm Settings → Tokens tab:

  • Assertion Lifespan: Thời gian assertion hợp lệ (mặc định 5 phút, khuyến nghị giữ ngắn)

  • Not Before: Assertion không hợp lệ trước thời điểm này (clock skew tolerance)

4.3 Ví dụ SAML Assertion

<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
    ID="_abc123" IssueInstant="2026-03-30T10:00:00Z" Version="2.0">
  <saml:Issuer>http://localhost:8080/realms/my-company</saml:Issuer>

<!-- Subject — user identity --> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"> [email protected] </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2026-03-30T10:05:00Z" Recipient="https://myapp.example.com/saml/acs"/> </saml:SubjectConfirmation> </saml:Subject>

<!-- Conditions — khi nào assertion hợp lệ --> <saml:Conditions NotBefore="2026-03-30T10:00:00Z" NotOnOrAfter="2026-03-30T10:05:00Z"> <saml:AudienceRestriction> <saml:Audience>https://myapp.example.com/saml/metadata&lt;/saml:Audience> </saml:AudienceRestriction> </saml:Conditions>

<!-- AuthnStatement — thông tin xác thực --> <saml:AuthnStatement AuthnInstant="2026-03-30T10:00:00Z" SessionIndex="session_abc123"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement>

<!-- AttributeStatement — user attributes --> <saml:AttributeStatement> <saml:Attribute Name="email"> <saml:AttributeValue>[email protected]</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="firstName"> <saml:AttributeValue>John</saml:AttributeValue> </saml:Attribute> <saml:Attribute Name="Role"> <saml:AttributeValue>admin</saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement> </saml:Assertion>

5. IDP-Initiated Login (Unsolicited Response)

Trong flow bình thường (SP-Initiated), user truy cập SP → SP redirect đến IdP → IdP xác thực → redirect về SP. Với IDP-Initiated Login, user bắt đầu từ IdP (Keycloak) mà không cần qua SP trước.

Cấu hình IDP-Initiated Login

  1. Mở SAML Client → tab Advanced

  2. Tìm IDP-Initiated SSO URL name: nhập tên URL, ví dụ my-app

  3. URL để IDP-Initiated Login sẽ là:

https://<keycloak-host>/realms/<realm>/protocol/saml/clients/my-app

Lưu ý bảo mật: IDP-Initiated Login tiềm ẩn rủi ro CSRF — assertion không có InResponseTo attribute. Chỉ sử dụng khi SP yêu cầu (một số SaaS apps chỉ hỗ trợ IDP-Initiated).

Các settings cho IDP-Initiated

SettingMô tả
IDP-Initiated SSO URL namePhần cuối URL cho IDP-Initiated Login
IDP-Initiated SSO Relay StateDefault RelayState gửi đến SP
Assertion Consumer Service POST Binding URLURL SP nhận assertion

6. Protocol Mappers

Protocol Mappers quyết định thông tin nào được đưa vào tokens/assertions. Chúng biến đổi user attributes, roles, và metadata thành claims (OIDC) hoặc attributes (SAML).

6.1 Khái niệm cơ bản

Protocol Mappers có thể được thêm ở hai cấp:

  • Client level: Mappers áp dụng riêng cho client đó (Client → Client scopes → Dedicated scope)

  • Client Scope level: Mappers áp dụng cho tất cả clients sử dụng scope đó

Mỗi mapper có các cấu hình chung:

SettingMô tả
NameTên mapper (dùng để quản lý)
Mapper TypeLoại mapper (User Attribute, Hardcoded Claim,...)
Add to ID tokenThêm vào ID Token (OIDC)
Add to access tokenThêm vào Access Token (OIDC)
Add to userinfoThêm vào UserInfo response (OIDC)
Add to token introspectionThêm vào Token Introspection response
Add to lightweight access tokenThêm vào Lightweight Access Token

6.2 OIDC Protocol Mappers

User Attribute Mapper — Map user attribute sang token claim:

Mapper Type: User Attribute
Name: department-mapper
User Attribute: department         # attribute name trong User Profile
Token Claim Name: department       # claim name trong JWT
Claim JSON Type: String            # String, long, int, boolean, JSON
Add to ID token: ON
Add to access token: ON
Add to userinfo: ON
Multivalued: OFF

Kết quả trong JWT:

{
  "sub": "user-id",
  "email": "[email protected]",
  "department": "Engineering",
  ...
}

User Property Mapper — Map built-in user property (username, email, firstName, lastName):

Mapper Type: User Property
Name: full-name-mapper
Property: firstName
Token Claim Name: given_name
Claim JSON Type: String

User Session Note Mapper — Map session data vào token:

Mapper Type: User Session Note
Name: client-ip-mapper
User Session Note: clientAddress    # hoặc clientHost, identity_provider, etc.
Token Claim Name: client_ip
Claim JSON Type: String
Add to access token: ON

Session notes có sẵn: clientAddress, clientHost, identity_provider, identity_provider_identity.

Hardcoded Claim Mapper — Thêm claim với giá trị cố định:

Mapper Type: Hardcoded claim
Name: environment-mapper
Token Claim Name: env
Claim value: production
Claim JSON Type: String
Add to access token: ON

Group Membership Mapper — Thêm danh sách groups của user vào token:

Mapper Type: Group Membership
Name: groups-mapper
Token Claim Name: groups
Full group path: ON                 # /parent/child hoặc chỉ child
Add to ID token: ON
Add to access token: ON

Kết quả:

{
  "groups": ["/Engineering", "/Engineering/Backend"]
}

Audience Mapper — Thêm audience vào access token:

Mapper Type: Audience
Name: api-audience
Included Client Audience: my-api-service   # Client ID của resource server
Add to access token: ON

Kết quả:

{
  "aud": ["my-api-service", "account"]
}

Script Mapper — Custom logic bằng JavaScript:

Mapper Type: Script Mapper
Name: custom-role-mapper
Script:
  // Combine realm roles và client roles thành flat list
  var roles = [];

// Realm roles var realmRoles = user.getRealmRoleMappingsStream(); realmRoles.forEach(function(role) { roles.push(role.getName()); });

// Client roles cho client cụ thể var client = keycloakSession.clients() .getClientByClientId(realm, 'my-app'); if (client) { var clientRoles = user.getClientRoleMappingsStream(client); clientRoles.forEach(function(role) { roles.push('client:' + role.getName()); }); }

exports = Java.to(roles, "java.lang.String[]");

Token Claim Name: all_roles Claim JSON Type: JSON Multivalued: ON

Lưu ý: Script Mapper sử dụng Nashorn JavaScript engine. Trong Keycloak 24+, cần deploy script mappers dưới dạng custom JAR provider thay vì inline script. Xem Deploy Scripts trong tài liệu Keycloak.

6.3 SAML Protocol Mappers

SAML mappers tương tự OIDC nhưng output là SAML Attribute thay vì JWT claim:

User Attribute Mapper (SAML):

Mapper Type: User Attribute
Name: department-saml
User Attribute: department
Friendly Name: Department
SAML Attribute Name: urn:oid:2.16.840.1.113730.3.1.241  # hoặc friendly name
SAML Attribute NameFormat: URI Reference                  # URI, Basic, Unspecified

Role List Mapper (SAML):

Mapper Type: Role list
Name: role-list
Role attribute name: Role
Friendly Name: Roles
SAML Attribute NameFormat: Basic
Single Role Attribute: ON    # Tất cả roles trong 1 attribute (khuyến nghị)
                              # OFF = mỗi role 1 attribute riêng

Hardcoded Attribute Mapper (SAML):

Mapper Type: Hardcoded attribute
Name: tenant-id
SAML Attribute Name: tenant_id
SAML Attribute Value: my-company
Friendly Name: Tenant ID
SAML Attribute NameFormat: Basic

Các SAML Attribute NameFormat:

FormatMô tảVí dụ
BasicTên đơn giảnemail, firstName
URI ReferenceOID format, tiêu chuẩnurn:oid:0.9.2342.19200300.100.1.3
UnspecifiedKhông xác định formatTùy ý

7. Lightweight Access Tokens

Mặc định, Keycloak access tokens chứa rất nhiều claims (realm_access, resource_access, email, name, preferred_username,...). Lightweight Access Tokens giảm kích thước token bằng cách chỉ giữ lại claims thiết yếu.

7.1 Tại sao cần Lightweight Access Tokens?

  • Giảm bandwidth: Token nhỏ hơn = gửi qua HTTP header nhanh hơn

  • Giảm thông tin nhạy cảm: Access token thường được gửi đến nhiều services, không nên chứa quá nhiều PII

  • Cải thiện security: Resource server sử dụng Token Introspection để lấy full claims khi cần

7.2 Cấu hình Lightweight Access Tokens

Mặc định, Protocol Mappers có option Add to lightweight access token. Để sử dụng:

  1. Với mỗi mapper, tắt Add to access token ở những claims không cần trong lightweight token

  2. Sử dụng Client Policy (xem bài sau) để enforce lightweight tokens cho clients cụ thể

  3. Resource server gọi Token Introspection endpoint để lấy full claims:

# Token Introspection — lấy full claims
POST /realms/my-company/protocol/openid-connect/token/introspect
Content-Type: application/x-www-form-urlencoded

token=ACCESS_TOKEN&
client_id=my-resource-server&
client_secret=CLIENT_SECRET

# Response chứa full claims
{
  "active": true,
  "sub": "user-id",
  "email": "[email protected]",
  "realm_access": { "roles": ["admin", "user"] },
  "resource_access": { ... },
  ...
}

8. Pairwise Subject Identifier

Theo mặc định, Keycloak sử dụng public subject identifier — giá trị sub claim giống nhau cho tất cả clients. Điều này cho phép các clients liên kết (correlate) user across services.

Pairwise subject identifier tạo sub khác nhau cho mỗi client — ngăn chặn cross-service user tracking.

8.1 Cấu hình Pairwise Identifier

  1. Thêm Protocol Mapper loại Pairwise subject identifier vào client hoặc client scope

  2. Cấu hình:

Mapper Type: Pairwise subject identifier
Name: pairwise-sub
Salt: random-salt-value-keep-secret   # Salt dùng để hash, PHẢI giữ bí mật
Pairwise Subject Identifier Algorithm: SHA-256
Sector Identifier URI: (tùy chọn)     # Nhóm clients share cùng sub

Kết quả:

# Client A nhận sub:
{ "sub": "hashed-value-for-client-a" }

Client B nhận sub khác:

{ "sub": "hashed-value-for-client-b" }

Cùng 1 user nhưng sub khác nhau → không thể correlate

Sector Identifier URI:

Nếu bạn muốn một nhóm clients chia sẻ cùng sub (ví dụ: web app và mobile app của cùng service), sử dụng Sector Identifier URI. URI này trỏ đến JSON array chứa redirect URIs của các clients trong cùng sector:

# https://myservice.example.com/sector-identifier.json
["https://webapp.example.com/callback", "myapp://callback"]

9. Tích hợp SAML với Spring Boot

Sử dụng spring-security-saml2-service-provider để tích hợp SAML SP:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-saml2-service-provider</artifactId>
</dependency>
# application.yml
spring:
  security:
    saml2:
      relyingparty:
        registration:
          keycloak:
            entity-id: https://myapp.example.com/saml/metadata
            signing:
              credentials:
                - private-key-location: classpath:credentials/sp-private.pem
                  certificate-location: classpath:credentials/sp-certificate.pem
            assertingparty:
              metadata-uri: http://localhost:8080/realms/my-company/protocol/saml/descriptor
// SecurityConfig.java
@Configuration
@EnableWebSecurity
public class SamlSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .saml2Login(saml2 -> saml2
                .loginPage("/saml2/authenticate/keycloak")
            )
            .saml2Logout(Customizer.withDefaults());
        return http.build();
    }
}

10. Bài tập thực hành

Lab 1: Tạo SAML Client và kiểm tra Assertion

  1. Tạo SAML client với Entity ID https://localhost:8443/saml

  2. Cấu hình ACS URL, Sign Documents, Sign Assertions = ON

  3. Sử dụng samltool.com hoặc SAML-tracer browser extension để capture SAML Response

  4. Phân tích SAML Assertion: NameID, AttributeStatement, Conditions, Signature

Lab 2: Protocol Mappers cho OIDC

  1. Tạo user attribute employee_id trong User Profile

  2. Tạo User Attribute Mapper: employee_id → token claim emp_id

  3. Tạo Group Membership Mapper: groups → token claim groups

  4. Tạo Hardcoded Claim: env = staging

  5. Test: Lấy token và verify claims trong jwt.io

Lab 3: Protocol Mappers cho SAML

  1. Tạo SAML User Attribute Mapper cho department

  2. Tạo Role List Mapper với Single Role Attribute = ON

  3. Cấu hình Name ID Format = emailAddress

  4. Capture SAML Response và verify AttributeStatement

Lab 4: Pairwise Subject Identifier

  1. Tạo 2 OIDC clients: app-a và app-b

  2. Thêm Pairwise Subject Identifier mapper vào cả 2 clients với cùng salt

  3. Đăng nhập cùng user vào cả 2 clients

  4. So sánh giá trị sub trong access tokens — phải khác nhau

  5. Cấu hình Sector Identifier URI để 2 clients share cùng sub