Call a bean AFTER successful spring security login? - spring

If I have spring security working, how can I have it call a bean to initialize all my user data once it has logged in? I can do a Servlet Filter but it calls that on every request. I want to just call some init code to load some user data into the session after the user logs in.

When the user logs in correctly spring security call an instance of AuthenticationSuccessHandler. What you want to do is create your own bean and use that to perform whatever extra actions you want.
Your class would probably look something like this:
public class YourAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//do whatever you want
super.onAuthenticationSuccess(request, response, authentication);
}
}
Also register your class as a spring bean
<beans:bean id="authenticationSuccessHandler"
class="your.package.YourAuthenticationSuccessHandler"/>
and add it to the form login security configuration as the value of authentication-success-handler-ref

Related

Is possible ask for an acces token oauth2 just with refresh token in spring security? without basic authentication?

I would like to know if in spring oauth2 is possible get a new pair tokens (access token and refresh token) just using another refresh token, without the basic authentication (without clientId and clientSecret, is there any way?
For exemple:
WITH BASIC AUTH
curl -u clientId:clientSecret -X POST 'http://myapplication.oauth2/accounts/oauth/token?grant_type=refresh_token&client_id=<CLIENT_ID>&refresh_token=' -v
WITHOUT BASIC AUTH
curl -u -X POST 'http://myapplication.oauth2/accounts/oauth/token?grant_type=refresh_token&client_id=<CLIENT_ID>&refresh_token=' -v
I note that sprint BasicAuthenticationFilter in spring uses validation bellow, maybe override this filter and make the authentication just with refresh token.
String header = request.getHeader("Authorization");
if (header == null || !header.toLowerCase().startsWith("basic ")) {
chain.doFilter(request, response);
return;
}
The short answer is no. The class used to manage the Spring Oauth 2 endpoints is the following one:
#FrameworkEndpoint
public class TokenEndpoint extends AbstractEndpoint
Both requests, I mean, get access token and refresh one use the same endpoint with different parameters. And the method to manage those ones is:
#RequestMapping(
value = {"/oauth/token"},
method = {RequestMethod.POST}
)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, #RequestParam Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException("There is no client authentication. Try adding an appropriate authentication filter.");
} else {
String clientId = this.getClientId(principal);
...
As you can see, a Principal object is required (in this case provided by the Basic Authentication).
Even, if you configure the security of your project to permit that url without checking authentication, you will achieve to "enter" in above method but you will receive an InsufficientAuthenticationException because no Authentication instance has been provided.
Why custom authentication will not work
1. Create a custom AuthenticationProvider will not work because the method postAccessToken is invoked before. So you will receive an InsufficientAuthenticationException.
2. Create a OncePerRequestFilter and configure it to execute before process the current request:
#Override
protected void configure(HttpSecurity http) throws Exception {
http...
.anyRequest().authenticated()
.and()
.addFilterBefore(myCustomFilter, UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(POST, "/accounts/oauth/**");
}
with a code "similar to":
#Component
public class CustomAuthenticationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
...
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken("existingUser",
"passwordOfExistingUser",
Collections.emptyList()));
...
filterChain.doFilter(request, response);
}
The problem with this approach is the principal in TokenEndpoint comes from the HttpServletRequest not from Spring context, as you can see debugging BasicAuthenticationFilter class.
In your custom filter you can try, using reflection, set a value in userPrincipal property but, as you can verify, request has several "internal request properties" and that could be a "too tricky option".
In summary, Oauth standard needs user/pass to access to the resources, if you want to workaround in almost of provided endpoints maybe that project is not what you are looking for.
Workaround to include your own object in Spring Principal
I do not recommend that but if you still want to go ahead with this approach, there is a way to include your own value inside the principal parameter received by TokenEndpoint class.
It is important to take into account BasicAuthorizationFilter will be still executed, however you will be able to override the Spring principal object by your own one.
For this, we can reuse the previous CustomAuthenticationFilter but now your have to include the filters you need, I mean, allowed urls, parameters, etc You are going to "open the doors", so be careful about what you allow and not.
The difference in this case is, instead of add the configuration in our class that extends WebSecurityConfigurerAdapter we are going to do it in:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private CustomAuthenticationFilter customAuthenticationFilter;
...
#Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.checkTokenAccess("isAuthenticated()");
security.addTokenEndpointAuthenticationFilter(customAuthenticationFilter);
}
...

