Re: Example of logged in user retrieval in REST Controller or Repository

174 views
Skip to first unread message

Jérôme LELEU

unread,
Oct 9, 2018, 2:16:55 AM10/9/18
to ul12...@gmail.com, pac4j...@googlegroups.com
Hi,

If you use a "legacy/migration" library like spring-security-pac4j (Spring Security and pac4j, 2 security libraries bounded together) or buji-pac4j (Shiro and pac4j), the security context of the legacy security framework (Spring Security or Shiro) is populated.

If you use a "standalone" library like spring-webmvc-pac4j (Spring MVC and pac4j, just one security library), you can access the authenticated user via his profiles through the ProfileManager, but you need the HTTP request and response. There is no static method from a helper you can call.

Nonetheless, I think we could do something here as well as make the remote user available at the request level...

Thanks.
Best regards,
Jérôme


On Mon, Oct 8, 2018 at 8:14 PM Urban Leben <ul12...@gmail.com> wrote:
Hi,

I have followed the guides and successfully connected pac4j with AD FS SAML in Spring Boot.

I have also seen the demo files located in different repositories such as and the examples with MVC.


What I can't seem to figure out is if it's possible to retrieve a logged in user in a Spring REST Controller or in a Spring Repository where we don't receive HttpServletRequest and HttpServletResponse.

I'm trying to achieve something in a way it is done with Spring Security.

Example:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String currentPrincipalName = authentication.getName();

Is something like this possible? It would be very grateful if you could send me into the right direction.

Best regards,
Urban.

--
You received this message because you are subscribed to the Google Groups "Pac4j users mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Urban Leben

unread,
Oct 9, 2018, 2:52:12 AM10/9/18
to Pac4j users mailing list
Hi,

Thanks for your answer. I have deleted the original post since I came to very similar conclusions you offered to me and decided on the second one.

That is to use the newer library and intercept a request and store the user information in a similar fashion the old spring-security module stores it on a request level.

If you would have recommendations about this, they would bemore than appreciated.

Best regards,
Urban.

Dne torek, 09. oktober 2018 08.16.55 UTC+2 je oseba Jérôme LELEU napisala:

Bob Rao

unread,
Oct 9, 2018, 3:31:25 AM10/9/18
to Pac4j users mailing list
If you are using Spring Boot, it's pretty easy to get an instance of the request and response. You can simply autowire it in via Spring:

    @Autowired
   
private HttpServletRequest request;

   
@Autowired
   
private HttpServletResponse response;

Alternatively, pass it in the constructor or even in the controller method (which Spring will implicitly autowire).

Spring makes use of its AOP proxies so the `request` methods are always proxied to the current request.

While you can use request/response like this in any Spring DI class, I found it easier to bypass the boilerplate of constructing a context every time. What I've done is create a J2EContext and then a ProfileManager bean so I can easily autowire a context or profilemanager anywhere I want to use them. With @RequestScope, they also make use of the proxy so that particular proxied variable always refers to the current request scope even if the consumer is in a larger scope (session, singleton, etc.).

@Configuration
public class J2EContextConfig {

   
@Autowired
   
private HttpServletRequest request;

   
@Autowired
   
private HttpServletResponse response;
   
   
@Autowired
   
private Config config;
   
   
@Bean
   
@RequestScope
   
public J2EContext getContext() {
       
@SuppressWarnings("unchecked")
        J2EContext context
= new J2EContext(request, response, config.getSessionStore());
       
return context;
   
}

}

@Configuration
public class ProfileManagerConfig extends ProfileManagerFactoryAware<J2EContext> {

   
@Autowired
   
private J2EContext context;
   
   
@Autowired
   
private Config config;
   
   
@Bean
   
@RequestScope
   
public ProfileManager<CommonProfile> getProfileManager() {
       
@SuppressWarnings("unchecked")
       
ProfileManager<CommonProfile> manager = this.getProfileManager(context, config);
       
return manager;
   
}
}

Then I can get a Pac4j profile anywhere:

    @Autowired
   
