We have an application with 3 different user roles as User, Author & Admin. Each access role is having different set of menus and screens.
Issue is even though Menu item is hidden if we capture the admin URL and past it in user login it is opening the page. All action on the page will not work but still we are planning to restrict the page opening as well.
Only way I could see how we can handle is write a condition in each action to validate the access before opening the page. But with this approach we should touch many files, is there any best way to handle this situation.
Our application is written using Spring MVC framework.
Thanks.
You asked:
But with this approach we should touch many files, is there any best
way to handle this situation.
From Spring MVC HandlerInterceptor javadoc:
"Applications can register any number of existing or custom
interceptors for certain groups of handlers, to add common
preprocessing behavior without needing to modify each handler
implementation."
What you may do:
Write a custom HandlerInterceptor which should extend
HandlerInterceptorAdapter.
Override the boolean preHandle() method. This method is invoked just before the handler is invoked. So you can check access of logged in user (maybe from session). You can write a custom response from within this method.
Register the interceptor in your dispatcher-servlet.xml.
For example:
public class AuthInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String uri = request.getRequestURI();
User user = (User) request.getSession().getAttribute("foo"); //for example
if (...) { //check access to this uri, if access fails
response.sendRedirect("/to/some/url");
return false;
}
return true;
}
}
And register this HandlerInterceptor to dispatcher-servlet.xml:
<mvc:interceptors>
<bean class="your.package.AuthInterceptor"/>
</mvc:interceptors>
You can configure this interceptor to be more url-specific. See Spring Reference and Spring javadoc.
Related
I'm implementing some REST services in Spring and need to reject, in some cases, a successful login of a user.
I have implemented my UserDetailsService and programmed the loadUserByUsername(String username) method, but, when a user gets correctly authenticated, I need to do another validation and, if it fails, reject the access.
To do so I have implemented a listener to detect correct authentications:
#Component
public class LoginSuccessListener implements ApplicationListener{
#Autowired
LicenseControlService licenseControlService;
#Override
public void onApplicationEvent(InteractiveAuthenticationSuccessEvent e){
User user = (User)e.getAuthentication().getPrincipal();
//Here I want to reject the access because of whatever logic
}
I need to be sure to apply the logic which might reject the access when the user gets correctly authorized, that's why I need to put the logic when I receive this event.
Is there any way to do that?
Im posting the solution I have adopted in case someone needs the same behaviour:
What I did was, at the class which implements the UserDetailsService, when returning the User class, instantiate it with a false at the enabled property... that returns a 401 to the requester.
I also implemented a CustomAuthenticationEntryPoint which extends BasicAuthenticationEntryPoint, and with an overriden comence method. That method is called whenever Spring is returning an authentication error, so, in this method, I can query the type of the AuthenticationException and decide and modify the returned status according to it.
I have been following #Dave Syers' excellent tutorial on Spring boot and oAuth2
I have been able to create a log in function, so that protected resources need a login to facebook before they can be accessed.
But now I am trying to create a "sign up" page. On stackoverflow, for example, there is an option to sign up with facebook, so your details are sent to Stackoverflow.com from facebook. How can this be performed with oAuth2? I was able to do this with spring-social, but I cannot wrap my head around how to do this with a direct oauth2 approach.
Please help?
The answer was simpler than I expected. All I needed to do was add my custom AuthenticationSuccessHandler to the filter:
All I had to do was add an AuthenticationSuccessHandler handle to the method that returns a Filter ssoFilter()
#Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
private Filter ssoFilter() {
OAuth2ClientAuthenticationProcessingFilter facebookFilter = new OAuth2ClientAuthenticationProcessingFilter("/login/facebook");
OAuth2RestTemplate facebookTemplate = new OAuth2RestTemplate(facebook(), oauth2ClientContext);
facebookFilter.setRestTemplate(facebookTemplate);
facebookFilter.setTokenServices(new UserInfoTokenServices(facebookResource().getUserInfoUri(), facebook().getClientId()));
facebookFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
return facebookFilter;
}
And my CustomAuthenticationSuccessHandler was just a component that extended AuthenticationSuccessHandler
#Component
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
//implementation
}
}
So in my sign up page, I could simply use the same login action, but in the success handler I created the User and stored her in the DB
Make a integrated jwt-oauth2-signup-login is difficult. There are some easy way:
1, to use satellizer-spring-boot, or satellizer.
2,to use spring social.
3, add jwt to spring oauth2 as separate provider:
This is how to do with 3:
I have not use signup+oauth2 yet(Because I like spring social and it can do same function), but in theory it can be done in a very easy and can be done as follow:
First, when user login (Register on facebook will also lead to login page) form facebook, just import the user's information and write the information to user model. It is can be done with a controller and a view.
On front page, it is easy to make user choose to login, or register a new account: As Spring boot support multiple filter and multiple AuthenticationProvider,That means you can use two filters, one for oauth2,and another (jwt local server) filter for local server register.
1,download a standard spring boot jwtFilter.java file and put it in your config directory.
2,Make a controller for register new user.
3, make a /login to return jwt token.
3, make two filter, one for oauth2, one for local jwt.
4, make a Sign up link to /register. and a login tag link to /login.
ps: you can copy all the lines form a standard spring boot jwt project, here is one: https://github.com/mrmodise/senepe
I'm having some trouble regarding the authorization endpoint of my Spring based OAuth2 provider. I need more information from the client than there is currently possible. This is what I want to achieve:
I need the custom parameter in the authentication process later on. Is there any simple way to extend the default parameters with my custom one or do I need to implement a certain class myself?
Did some research on how the authentication endpoint works in the current Spring code. I found that the Authorization Endpoint uses a method named authorize that takes all the parameter that are being set and converts then into an AuthorizationRequest. While looking further into the AuthorizationRequest class I found that it holds a map with extensions that is being filled throughout the authorization process. But it does not seem to get filled with my custom parameter (as shown above). This is in fact by only looking at the code, so I might be wrong.
Would it be a good idea to extend the AuthorizationEndpoint with my custom implementation or is there a better and cleaner way to do this?
Update #1 (07-10-2015)
The place where I'd like to use the custom parameter is in my own implementation of the AuthenticationProvider. I need to information to be available inside the authenticate method of this class.
Update #2 (07-10-2015)
It seems that the AuthorizationProvider gets called before the AuthorizationEndpoint. This means that the custom parameter is obtained after the class where I need it (so that's too late).
Maybe I can get the referral Url by either extending part of the Spring security classes or by obtaining it in the HTML through JavaScript. Is this a good idea or should I use another approach?
So I managed to fix the problem myself by searching some more on Google.
What you need to do is speak to the HttpSessionRequestCache to get the referral URL. This is how I solved it in my own implementation of the AuthenticationProvider
#Component
public class CustomProvider implements AuthenticationProvider {
#Autowired
private HttpServletRequest httpRequest;
#Autowired
private HttpServletResponse httpResponse;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(httpRequest, httpResponse);
logger.info("Referral URL: " + savedRequest.getRedirectUrl());
logger.info("Parameters: " + savedRequest.getParameterMap().keySet().toString());
}
}
This will print out the URL of the request that was called before heading to the login page of spring security. The second log method prints out the parameters that where found in this URL. This question and answer helped me in creating a solution for my problem.
I need to handle user's request any time when he trying to load some page. At this listener i need to make some special checks, and, in result, close or not close user's session. How i should implement this? Looks like a common task, but i'm pretty new to spring and spring security.
I think of a listener as something that observes behaviour but doesn't affect behaviour. Since you mention closing the user's session, this is definitely affecting the user. Therefore, I think you are talking about an interceptor/filter rather than listener.
Spring provides a good interceptor framework for something like this.
However, since you are talking about sessions, this is the domain of spring security. Looks like there is another way to handle session management here: Is it possible to invalidate a spring security session?
Like Lithium said, a filter would supposedly be appropiate to handle the given task. Spring Security uses it's own filter chain (link points to 3.1.x docs), to which you can add your own filters - be careful about the positioning of your filter in the chain, here are some notes on ordering.
Depending on your requirements, such a filter could for example redirect the user to another page than the requested one one stop executing the filter chain - again: positioning in the filter chain is vital.
I think you should try interceptor. Little more details:
Create HandlerInterceptor class
public class RequestInitializeInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//Code to perform database checks
}
}
Define interceptor in servlet-context.xml (ApplicationContext for Servlet) file
<mvc:interceptors>
<mvc:interceptor>
<!-- Update path as per you requirement --!>
<mvc:mapping path="/**"/>
<bean class="com.abc.web.support.RequestInitializeInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
I've wrote a web app with its brave controllers and handler mapping, everything with Spring 3.0 and controller annotations. Now turns out that I need simple and custom autentication. I don't want to use ACEGI for the moment, because I've no time to learn it. I'd like ideally that I could have a routine that gets called before every mapped handler, gets from the HttpSession the userId, checks if he is logged in and the session key and if not redirects to a login page. I've been thinking about an interceptor... the problem is that you have to use HandlerInterceptorAdapter, which has the following method:
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
that won't let me access the HttpSession associated with the request. How do I solve this?
Are you sure? You should be able to obtain the session through request.getSession().