Skip to content

Commit b1821cb

Browse files
get-Xsuaa-Token
- MR comments, reworked READMEs
1 parent eeb66b4 commit b1821cb

File tree

3 files changed

+140
-209
lines changed

3 files changed

+140
-209
lines changed

README.md

Lines changed: 20 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,25 @@ using XSUAA-based authorization (scopes, role collections).
132132

133133
#### How Token Exchange Works
134134

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
135+
```
136+
1. Request arrives with Authorization: Bearer <token>
137+
2. Library identifies issuer (IAS vs XSUAA) from token claims
138+
3. Token validated against appropriate identity service
139+
4. [IF IAS token + exchange enabled]
140+
├─ Obtain strong IAS ID token (if access token provided)
141+
├─ Call XSUAA /oauth/token endpoint with JWT bearer grant
142+
└─ Store exchanged XSUAA token in SecurityContext
143+
5. [IF exchange disabled OR XSUAA token]
144+
└─ Use validated token directly
145+
6. The XSUAA token contains the user's roles/scopes as defined in XSUAA
146+
7. Authorization proceeds using familiar XSUAA token attributes
147+
```
142148

143149
If the incoming token is already an XSUAA token, no exchange occurs—it's validated and used directly.
144150

151+
**Failure Handling**: If token exchange fails (network issues, misconfiguration), authentication fails with 401
152+
Unauthorized. No silent fallback occurs since IAS access tokens typically lack scopes needed for authorization.
153+
145154
#### Token Exchange Modes
146155

147156
The [`TokenExchangeMode`](java-security/src/main/java/com/sap/cloud/security/token/TokenExchangeMode.java)enum controls
@@ -168,230 +177,38 @@ The Initial token is still available via the [`SecurityContext.getInitialToken()
168177
2. IAS service binding must include `xsuaa-cross-consumption: true` parameter
169178
3. Ensure XSUAA trusts the IAS identity provider
170179

171-
#### Token Exchange Flow Summary
172-
173-
```
174-
1. Request arrives with Authorization: Bearer <token>
175-
2. Library identifies issuer (IAS vs XSUAA) from token claims
176-
3. Token validated against appropriate identity service
177-
4. [IF IAS token + exchange enabled]
178-
├─ Obtain strong IAS ID token (if access token provided)
179-
├─ Call XSUAA /oauth/token endpoint with JWT bearer grant
180-
└─ Store exchanged XSUAA token in SecurityContext
181-
5. [IF exchange disabled OR XSUAA token]
182-
└─ Use validated token directly
183-
6. Request proceeds with authenticated security context
184-
```
185-
186-
**Failure Handling**: If token exchange fails (network issues, misconfiguration), authentication fails with 401
187-
Unauthorized. No silent fallback occurs since IAS access tokens typically lack scopes needed for authorization.
188-
189180
#### 2.4.1 Jakarta Example: Using [`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java)
190181