private ProfileManager<CommonProfile> profileManager;

   
private myMethod() {
       
CommonProfile profile = profileManager.get(true).orElseThrow(() -> {
           
return new SomeException();
       
});

       
String id = profile.getId();
       
// do things

   
}


Regards,
Bob

Jérôme LELEU

unread,
Oct 9, 2018, 6:36:00 AM10/9/18
to Bob Rao, pac4j...@googlegroups.com
Hi Bob,

Thanks for sharing.

This is an interesting proposal: indeed, DI seems to be a more modern solution than static methods.

There is one more thing people ask compared to Spring Security: the @Secured annotation. I'm not a real fan of this kind of annotations where I have the feeling that if I forget to setup something, annotations will be simply ignored and no security at all will be applied, but this is a common request I received.
So should we try to add a @RequireAnyRole annotation or think about some static method?

Thanks.
Best regards,
Jérôme

Jérôme LELEU

unread,
Oct 9, 2018, 11:21:12 AM10/9/18
to Bob Rao, pac4j...@googlegroups.com
Or we may have a third option: some AbstractRestController and AbstractController classes from which all Spring (REST) controllers must inherit to benefit from the following methods: getProfiles, getProfile, requireAnyRole...

Sounds like a good compromise too...

Bob Rao

unread,
Oct 9, 2018, 8:21:56 PM10/9/18
to Pac4j users mailing list
We've had to make a similar decision for our controllers. Considered the abstract/base controller path too, but it didn't seem to offer too many benefits and still had the issue of having to remember to derive from the secured class, and would have been more work to adapt into existing codebases with many controllers.

> I have the feeling that if I forget to setup something, annotations will be simply ignored and no security at all will be applied

We had the same concern. Instead, we've created a custom controller to default all controllers within a specific package to be 'secured' unless otherwise annotated. For a more generic approach, maybe have a mapping of package to security level in properties, much like logging currently has mapping of package to log level. This works for us as we do not have much of a public facing site, therefore >90% of our controllers must be secured.

Also, given that our different login clients require access to different controllers before auth (e.g. forms login needs access to ... the login form and supporting JS/CSS, while SAML login needs access to just the callback controller, so these controllers are annotated as "allow for forms" or "allow for saml") we've had to implement a per-client security annotation. This works for us as we only allow access to one (configured) login client per deployment; other Pac4j users might have different requirements. Currently I've done it by defining a predicate bean alongside every client, and calling that predicate with annotations from the security interceptor.

Regards,
Bob

Bob Rao

unread,
Oct 9, 2018, 8:24:06 PM10/9/18
to Pac4j users mailing list
Sorry, "we've created a custom controller to default all controllers" should be "we've created a custom security interceptor to default all controllers".

Jérôme LELEU

unread,
Oct 10, 2018, 8:49:32 AM10/10/18
to Bob Rao, pac4j...@googlegroups.com
Hi,

Thanks for the feedback.

I decided to start with base controllers: https://github.com/pac4j/spring-webmvc-pac4j/pull/23

I'll see what I can do with annotations later on.

Thanks.
Best regards,
Jérôme



Jérôme LELEU

unread,
Oct 17, 2018, 12:34:45 PM10/17/18
to Bob Rao, pac4j...@googlegroups.com
Hi,

The base controllers were definitely too limited when I tried to migrate a legacy web application so I take your idea (@RequestScope) and created two helpers: the UISecurityHelper and the WSSecurityHelper.

I also created the RequireAnyRole and RequireAllRoles annotations for those who want to go that way.


Any feedback will be appreciated.

Thanks.
Best regards,
Jérôme

Jérôme LELEU

unread,
Oct 22, 2018, 5:12:48 AM10/22/18
to Pac4j users mailing list
Hi,

I finally changed my mind and decided to abandon the helpers to directly inject pac4j components (web context and profile manager), exactly like your original solution.

It's more consistent with other pac4j implementations (J2E).

Thanks.
Best regards,
Jérôme

To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages