I'd like to be able to make beans with various security scopes
Use Case 1: Logging inside of an http request/session.
We are finally upgrading to log4j2, and a lot of our previous solutions don't work as is
[INFO ] [2018.06.11 09:11:34] view.NavigationBar - (232BAC300512E17EC18FA1179FD18322:myuser@mydomain.tld) - Viewed Tab: Catalog
which is solved by
@Bean
@RequestScope
static CloseableThreadContext.Instance logSessionData( HttpServletRequest request ) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Map<String,String> map = new HashMap<>( );
map.put( "session", request.getSession( false ).getId() );
if (authentication != null ) {
UserDetails principal = (UserDetails) authentication.getPrincipal();
map.put( "user", principal.getUsername() );
}
return CloseableThreadContext.putAll( map ); // sideeffecty black magic
}
Use Case 2: Logging outside of an http request
[INFO ] [2018.06.14 14:12:29] fileDownload.FileDownloaderService - (:myuser@mydomain.tld) - #-
you'll note this has no session id, that's because it's in another thread that's not used for addressing http requests. There doesn't appear to be a good scope currently to resolve this. What'd I'd like to do is write something like this
@Bean
@Scope("securityContext") is reinstantiated whenever the SecurityContextHolder is changed...
static CloseableThreadContext.Instance logSessionData( UserDetails principal ) {
Map<String,String> map = new HashMap<>( );
map.put( "user", principal.getUsername() );
return CloseableThreadContext.putAll( map ); // sideeffecty black magic
}
Use Case 3: Injecting Users into @Components
being a fan of Dependency Injection/Inversion I honestly don't think services of any kind should know how to retrieve a user.
@Controller
@AuthenticatedScope // only created when a user has authenticated
class MyController {
MyController( @User myUser ) {
...
Now the user must be authenticated in order for this bean to match, otherwise 404 because it can't be created. I would also suggest an @UnauthenticatedScope for being able to provide easy polymorphic behavior when it's not authenticated (instead of writing if then else logic into the controllers).
P.S yes I'm aware theirs an @User request method handler... but I believe that should operate off of a scoped bean. I think that if this were implemented in the long run SecurityContextHolder could become a module private api, instead of exposed to the world.
Comment From: rwinch
The scope of Authentication is not well defined as it can change in the middle of a single request which means it isn't ideal for special scopes. You should prefer using the SecurityContextHolder or injecting the SecurityContextHolderStrategy.