23
23
import stroom .security .common .impl .UserIdentitySessionUtil ;
24
24
import stroom .security .impl .OpenIdManager .RedirectUrl ;
25
25
import stroom .security .openid .api .OpenId ;
26
+ import stroom .util .authentication .HasExpiry ;
26
27
import stroom .util .logging .LambdaLogger ;
27
28
import stroom .util .logging .LambdaLoggerFactory ;
28
29
import stroom .util .logging .LogUtil ;
@@ -136,25 +137,42 @@ private void filter(final HttpServletRequest request,
136
137
chain .doFilter (request , response );
137
138
} else if (isStaticResource (fullPath , servletPath , servletName )) {
138
139
chain .doFilter (request , response );
140
+ } else if (shouldBypassAuthentication (request , fullPath , servletPath , servletName )) {
141
+ LOGGER .debug ("Running as proc user for unauthenticated resource, servletName: {}, " +
142
+ "fullPath: {}, servletPath: {}" , servletName , fullPath , servletPath );
143
+ // Some paths don't need authentication. If that is the case then proceed as proc user.
144
+ securityContext .asProcessingUser (() ->
145
+ process (request , response , chain ));
139
146
} else {
140
- // Api requests that are not from the front-end should have a token.
141
- // Also request from an AWS ALB will have an ALB signed token containing the claims
142
- // Need to do this first, so we get a fresh token from AWS ALB rather than using a stale
143
- // one from session.
144
- Optional <UserIdentity > optUserIdentity = openIdManager .loginWithRequestToken (request );
145
-
146
- // Log current user.
147
- if (LOGGER .isDebugEnabled ()) {
148
- logUserIdentityToDebug (
149
- optUserIdentity , fullPath , "after trying to login with request token" );
150
- }
147
+ // First see if a previous call has placed a userIdentity in session
148
+ Optional <UserIdentity > optUserIdentity = UserIdentitySessionUtil .getUserFromSession (
149
+ SessionUtil .getExistingSession (request ));
150
+ logUserIdentityToDebug (optUserIdentity , fullPath , servletPath , "from session" );
151
+
152
+ // Check if the underlying claims/token have expired. The expiry time of some impls
153
+ // may get refreshed over time, so we may never hit it. When code flow is handled by
154
+ // AWS ALB we will expire, so will just get the latest token from headers which the
155
+ // ALB will be refreshing.
156
+ optUserIdentity = optUserIdentity .map (userIdentity -> {
157
+ if (userIdentity instanceof final HasExpiry hasExpiry ) {
158
+ if (hasExpiry .hasExpired ()) {
159
+ LOGGER .info ("UserIdentity {} has expired, expiry: {}" ,
160
+ userIdentityToString (userIdentity ), hasExpiry .getExpireTime ());
161
+ // Clear the identity, so we have to re-acquire it from headers or code flow
162
+ return null ;
163
+ } else {
164
+ LOGGER .debug (() -> LogUtil .message ("UserIdentity {} expires in {}" ,
165
+ userIdentityToString (userIdentity ), hasExpiry .getTimeTilExpired ()));
166
+ }
167
+ }
168
+ return userIdentity ;
169
+ });
151
170
152
- // If no user from header token, see if we have one in session already.
171
+ // API requests that are not from the front-end should have a token.
172
+ // Also requests from an AWS ALB will have an ALB signed token containing the claims
153
173
if (optUserIdentity .isEmpty ()) {
154
- optUserIdentity = UserIdentitySessionUtil .get (SessionUtil .getExistingSession (request ));
155
- if (LOGGER .isDebugEnabled ()) {
156
- logUserIdentityToDebug (optUserIdentity , fullPath , "from session" );
157
- }
174
+ optUserIdentity = openIdManager .loginWithRequestToken (request );
175
+ logUserIdentityToDebug (optUserIdentity , fullPath , servletPath , "from request token" );
158
176
}
159
177
160
178
if (optUserIdentity .isPresent ()) {
@@ -163,19 +181,20 @@ private void filter(final HttpServletRequest request,
163
181
// Now we have the session make note of the user-agent for logging and sessionListServlet duties
164
182
UserAgentSessionUtil .setUserAgentInSession (request );
165
183
184
+ // If OIDC code flow has been handled by the AWS ALB then the session won't have been
185
+ // created by our code flow code. Thus, ensure we have a session with the user in it
186
+ if (isStroomUIServlet (servletName )) {
187
+ SessionUtil .getOrCreateSession (request , aSession -> {
188
+ LOGGER .info ("Creating session {} for user {}, fullPath: {}, servlet: {}" ,
189
+ aSession .getId (), userIdentity , fullPath , servletName );
190
+ UserIdentitySessionUtil .setUserInSession (aSession , userIdentity );
191
+ });
192
+ }
193
+
166
194
// Now handle the request as this user
167
195
securityContext .asUser (userIdentity , () ->
168
196
process (request , response , chain ));
169
-
170
- } else if (shouldBypassAuthentication (request , fullPath , servletPath , servletName )) {
171
- LOGGER .debug ("Running as proc user for unauthenticated servletName: {}, " +
172
- "fullPath: {}, servletPath: {}" , servletName , fullPath , servletPath );
173
- // Some paths don't need authentication. If that is the case then proceed as proc user.
174
- securityContext .asProcessingUser (() ->
175
- process (request , response , chain ));
176
-
177
- // } else if (isApiRequest(servletPath)) {
178
- } else if (Objects .equals (ResourcePaths .STROOM_SERVLET_NAME , servletName )) {
197
+ } else if (isStroomUIServlet (servletName )) {
179
198
doOpenIdFlow (request , response , fullPath );
180
199
} else {
181
200
// If we couldn't log in with a token or couldn't get a token then error as this is an API call
@@ -187,6 +206,11 @@ private void filter(final HttpServletRequest request,
187
206
}
188
207
}
189
208
209
+ private boolean isStroomUIServlet (final String servletName ) {
210
+ return Objects .equals (ResourcePaths .STROOM_SERVLET_NAME , servletName )
211
+ || Objects .equals (ResourcePaths .SESSION_LIST_SERVLET_NAME , servletName );
212
+ }
213
+
190
214
private void doOpenIdFlow (final HttpServletRequest request ,
191
215
final HttpServletResponse response ,
192
216
final String fullPath ) throws IOException {
@@ -245,20 +269,27 @@ private void doOpenIdFlow(final HttpServletRequest request,
245
269
@ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
246
270
private void logUserIdentityToDebug (final Optional <UserIdentity > optUserIdentity ,
247
271
final String fullPath ,
272
+ final String servletName ,
248
273
final String msg ) {
249
- LOGGER .debug ("User identity ({}): {} path : {}" ,
274
+ LOGGER .debug (() -> LogUtil . message ( "User identity ({}): {}, fullPath: {}, servletName : {}" ,
250
275
msg ,
251
- optUserIdentity .map (
252
- identity -> {
253
- final String id = identity .getDisplayName () != null
254
- ? identity .getSubjectId () + " (" + identity .getDisplayName () + ")"
255
- : identity .getSubjectId ();
256
- return LogUtil .message ("'{}' {}" ,
257
- id ,
258
- identity .getClass ().getSimpleName ());
259
- })
276
+ optUserIdentity .map (this ::userIdentityToString )
260
277
.orElse ("<empty>" ),
261
- fullPath );
278
+ fullPath ,
279
+ servletName ));
280
+ }
281
+
282
+ private String userIdentityToString (final UserIdentity userIdentity ) {
283
+ if (userIdentity == null ) {
284
+ return "" ;
285
+ } else {
286
+ final String id = userIdentity .getDisplayName () != null
287
+ ? userIdentity .getSubjectId () + " (" + userIdentity .getDisplayName () + ")"
288
+ : userIdentity .getSubjectId ();
289
+ return LogUtil .message ("'{}' {}" ,
290
+ id ,
291
+ userIdentity .getClass ().getSimpleName ());
292
+ }
262
293
}
263
294
264
295
private String getPostAuthRedirectUri (final HttpServletRequest request ) {
@@ -298,17 +329,6 @@ private boolean shouldBypassAuthentication(final HttpServletRequest servletReque
298
329
} else {
299
330
shouldBypass = authenticationBypassChecker .isUnauthenticated (servletName , servletPath , fullPath );
300
331
}
301
-
302
- if (LOGGER .isDebugEnabled ()) {
303
- if (shouldBypass ) {
304
- LOGGER .debug ("Bypassing authentication for servletName: {}, fullPath: {}, servletPath: {}" ,
305
- NullSafe .get (
306
- servletRequest .getHttpServletMapping (),
307
- HttpServletMapping ::getServletName ),
308
- fullPath ,
309
- servletPath );
310
- }
311
- }
312
332
return shouldBypass ;
313
333
}
314
334
0 commit comments