191182
For Jakarta EE applications, use [
192183
`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java) in
193-
a servlet filter:
194-
195-
**Setup Requirements**:
196-
197-
- IAS and XSUAA service configurations ([
198-
`OAuth2ServiceConfiguration`](java-api/src/main/java/com/sap/cloud/security/config/OAuth2ServiceConfiguration.java))
199-
- HTTP client for token exchange (`CloseableHttpClient` via [
200-
`HttpClientFactory`](token-client/src/main/java/com/sap/cloud/security/client/HttpClientFactory.java))
201-
- Chosen [`TokenExchangeMode`](java-security/src/main/java/com/sap/cloud/security/token/TokenExchangeMode.java)
202-
203-
**Configuration Example**:
204-
205-
```java
206-
// 1. Load service configurations from environment
207-
// OAuth2ServiceConfiguration iasConfig = // obtain from environment bindings
208-
// OAuth2ServiceConfiguration xsuaaConfig = // obtain from environment bindings
209-
210-
// 2. Create HTTP client for JWKS and token exchange
211-
CloseableHttpClient httpClient = HttpClientFactory.create(iasConfig.getClientIdentity());
212-
213-
// 3. Choose token exchange mode
214-
TokenExchangeMode exchangeMode = TokenExchangeMode.FORCE_XSUAA;
215-
216-
// 4. Create authenticator
217-
HybridTokenAuthenticator authenticator =
218-
new HybridTokenAuthenticator(iasConfig, httpClient, xsuaaConfig, exchangeMode);
219-
220-
// 5. Use in servlet filter
221-
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
222-
throws IOException, ServletException {
223-
224-
TokenAuthenticationResult result = authenticator.validateRequest(request, response);
184+
a servlet filter.
225185

226-
if (result.isAuthenticated()) {
227-
// In FORCE_XSUAA mode: SecurityContext.getToken() returns XSUAA token
228-
// In PROVIDE_XSUAA mode: SecurityContext.getToken() returns IAS token
229-
// SecurityContext.getXsuaaToken() returns exchanged XSUAA token
230-
231-
chain.doFilter(request, response);
232-
} else {
233-
((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
234-
}
235-
}
236-
```
237-
238-
**Key Classes**:
239-
240-
- [
241-
`HybridTokenAuthenticator`](java-security/src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java)
242-
Main authenticator
243-
- [`SecurityContext`](java-api/src/main/java/com/sap/cloud/security/token/SecurityContext.java) — Access tokens and
244-
certificates
245-
- [
246-
`TokenAuthenticationResult`](java-security/src/main/java/com/sap/cloud/security/servlet/TokenAuthenticatorResult.java)
247-
Authentication result
186+
For more information, see the [HybridTokenAuthenticator Javadoc](java-security/README.md#hybridtokenauthenticator-usage).
248187

249188
#### 2.4.2 Spring Boot Example: Using [`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
250189

251190
For Spring Boot applications, [
252191
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
253192
automatically configures hybrid authentication when both IAS and XSUAA bindings are detected.
254193

255-
**Enable Token Exchange via Configuration**:
256-
257-
```yaml
258-
# application.yml
259-
sap:
260-
spring:
261-
security:
262-
hybrid:
263-
token:
264-
exchange:
265-
mode: provide_xsuaa # Options: disabled, provide_xsuaa, force_xsuaa (default: disabled)
266-
```
267-
268-
**Spring Security Configuration**:
269-
270-
```java
271-
272-
@EnableWebSecurity
273-
public class SecurityConfig {
274-
275-
@Override
276-
protected void configure(HttpSecurity http) throws Exception {
277-
http.oauth2ResourceServer(oauth2 -> oauth2.jwt());
278-
// Uses auto-configured HybridJwtDecoder
279-
}
280-
}
281-
```
282-
283-
**How It Works**:
284-
285-
1. [
286-
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
287-
detects IAS + XSUAA bindings
288-
2. Creates [
289-
`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
290-
bean with configured mode
291-
3. Registers [`IdTokenExtension`](java-api/src/main/java/com/sap/cloud/security/token/IdTokenExtension.java) and [
292-
`XsuaaTokenExtension`](java-api/src/main/java/com/sap/cloud/security/token/XsuaaTokenExtension.java) in [
293-
`SecurityContext`](java-api/src/main/java/com/sap/cloud/security/token/SecurityContext.java)
294-
4. Spring Security uses decoder for all JWT validation
295-
296-
**Access Tokens in Application Code**:
297-
298-
```java
299-
300-
@RestController
301-
public class ApiController {
302-
303-
@GetMapping("/api/resource")
304-
public String getResource(@AuthenticationPrincipal Jwt jwt) {
305-
// In FORCE_XSUAA mode: jwt is XSUAA token
306-
// In PROVIDE_XSUAA mode: jwt is IAS token
307-
308-
Token xsuaaToken = SecurityContext.getXsuaaToken(); // Always available if exchange enabled
309-
List<String> scopes = xsuaaToken.getClaimAsStringList("scope");
310-
311-
return "Resource accessed";
312-
}
313-
}
314-
```
315-
316-
**Key Configuration Properties**:
317-
318-
| Property | Default | Description |
319-
|--------------------------------------------------|------------|-----------------------------------------------------------------|
320-
| `sap.spring.security.hybrid.auto` | `true` | Enable/disable hybrid auto-configuration |
321-
| `sap.spring.security.hybrid.token.exchange.mode` | `disabled` | Token exchange mode: `disabled`, `provide_xsuaa`, `force_xsuaa` |
322-
323-
**Key Classes**:
324-
325-
- [
326-
`HybridJwtDecoder`](spring-security/src/main/java/com/sap/cloud/security/spring/token/authentication/HybridJwtDecoder.java)
327-
JWT decoder with exchange logic
328-
- [
329-
`HybridIdentityServicesAutoConfiguration`](spring-security/src/main/java/com/sap/cloud/security/spring/autoconfig/HybridIdentityServicesAutoConfiguration.java)
330-
Auto-configuration
331-
- [
332-
`DefaultIdTokenExtension`](java-security/src/main/java/com/sap/cloud/security/token/DefaultIdTokenExtension.java)
333-
ID token resolution
334-
- [
335-
`DefaultXsuaaTokenExtension`](token-client/src/main/java/com/sap/cloud/security/xsuaa/client/DefaultXsuaaTokenExtension.java)
336-
XSUAA token exchange
194+
For more information, see the [HybridJwtDecoder Javadoc](spring-security/README.md#token-exchange-configuration).
337195

338196
#### Important Constraints
339197

340198
**IAS User Tokens Only**: Token exchange only applies to end-user tokens from IAS. Client credentials tokens are **not**
341199
exchanged. Attempting exchange on technical tokens will result in errors.
342200

343-
**Service Binding Configuration**:
344-
345-
- Cloud Foundry: IAS binding must include `"xsuaa-cross-consumption": true`
346-
- Kubernetes/Kyma: Ensure XSUAA trusts IAS as identity provider
347-
348-
**Failure Behavior**: Exchange failures result in 401 Unauthorized responses. There is no silent fallback to avoid
349-
security issues.
350-
351201
**Performance**: Exchanged tokens are cached per request and reused until expiration. Caching is automatic and requires
352202
no configuration.
353203

354-
#### Migration Strategy
355-
356-
**Phase 1 - Enable Hybrid Auth**:
357-
358-
```yaml
359-
mode: provide_xsuaa # Keep XSUAA for authorization, start accepting IAS tokens
360-
```
361-
362-
**Phase 2 - Gradual Migration**:
363-
364-
- Migrate roles/authorization to IAS/Attribute Management Service
365-
- Access both tokens via `SecurityContext`
366-
- Begin using IAS token attributes for new features
367-
368-
**Phase 3 - Complete Migration**:
369-
370-
```yaml
371-
mode: disabled # Remove exchange, operate solely with IAS
372-
```
373-
374-
- Remove XSUAA binding
375-
- Use IAS tokens exclusively
376-
377204
#### Troubleshooting
378205

379206
Common issues and solutions:
380207

381208
| Issue | Cause | Solution |
382209
|-----------------------------------|------------------------------------------------|--------------------------------------------------|
383210
| `Token exchange failed` exception | Missing XSUAA binding or invalid configuration | Verify both IAS and XSUAA service bindings exist |
384-
| Exchange returns 400 | IAS binding missing `xsuaa-cross-consumption` | Add parameter to IAS service binding |
385-
| Exchanged token has no scopes | Role mappings not configured in XSUAA | Configure role collections in XSUAA |
386-
| Memory leak warnings | `SecurityContext` not cleared after request | Call `SecurityContext.clear()` in finally block |
387-
388-
**Enable Debug Logging**:
389-
390-
```yaml
391-
logging:
392-
level:
393-
com.sap.cloud.security: DEBUG
394-
```
211+
| Exchange returns 401 | IAS binding missing `xsuaa-cross-consumption` | Add parameter to IAS service binding |
395212

396213
## Installation
397214
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`:

java-security/README.md

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ Since it requires the Tomcat 10 runtime, it needs to be deployed using the [SAP
4848
- [Maven Dependencies](#maven-dependencies)
4949
2. [Usage](#usage)
5050
- [TokenAuthenticator Usage](#tokenauthenticator-usage)
51+
- [HybridTokenAuthenticator Usage](#hybridtokenauthenticator-usage)
5152
- [OAuth2ServiceServiceConfiguration Usage](#oauth2serviceserviceconfiguration-usage)
5253
- [JwtValidatorBuilder usage](#jwtvalidatorbuilder-usage)
5354
- [Token keys(JWKs) cache](#token-keys--jwks--cache)
@@ -79,11 +80,12 @@ Since it requires the Tomcat 10 runtime, it needs to be deployed using the [SAP
7980
## Usage
8081
### `TokenAuthenticator` usage
8182
The [`TokenAuthenticator`](/java-api/src/main/java/com/sap/cloud/security/servlet/TokenAuthenticator.java) makes it easy to integrate token based authentication into your java application.
82-
The library provides 2 default implementations of `TokenAuthenticator` interface:
83+
The library provides 3 default implementations of `TokenAuthenticator` interface:
8384
- [XsuaaTokenAuthenticator](src/main/java/com/sap/cloud/security/servlet/XsuaaTokenAuthenticator.java) for Xsuaa Access token validation
8485
- [IasTokenAuthenticator](src/main/java/com/sap/cloud/security/servlet/IasTokenAuthenticator.java) for Identity OIDC token validation.
86+
- [HybridTokenAuthenticator](src/main/java/com/sap/cloud/security/servlet/HybridTokenAuthenticator.java) for Identity OIDC token validation with Xsuaa token exchange in hybrid environments.
8587

86-
`XsuaaTokenAuthenticator` and `IasTokenAuthenticator` takes care of
88+
`XsuaaTokenAuthenticator`, `HybridTokenAuthenticator` and `IasTokenAuthenticator` takes care of
8789
* `OAuth2ServiceConfiguration` loading
8890
* `org.apache.http.HttpClient` initialization (it's required for signature validation)
8991
* Jwt Validator setup with help of [`JwtValidatorBuilder`](src/main/java/com/sap/cloud/security/token/validation/validators/JwtValidatorBuilder.java)
@@ -132,6 +134,50 @@ public class XsuaaSecurityFilter implements Filter {
132134
}
133135
```
134136

137+
#### `HybridTokenAuthenticator` usage
138+
139+
The `HybridTokenAuthenticator` is designed for hybrid scenarios where an application needs to validate tokens issued by the Identity service (IAS) and exchange them for tokens issued by the XSUAA service. This is particularly useful when integrating applications that rely on both services for authentication and authorization.
140+
141+
**Setup Requirements**:
142+
143+
- IAS and XSUAA service configurations ([
144+
`OAuth2ServiceConfiguration`](java-api/src/main/java/com/sap/cloud/security/config/OAuth2ServiceConfiguration.java))
145+
- HTTP client for token exchange (`CloseableHttpClient` via [
146+
`HttpClientFactory`](token-client/src/main/java/com/sap/cloud/security/client/HttpClientFactory.java))
147+
- Chosen [`TokenExchangeMode`](java-security/src/main/java/com/sap/cloud/security/token/TokenExchangeMode.java)
148+
149+
**Configuration Example**:
150+
151+
```java
152+
// 1. Load service configurations from environment
153+
OAuth2ServiceConfiguration iasConfig = Environment.getIasConfiguration();
154+
OAuth2ServiceConfiguration xsuaaConfig = Environment.getXsuaaConfiguration();
155+
156+
// 2. Choose token exchange mode
157+
TokenExchangeMode exchangeMode = TokenExchangeMode.FORCE_XSUAA;
158+
159+
// 3. Create authenticator
160+
HybridTokenAuthenticator authenticator =
161+
new HybridTokenAuthenticator(iasConfig, HttpClientFactory.create(iasConfig.getClientIdentity()), xsuaaConfig, exchangeMode);
162+
163+
// 4. Use in servlet filter
164+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
165+
throws IOException, ServletException {
166+
167+
TokenAuthenticationResult result = authenticator.validateRequest(request, response);
168+
169+
if (result.isAuthenticated()) {
170+
// In FORCE_XSUAA mode: SecurityContext.getToken() returns XSUAA token
171+
// In PROVIDE_XSUAA mode: SecurityContext.getToken() returns IAS token
172+
// SecurityContext.getXsuaaToken() returns exchanged XSUAA token
173+
174+
chain.doFilter(request, response);
175+
} else {
176+
((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
177+
}
178+
}
179+
```
180+
135181
### `OAuth2ServiceServiceConfiguration` usage
136182
Access the OAuth2 Service configuration bound to the application:
137183
* For Xsuaa Service

0 commit comments

Comments
 (0)