Skip to content

Commit 10e3f9e

Browse files
get-Xsuaa-Token
- extended readme for new feature
1 parent e5ac1b8 commit 10e3f9e

File tree

1 file changed

+273
-0
lines changed

1 file changed

+273
-0
lines changed

README.md

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ The libraries focus on streamlining [OAuth 2.0](https://oauth.net) access token
1818
- [2.1.2 Spring Boot applications](#212-spring-boot-web-applications)
1919
- [2.2 Token Flows](#22-token-flows-for-token-retrievals)
2020
- [2.3 Testing utilities](#23-testing-utilities)
21+
- [2.4 Token Exchange for Hybrid Authentication](#24-token-exchange-for-hybrid-authentication)
22+
- [2.4.1 Jakarta Example](#241-jakarta-example-using-hybridtokenauthenticator)
23+
- [2.4.2 Spring Boot Example](#242-spring-boot-example-using-hybridjwtdecoder)
2124
3. [Installation](#installation)
2225
4. [Troubleshooting](#troubleshooting)
2326
5. [Common Pitfalls](#common-pitfalls)
@@ -118,6 +121,276 @@ In the table below you'll find links to detailed information.
118121
|-------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
119122
| [java-security-test](/java-security-test) | [Integration test code snippet](/samples/spring-security-hybrid-usage/src/test/java/sample/spring/security/junitjupiter/TestControllerIasTest.java) for Spring application <br/>[Integration test code snippet](/samples/java-security-usage/src/test/java/com/sap/cloud/security/samples/HelloJavaServletIntegrationTest.java) for Jakarta EE web.xml based servlets <br/> [Integration test code snippet](/samples/java-security-usage-ias/src/test/java/com/sap/cloud/security/samples/ias/HelloJavaServletIntegrationTest.java) for Jakarta EE annotation based servlets <br/> |
120123

124+
### 2.4 Token Exchange for Hybrid Authentication
125+
126+
In hybrid authentication setups, your application can accept tokens from both **SAP Identity Authentication Service (
127+
IAS)** and **XSUAA** simultaneously. This approach eases migration from XSUAA to IAS by exchanging IAS user tokens for
128+
XSUAA tokens behind the scenes.
129+
130+
**Goal**: Maintain backward compatibility during migration. Users authenticate via IAS, but the application continues
131+
using XSUAA-based authorization (scopes, role collections).
132+
133+
#### How Token Exchange Works
134+
135+
When a JWT bearer token arrives:
136+
137+
1. The library identifies whether the token was issued by IAS or XSUAA
138+
2. The token is validated using the appropriate validator
139+
3. If the token is from IAS and exchange is enabled, an XSUAA token is obtained via OAuth2 JWT bearer flow
140+
4. The XSUAA token contains the user's roles/scopes as defined in XSUAA
141+
5. Authorization proceeds using familiar XSUAA token attributes
142+
143+
If the incoming token is already an XSUAA token, no exchange occurs—it's validated and used directly.
144+
145+
#### Token Exchange Modes
146+
147+
The [`TokenExchangeMode`](java-security/src/main/java/com/sap/cloud/security/token/TokenExchangeMode.java)enum controls
148+
when
149+
and how IAS tokens are exchanged:
150+
151+
| Mode | Behavior |
152+
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
153+
| **`DISABLED`** | No exchange. Each token type is validated and used as-is. |
154+
| **`PROVIDE_XSUAA`** | IAS token is validated and exchanged for XSUAA, but the IAS token remains primary in the security context. The XSUAA token is accessible via [`SecurityContext.getXsuaaToken()`](java-api/src/main/java/com/sap/cloud/security/token/SecurityContext.java). |
155+
| **`FORCE_XSUAA`** | IAS token is exchanged for XSUAA and the XSUAA token replaces the IAS token in the security context. The application treats all requests as XSUAA-authenticated. |
156+
157+
**Mode Selection Guide**:
158+
159+
- Use **`PROVIDE_XSUAA`** when gradually building IAS-based features while maintaining XSUAA authorization
160+
- Use **`FORCE_XSUAA`** for maximum backward compatibility—your app operates as if it were XSUAA-only
161+
- Use **`DISABLED`** after completing the migration to IAS
162+
163+
#### Prerequisites for Token Exchange
164+
165+
1. Both XSUAA and IAS service bindings must be configured
166+
2. IAS service binding must include `xsuaa-cross-consumption: true` parameter (Cloud Foundry)
167+
3. On Kubernetes/Kyma, ensure XSUAA trusts the IAS identity provider
168+
169+
#### Token Exchange Flow Summary
170+
171+
```
172+
1. Request arrives with Authorization: Bearer <token>
173+
2. Library identifies issuer (IAS vs XSUAA) from token claims
174+
3. Token validated against appropriate identity service
175+
4. [IF IAS token + exchange enabled]
176+
├─ Obtain strong IAS ID token (if access token provided)
177+
├─ Call XSUAA /oauth/token endpoint with JWT bearer grant
178+
└─ Store exchanged XSUAA token in SecurityContext
179+
5. [IF exchange disabled OR XSUAA token]
180+
└─ Use validated token directly
181+
6. Request proceeds with authenticated security context
182+
```
183+
184+
**Failure Handling**: If token exchange fails (network issues, misconfiguration), authentication fails with 401
185+
Unauthorized. No silent fallback occurs since IAS access tokens typically lack scopes needed for authorization.
186+
187+
#### 2.4.1 Jakarta Example: Using [`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java)
188+
189+
For Jakarta EE applications, use [
190+
`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java) in
191+
a servlet filter:
192+
193+
**Setup Requirements**:
194+
195+
- IAS and XSUAA service configurations ([
196+
`OAuth2ServiceConfiguration`](java-api/src/main/java/com/sap/cloud/security/config/OAuth2ServiceConfiguration.java))
197+
- HTTP client for token exchange (`CloseableHttpClient` via [
198+
`HttpClientFactory`](token-client/src/main/java/com/sap/cloud/security/client/HttpClientFactory.java))
199+
- Chosen [`TokenExchangeMode`](java-security/src/main/java/com/sap/cloud/security/token/TokenExchangeMode.java)
200+
201+
**Configuration Example**:
202+
203+
```java
204+
// 1. Load service configurations from environment
205+
// OAuth2ServiceConfiguration iasConfig = // obtain from environment bindings
206+
// OAuth2ServiceConfiguration xsuaaConfig = // obtain from environment bindings
207+
208+
// 2. Create HTTP client for JWKS and token exchange
209+
CloseableHttpClient httpClient = HttpClientFactory.create(iasConfig.getClientIdentity());
210+
211+
// 3. Choose token exchange mode
212+
TokenExchangeMode exchangeMode = TokenExchangeMode.FORCE_XSUAA;
213+
214+
// 4. Create authenticator
215+
HybridTokenAuthenticator authenticator =
216+
new HybridTokenAuthenticator(iasConfig, httpClient, xsuaaConfig, exchangeMode);
217+
218+
// 5. Use in servlet filter
219+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
220+
throws IOException, ServletException {
221+
222+
TokenAuthenticationResult result = authenticator.validateRequest(request, response);
223+
224+
if (result.isAuthenticated()) {
225+
// In FORCE_XSUAA mode: SecurityContext.getToken() returns XSUAA token
226+
// In PROVIDE_XSUAA mode: SecurityContext.getToken() returns IAS token
227+
// SecurityContext.getXsuaaToken() returns exchanged XSUAA token
228+
229+
chain.doFilter(request, response);
230+
} else {
231+
((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
232+
}
233+
}
234+
```
235+
236+
**Key Classes**:
237+
238+
- [
239+
`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java)
240+
Main authenticator
241+
- [`SecurityContext`](java-api/src/main/java/com/sap/cloud/security/token/SecurityContext.java) — Access tokens and
242+
certificates
243+
- [
244+
`TokenAuthenticationResult`](java-security/src/main/java/com/sap/cloud/security/servlet/TokenAuthenticatorResult.java)
245+
Authentication result
246+
247+
#### 2.4.2 Spring Boot Example: Using [`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
248+
249+
For Spring Boot applications, [
250+
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
251+
automatically configures hybrid authentication when both IAS and XSUAA bindings are detected.
252+
253+
**Enable Token Exchange via Configuration**:
254+
255+
```yaml
256+
# application.yml
257+
sap:
258+
spring:
259+
security:
260+
hybrid:
261+
token:
262+
exchange:
263+
mode: provide_xsuaa # Options: disabled, provide_xsuaa, force_xsuaa (default: disabled)
264+
```
265+
266+
**Spring Security Configuration**:
267+
268+
```java
269+
270+
@EnableWebSecurity
271+
public class SecurityConfig {
272+
273+
@Override
274+
protected void configure(HttpSecurity http) throws Exception {
275+
http.oauth2ResourceServer(oauth2 -> oauth2.jwt());
276+
// Uses auto-configured HybridJwtDecoder
277+
}
278+
}
279+
```
280+
281+
**How It Works**:
282+
283+
1. [
284+
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
285+
detects IAS + XSUAA bindings
286+
2. Creates [
287+
`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
288+
bean with configured mode
289+
3. Registers [`IdTokenExtension`](java-api/src/main/java/com/sap/cloud/security/token/IdTokenExtension.java) and [
290+
`XsuaaTokenExtension`](java-api/src/main/java/com/sap/cloud/security/token/XsuaaTokenExtension.java) in [
291+
`SecurityContext`](java-api/src/main/java/com/sap/cloud/security/token/SecurityContext.java)
292+
4. Spring Security uses decoder for all JWT validation
293+
294+
**Access Tokens in Application Code**:
295+
296+
```java
297+
298+
@RestController
299+
public class ApiController {
300+
301+
@GetMapping("/api/resource")
302+
public String getResource(@AuthenticationPrincipal Jwt jwt) {
303+
// In FORCE_XSUAA mode: jwt is XSUAA token
304+
// In PROVIDE_XSUAA mode: jwt is IAS token
305+
306+
Token xsuaaToken = SecurityContext.getXsuaaToken(); // Always available if exchange enabled
307+
List<String> scopes = xsuaaToken.getClaimAsStringList("scope");
308+
309+
return "Resource accessed";
310+
}
311+
}
312+
```
313+
314+
**Key Configuration Properties**:
315+
316+
| Property | Default | Description |
317+
|--------------------------------------------------|------------|-----------------------------------------------------------------|
318+
| `sap.spring.security.hybrid.auto` | `true` | Enable/disable hybrid auto-configuration |
319+
| `sap.spring.security.hybrid.token.exchange.mode` | `disabled` | Token exchange mode: `disabled`, `provide_xsuaa`, `force_xsuaa` |
320+
321+
**Key Classes**:
322+
323+
- [
324+
`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
325+
JWT decoder with exchange logic
326+
- [
327+
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
328+
Auto-configuration
329+
- [
330+
`DefaultIdTokenExtension`](java-security/src/main/java/com/sap/cloud/security/token/DefaultIdTokenExtension.java)
331+
ID token resolution
332+
- [
333+
`DefaultXsuaaTokenExtension`](token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultXsuaaTokenExtension.java)
334+
XSUAA token exchange
335+
336+
#### Important Constraints
337+
338+
**IAS User Tokens Only**: Token exchange only applies to end-user tokens from IAS. Client credentials tokens are **not**
339+
exchanged. Attempting exchange on technical tokens will result in errors.
340+
341+
**Service Binding Configuration**:
342+
343+
- Cloud Foundry: IAS binding must include `"xsuaa-cross-consumption": true`
344+
- Kubernetes/Kyma: Ensure XSUAA trusts IAS as identity provider
345+
346+
**Failure Behavior**: Exchange failures result in 401 Unauthorized responses. There is no silent fallback to avoid
347+
security issues.
348+
349+
**Performance**: Exchanged tokens are cached per request and reused until expiration. Caching is automatic and requires
350+
no configuration.
351+
352+
#### Migration Strategy
353+
354+
**Phase 1 - Enable Hybrid Auth**:
355+
356+
```yaml
357+
mode: provide_xsuaa # Keep XSUAA for authorization, start accepting IAS tokens
358+
```
359+
360+
**Phase 2 - Gradual Migration**:
361+
362+
- Migrate roles/authorization to IAS/Attribute Management Service
363+
- Access both tokens via `SecurityContext`
364+
- Begin using IAS token attributes for new features
365+
366+
**Phase 3 - Complete Migration**:
367+
368+
```yaml
369+
mode: disabled # Remove exchange, operate solely with IAS
370+
```
371+
372+
- Remove XSUAA binding
373+
- Use IAS tokens exclusively
374+
375+
#### Troubleshooting
376+
377+
Common issues and solutions:
378+
379+
| Issue | Cause | Solution |
380+
|-----------------------------------|------------------------------------------------|--------------------------------------------------|
381+
| `Token exchange failed` exception | Missing XSUAA binding or invalid configuration | Verify both IAS and XSUAA service bindings exist |
382+
| Exchange returns 400 | IAS binding missing `xsuaa-cross-consumption` | Add parameter to IAS service binding |
383+
| Exchanged token has no scopes | Role mappings not configured in XSUAA | Configure role collections in XSUAA |
384+
| Memory leak warnings | `SecurityContext` not cleared after request | Call `SecurityContext.clear()` in finally block |
385+
386+
**Enable Debug Logging**:
387+
388+
```yaml
389+
logging:
390+
level:
391+
com.sap.cloud.security: DEBUG
392+
```
393+
121394
## Installation
122395
The SAP Cloud Security Services Integration is published to maven central: https://search.maven.org/search?q=com.sap.cloud.security and is available as a Maven dependency. Add the following BOM to your dependency management in your `pom.xml`:
123396
```xml

0 commit comments

Comments
 (0)