configuring interceptors to perform "pre-tasks" on hitting endpoints in spring based web app

I am required to perform some pre-task whenever few specific endpoints are hit in my spring based web app. I came across the interceptor component provided by the spring-security framework. I searched various forums but didn't find relevant answers for configuring and adding interceptor.
Consider a situation where I am required to set some key=value in a database by sending POST request in the database whenever the user hits following endpoints.
/endpoint1
/endpoint2
/endpoint3
/endpoint4
After completion of the pre-task user should be redirected to the origin endpoint.
How can this be achieved using an interceptor in the spring-security framework?
Spring Security is for security stuff related to Authentification and Authorization. You can trigger some action if somebody logged in, but if you just need to trigger action for each request than Spring Security is not a good place for that (according to business logic), better add just filter. Anyway answering to your question:
The best way is to add custom filter to Spring Security Filter Chain:
You have to overwrite:
#Configuration
public class CustomWebSecurityConfigurerAdapter
extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(
new CustomFilter(), BasicAuthenticationFilter.class);
}
}
and create your custom filter:
public class CustomFilter extends GenericFilterBean {
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//your logic here
chain.doFilter(request, response); //it's needed to pass your request father
}
}
Code taken from baeldung.com see for more information

Spring - Best way to control session creation

I am currently retrieving the session timeout from a database since it should be configurable so I just can't declare it in the web.xml.
In my HttpSessionEventPublisher, I basically retrieve the session object from the HttpSessionEvent and I set the session timeout value that I've retrieved from the database using setMaxInactiveInterval.
Upon investigation, whenever I access a POST url in my site, the HttpSessionEventPublisher is triggered and it creates a new Session object. I would like to control this behavior by only creating a Session object if and only if the user is successfully authenticated (logged in, passing through the AuthenticationProvider)
Is this possible?
The HttpSessionEventPublisher does not create sessions itself. It just translates servlet session events to the equivalent ones of spring security. Actually the creation of sessions is not controlled by spring security, but it can initiate one if needed.
If you just want to set the session timeout only upon authentication, then you may extend the authentication handler you use and set the timeout there.
For example the following code extends SavedRequestAwareAuthenticationSuccessHandler and retrieves the timeout from application properties (instead of database as in your case)
#Component
public class AuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Value("#{appProperties['session.timeout']}")
private int sessionTimeout;
private final Logger logger = LoggerFactory.getLogger(AuthenticationSuccessHandler.class);
#Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse res, Authentication authentication) throws ServletException, IOException {
logger.debug("onAuthenticationSuccess");
HttpSession session = req.getSession();
session.setMaxInactiveInterval(sessionTimeout);
super.onAuthenticationSuccess(req, res, authentication);
}
}

Pulling the userDetails in custom LogoutHandler Spring MVC

In MyLogoutHandler class I do override determineTargetUrl() method, here I am calling MyUserDetials userDetails = (MyUserDetials)userContextManager.getUserDetails(), but userDetails is null.
here is the configuration:
<security:logout
invalidate-session="true"
success-handler-ref="MyLogoutHandler"
logout-url="/auth/logout"/>
I noticed that since invalidate-session="true", it is null? but I like to keep this attribute "true", Can I have any other way to do configure?
My goal is: I need to pull some information from userDetails, to make a webservice call after user clicks logout.
Thank you.
You need create your own LogoutHandler, implement
void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication);
add it implementation to security:logout tag. After get user details from authentication parameter.
I fixed this issue. I created the My Own Handler and did override the:
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {...}
method of *SimpleUrlLogoutSuccessHandler*. Now I am able to get *authentication* object according to my spring configuration.
Thank you.

How to Inject session bean in custom spring security login success handler

i'm unable to inject a spring session bean in my custom success handler:
#Component
public class CustomSavedRequestAwareAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Resource
private SessionController sessionController;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
super.onAuthenticationSuccess(request, response, authentication);
sessionController.setUtenteOnline();
}
that return a null pointer exception on sessionController.
Thank you in advance
Your success handler is probably a singleton so you can only inject singletons into it reliably. You can solve this problem using scoped dependencies. Basically, it involves Spring injecting a singleton dynamic proxy that manages fetching the real bean from session scope and delegating calls to it.

Resources