0
# Authentication Context
1
2
The authentication context components provide thread-local user identification and authentication details for authorization requests in the CDAP security framework.
3
4
## Core Authentication Interfaces
5
6
### AuthenticationContext
7
8
Interface for determining authentication details in authorization contexts.
9
10
```java { .api }
11
interface AuthenticationContext {
12
/**
13
* Get the Principal making the current authorization request.
14
*
15
* @return the Principal making the authorization request
16
*/
17
Principal getPrincipal();
18
}
19
```
20
21
## Security Request Context
22
23
### SecurityRequestContext
24
25
Thread-local context for maintaining authenticated user information across request processing.
26
27
```java { .api }
28
final class SecurityRequestContext {
29
/**
30
* Get the user ID set on the current thread.
31
*
32
* @return the user ID or null if not set
33
*/
34
@Nullable
35
static String getUserId();
36
37
/**
38
* Get the user IP address set on the current thread.
39
*
40
* @return the user IP or null if not set
41
*/
42
@Nullable
43
static String getUserIP();
44
45
/**
46
* Set the user ID on the current thread.
47
*
48
* @param userIdParam the user ID to set
49
*/
50
static void setUserId(String userIdParam);
51
52
/**
53
* Set the user IP address on the current thread.
54
*
55
* @param userIPParam the user IP to set
56
*/
57
static void setUserIP(String userIPParam);
58
59
/**
60
* Create a Principal for the user set on the current thread.
61
*
62
* @return Principal with USER type for the current thread's user ID
63
*/
64
static Principal toPrincipal();
65
}
66
```
67
68
## Usage Examples
69
70
### Setting Request Context
71
72
```java
73
import co.cask.cdap.security.spi.authentication.SecurityRequestContext;
74
75
// At the beginning of request processing
76
public void handleRequest(HttpServletRequest request) {
77
// Extract user information from request (e.g., JWT token, session, etc.)
78
String userId = extractUserFromToken(request.getHeader("Authorization"));
79
String clientIP = request.getRemoteAddr();
80
81
// Set context for current thread
82
SecurityRequestContext.setUserId(userId);
83
SecurityRequestContext.setUserIP(clientIP);
84
85
try {
86
// Process request - authorization checks can now access user context
87
processBusinessLogic();
88
} finally {
89
// Clean up thread-local variables to prevent memory leaks
90
SecurityRequestContext.setUserId(null);
91
SecurityRequestContext.setUserIP(null);
92
}
93
}
94
```
95
96
### Using Authentication Context in Authorizers
97
98
```java
99
public class CustomAuthorizer extends AbstractAuthorizer {
100
101
@Override
102
public void initialize(AuthorizationContext context) throws Exception {
103
// AuthorizationContext extends AuthenticationContext
104
// You can get the current principal during initialization if needed
105
Principal currentPrincipal = context.getPrincipal();
106
107
// Initialize your authorization backend
108
setupAuthorizationBackend();
109
}
110
111
@Override
112
public void enforce(EntityId entity, Principal principal, Set<Action> actions)
113
throws Exception {
114
// The principal parameter contains the user information
115
// Additional context can be obtained from SecurityRequestContext if needed
116
String userIP = SecurityRequestContext.getUserIP();
117
118
// Log authorization attempt with IP for auditing
119
auditLog.info("Authorization check for user {} from IP {} on entity {} for actions {}",
120
principal.getName(), userIP, entity, actions);
121
122
// Perform authorization logic
123
if (!isAuthorized(entity, principal, actions)) {
124
throw new UnauthorizedException(principal, actions, entity);
125
}
126
}
127
}
128
```
129
130
### Thread-Safe Context Management
131
132
```java
133
public class RequestProcessor {
134
135
public void processMultipleRequests(List<UserRequest> requests) {
136
// Process requests in parallel, each with its own thread context
137
requests.parallelStream().forEach(this::processRequest);
138
}
139
140
private void processRequest(UserRequest request) {
141
// Each thread gets its own SecurityRequestContext
142
SecurityRequestContext.setUserId(request.getUserId());
143
SecurityRequestContext.setUserIP(request.getClientIP());
144
145
try {
146
// Process request - context is isolated per thread
147
Principal principal = SecurityRequestContext.toPrincipal();
148
authorizer.enforce(request.getTargetEntity(), principal, request.getActions());
149
150
// Perform business logic
151
executeBusinessLogic(request);
152
153
} catch (UnauthorizedException e) {
154
handleUnauthorizedAccess(request, e);
155
} finally {
156
// Clean up to prevent memory leaks
157
clearSecurityContext();
158
}
159
}
160
161
private void clearSecurityContext() {
162
SecurityRequestContext.setUserId(null);
163
SecurityRequestContext.setUserIP(null);
164
}
165
}
166
```
167
168
### Integration with Web Filters
169
170
```java
171
public class SecurityContextFilter implements Filter {
172
173
@Override
174
public void doFilter(ServletRequest request, ServletResponse response,
175
FilterChain chain) throws IOException, ServletException {
176
177
HttpServletRequest httpRequest = (HttpServletRequest) request;
178
179
try {
180
// Extract authentication information
181
String authHeader = httpRequest.getHeader("Authorization");
182
if (authHeader != null && authHeader.startsWith("Bearer ")) {
183
String token = authHeader.substring(7);
184
UserInfo userInfo = validateToken(token);
185
186
// Set security context for downstream processing
187
SecurityRequestContext.setUserId(userInfo.getUserId());
188
SecurityRequestContext.setUserIP(httpRequest.getRemoteAddr());
189
}
190
191
// Continue with request processing
192
chain.doFilter(request, response);
193
194
} finally {
195
// Always clean up thread-local state
196
SecurityRequestContext.setUserId(null);
197
SecurityRequestContext.setUserIP(null);
198
}
199
}
200
201
private UserInfo validateToken(String token) {
202
// Token validation logic
203
return jwtValidator.validate(token);
204
}
205
}
206
```
207
208
### Custom Authentication Context Implementation
209
210
```java
211
public class EnhancedAuthenticationContext implements AuthenticationContext {
212
213
@Override
214
public Principal getPrincipal() {
215
// Use SecurityRequestContext to build Principal
216
String userId = SecurityRequestContext.getUserId();
217
if (userId == null) {
218
throw new IllegalStateException("No user context available");
219
}
220
221
return new Principal(userId, Principal.PrincipalType.USER);
222
}
223
224
/**
225
* Additional method for enhanced context information.
226
*/
227
public String getClientIP() {
228
return SecurityRequestContext.getUserIP();
229
}
230
231
/**
232
* Check if the current request has authentication context.
233
*/
234
public boolean hasAuthenticationContext() {
235
return SecurityRequestContext.getUserId() != null;
236
}
237
}
238
```
239
240
## Integration Patterns
241
242
### With Spring Security
243
244
```java
245
@Component
246
public class SpringSecurityContextAdapter {
247
248
public void setSecurityContextFromSpring() {
249
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
250
if (auth != null && auth.isAuthenticated()) {
251
String username = auth.getName();
252
SecurityRequestContext.setUserId(username);
253
254
// Extract IP from request attributes if available
255
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
256
if (attributes instanceof ServletRequestAttributes) {
257
HttpServletRequest request = ((ServletRequestAttributes) attributes).getRequest();
258
SecurityRequestContext.setUserIP(request.getRemoteAddr());
259
}
260
}
261
}
262
263
@PreDestroy
264
public void clearContext() {
265
SecurityRequestContext.setUserId(null);
266
SecurityRequestContext.setUserIP(null);
267
}
268
}
269
```
270
271
### With OAuth/JWT
272
273
```java
274
public class JwtAuthenticationHandler {
275
private final JwtDecoder jwtDecoder;
276
277
public void handleJwtAuthentication(String jwtToken, String clientIP) {
278
try {
279
Jwt jwt = jwtDecoder.decode(jwtToken);
280
281
String userId = jwt.getClaimAsString("sub");
282
String email = jwt.getClaimAsString("email");
283
284
// Use email as user ID if sub is not human-readable
285
SecurityRequestContext.setUserId(email != null ? email : userId);
286
SecurityRequestContext.setUserIP(clientIP);
287
288
} catch (JwtException e) {
289
throw new UnauthorizedException("Invalid JWT token");
290
}
291
}
292
}