How to exchange deprecated getExtraInformation() in context of UsernamePasswordAuthenticationFilter? - spring

I am upgrading older Spring 2.5 code to Spring 3.0 (as a first step). During this I found the following problem:
The method getExtraInformation() from the type AuthenticationException is deprecated
The point is that this happens in a subclass of UsernamePasswordAuthenticationFilter:
#Override
protected void unsuccessfulAuthentication(final HttpServletRequest req, final HttpServletResponse res, final AuthenticationException authException) throws IOException, ServletException
{
req.setAttribute("exception", authException);
super.unsuccessfulAuthentication(req, res, authException);
if (authException instanceof CredentialsExpiredException)
{
final User user = ((UserDetailsImpl)authException.getExtraInformation()).getUser();
if (user.getCredentials().getUserCannotChange())
{
throw authException;
}
req.setAttribute("user", user);
req.setAttribute("msg", this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.credentialsExpiredPleaseChange"));
}
}
Until now I found no way to get the User in another way. So my question is how to get the user when it is no longer transported via the exceptions extra information?
The point is that the User is required here, because a decision has to be made if the exception is only rethrown or if a message should be presented to the user.
Btw. I have found no code that creates a CredentialsExpiredException with ExtraInformation, so I assume this will be done by the Spring/Spring Security Framework?

I think you have to step back and do this "extra information" check when Spring Security checks if there is CredentialsExpiredException. Assuming you are using the default settings , the CredentialsExpiredException is checked in the postAuthenticationChecks UserDetailsChecker in DaoAuthenticationProvider. The default implementation is DefaultPostAuthenticationChecks which you can override it with yours :
public class MyPostAuthenticationChecks extends DefaultPostAuthenticationChecks {
public void check(UserDetails user) {
UserDetailsImpl userImpl = (UserDetailsImpl)user;
if (user.getCredentials().getUserCannotChange()){
throw new CredentialsExpiredException("Some customized error message blalblbal");
}else{
super.check(user);
}
}
}

Related

Spring-security - invalid login always return 403 instead of appropriate errors

I am trying to input some more "accurate" error handling for invalid logins.
The three main objectives: invalid password, account disabled, invalid email.
The current calling hierarchy is the following:
Attempted login requests
#Override // THIS OVERRIDES THE DEFAULT SPRING SECURITY IMPLEMENTATION
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String email = request.getParameter("email");
String password = request.getParameter("password");
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(email, password);
return authManager.authenticate(authToken);
}
This calls another override method where I tried to insert error handling because it has access to the userRepo and object. The issue here is if the AccountLockedException or fails on email finding or password verification, it will always reutrn a 403 and no indication of the thrown exception.
#SneakyThrows
#Override // THIS OVERWRITES THE DEFAULT SPRING SECURITY ONE
public UserDetails loadUserByUsername(String email){
User user = findUserByEmail(email);
if ( user != null){
if (user.isEnabled()){
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
user.getRoles().forEach(role -> { authorities.add(new SimpleGrantedAuthority(role.getName()));});
sucessfulLogin(user);
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), authorities);
}
else { throw new AccountLockedException("Account disabled"); }
}
}
However, what I have found this previous method on throwing will call this additional override method (in the same class as the attempted authentication)
#Override // DO SOMETHING WITH THIS TO PREVENT BRUTE FORCE ATTACKS WITH LIMITED NUMBER OF ATTEMPTS IN A TIME-FRAME
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
System.out.println("aaa");
super.unsuccessfulAuthentication(request, response, failed);
}
Though, at this point it will display the following:
this option gets shown when the password is incorrect.
this option gets shown when the account is disabeld.
this option gets shown when the email is incorrect.
My question is. Firstly how do I appropriately distinguish between these errors and secondly send appropriate http responses based on these errors?
if (failed != null) {
if (failed.getMessage() == "AccountLockedException") {
response.setStatus(403);
} // if account is disabled
else if (failed.getMessage() == "EntityNotFoundException") {
response.setStatus(400);
} // if email incorrect
else if (failed.getMessage() == "Bad credentials") {
response.setStatus(400);
} // if password incorrect
else {
System.out.println("some kind of other authentication error");
response.setStatus(418); // some random error incase this ever happens
}

Call another method after Spring MVC handler returns

I have a requirement where I need to return some status/Long value from a rest controller and then execute code to send push notification.
#RequestMapping(value="/create")
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
Can some one please tell me how to achieve this? Is it possible to use Spring AOP for this? I don't think thread will guaranteed execution of sendPushNotifiction method only after return. So what are the ways to achieve this effectively?
Thanks in advance
I think it might be a good use case for asynchronous processing. Spring has good support for it. Precisely, you need to
Annotate sendPushNotifiction with #Async.
Annotate some configuration class with #EnableAsync.
Call sendPushNotifiction() before the return statement. The execution flow will not wait for sendPushNotifiction to finish.
If it doesn't work, try coding sendPushNotifiction in a separate service.
Create another method which first calls the createTicket() method and then calls the sendPushNotifiction(). That will do the job. This the simplest way in my humble opinion.
createTicket()is called by spring.You can't call it directly.You can use org.springframework.web.servlet.HandlerInterceptor.Just call your sendPushNotifiction() method from postHandle() or afterCompletion() method of
your HandlerInterceptor
package com.sample.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class NotifictionHandlerInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//do nothing
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//call your method here
//call sendPushNotifiction()
}
}
And register you handler in spring-mvc context
<mvc:interceptors>
<bean class="com.sample.NotifictionHandlerInterceptor" />
</mvc:interceptors>
You can call like that:
#RequestMapping(value="/create")
public void create(){
createTicket();
sendPushNotifiction();
}
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
i agree with youngHobbit solution where you can do like below wh
#RequestMapping(value="/create")
public String entryMethod() throws InterruptedException {
String response = createTicket();
sendPushNotifiction();
return response ;
}
public String createTicket() throws InterruptedException {
// code to create ticket
return "ticket created";
// need to call sendPushNotifiction() after I return status
}
public void sendPushNotifiction() throws InterruptedException {
// code to send push notification
System.out.println("Sent push notification successfully!!");
}
Though another solution can be to forward/redirect the request to another method once you are done with first one. But take the first approach if it solves your purpose as its simple,clear and readable
AOP is for basically dealing cross cutting concerns which you want to handle across application, should not be used for very specific purpose like this. Why to introduce extra complexity when
Another way is to postpone the execution of sendPushNotification() to some thread / thread pool. Before the return, use a queue to enqueue the processing, then in your thread dequeue and process.
However, you should take care to link your requests to the real caller and take care of failures, etc.
Web is full of examples. Look for java.util.concurrent examples, executors, ...
The HandlerInterceptor is the solution, but the code get a little bit more complex than expected. Here's a code suggestion to make it simpler by putting the whole solution in a single class:
#RequestMapping(value = "/create")
public String createTicket() throws InterruptedException {
String ticket = "ticket created";
result.set(ticket); // Save the ticket to be used after response
return ticket;
}
public void sendPushNotifiction(String ticket) throws InterruptedException {
System.out.println("Sent push notification successfully!!");
}
private static final ThreadLocal<String> result = new ThreadLocal<String>();
#Bean
public MappedInterceptor interceptor() {
return new MappedInterceptor(Arrays.array("/create"), new HandlerInterceptor() {
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// Get the saved object and clean for the next request
String ticket = result.get();
result.set(null);
// Execute after response
sendPushNotifiction(ticket);
}
});
}

spring authentication entry point

I have controller method, which annotated with
#RequestMapping(value = "/someting")
#PreAuthorize("hasAnyRole('ROLE_ACTIVE')")
...
When users without it role transit on this mapping I want to make the users without the appropriate role of the redirect to the home page and displays an alert, the fact that access is denied.
To solve this problem I make custom AccessDeniedHandler, which works perfectly, but only for authenticated users
For users without authentication I found AuthenticationEntryPoint
It looks like
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
AuthenticationException e) throws IOException, ServletException {
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(httpServletRequest);
if(flashMap != null) {
Alerts.addWarningAlert(flashMap, "access denied");
}
httpServletResponse.sendRedirect("/");
}
}
My alert can be added only to flash attributes or model of my main page, but flash map in this method always have null value
How I can solve it without redirecting to other controller, which then redirects to main page and add value to model? Or can I add my flash attributes to http servlet response?
It was possible using Session attributes. I added attribute and then take this attribute from Session in alerts handler.

Apache Shiro: How to enforce password change?

I've got a Java EE 7 (JSF, JPA) and CDI based application running, using Shiro for both Authentication and Authorization.
I've got the requirement, that users have to change their password after a certain amount of time (customizable by the application's admin, i.e. 30 days). In our User table we store the information when the password was last set and thus can calculate on Login if it's time to do so.
The plan is to redisplay the login page and represent a different form (change password instead of login). So far so good. However:
How can I enforce the password change and not letting the user navigate to a different page?
Is there a recommended (or even built in) solution?
My idea would be to implement a filter, that checks the session-scoped login object on whether the PW needs to be reset or not.
The hope would be, that this it as simple as creating a new filter, injecting login there and checking the state of the flag - and redirecting the user to the login page as long as flag is true/he does not update his pw.
(We already have a custom cdi aware EnvironmentLoaderListener in place to support our JPA realm.)
The new filter would go behind the last line?
[urls]
/javax.faces.resource/** = anon
/layout.xhtml = anon
/css/** = anon
/login.xhtml = user
/logout.xhtml = logout
/** = user
So we have:
/** = user,pwresetfilter
Suggestions on details as well as on the overall solution are welcome.
You can do with your solution, but probably better to have like that:
You make you own realm
MyRealm extends AuthorizingRealm {
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
}
}
Here in doGetAuthenticationInfo you will check credentials and throw exception if password need to be changed. Feel free to extend realm currently in use.
In your EnvironmentLoaderListener you register your realm
May be in the end you would need to have filter to redirect to correct page, or if you use REST(like Jersey), you could have an exception mapper which will response something to your browser client
I had a similar requirement that was for OTP after authentication and i used normal filter to filter out all requests.
MAke a attribute in use bean like lastPasswordChangedDate or may be a isPasswordChangerequired as you like. and compare it in filter.
My simple otpFliter Code is as follows but you can make your own according to need like jsf, etc.:
/**
* Servlet Filter implementation class OTPFilter
*/
#WebFilter(urlPatterns = {"/*"},initParams={#WebInitParam(name="enabled",value="0")})
public class OTPFilter implements Filter {
/**
* Default constructor.
*/
boolean enabled=true;
public OTPFilter() {
// TODO Auto-generated constructor stub
}
/**
* #see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* #see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// pass the request along the filter chain
//System.out.println(enabled);
if(enabled){
if(SecurityUtils.getSubject().getPrincipal()!=null){
if(request instanceof HttpServletRequest ){
HttpSession session = ((HttpServletRequest) request).getSession();
LoggedInUser user = (LoggedInUser) session.getAttribute("userinfo");
String url = ((HttpServletRequest) request).getRequestURL().toString();
//System.out.println("url is "+ url);
if( !url.contains("public") && !user.isOTPverified()){
if(user.getOTP() == null)
{
user.setOTP(OTPUtils.generateOTP());
}
//user.setOTPverified(true);
((HttpServletRequest) request).getRequestDispatcher("OTP.jsp").forward(request, response);
return;
}
}
}
}
chain.doFilter(request, response);
}
/**
* #see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
//System.out.println("fConfig.getInitParameter :" + fConfig.getInitParameter("enabled"));
enabled = fConfig.getInitParameter("enabled").equals("1");
}
}

Setting/getting session attribute in JSF

I am trying to implement simple log in functionality in a JSF application. Following this answer, I have implemented an AuthenticationFilter. I am trying to set an object in my managed bean as :
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) facesContext.getExternalContext().getSession(true);
session.setAttribute("user", user);
doFilter method of AuthenticationFilter looks like this:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
if (((HttpServletRequest) req).getSession().getAttribute("user") == null){
((HttpServletResponse) resp).sendRedirect("../login.jsf");
} else {
chain.doFilter(req, resp);
}
}
I always get ((HttpServletRequest) req).getSession().getAttribute("user") == null (true). I have searched and applied many alternatives like (in my bean) :
facesContext.getExternalContext().getSessionMap().put("user", user);
request.getSession().setAttribute("user", user);
session.getServletContext().setAttribute("user", user); // DISASTER
I don't have a clue how to manage this thing. Seemingly duplicate question did'nt help either. What am I doing wrong? How can I make it work? Is there a good and clean way to do it using JSF capabilities?
I recommend you use a security library like the previous answer. There are too many ways to do this incorrectly...
But if you're dead set on doing it yourself, don't set this in the Session. Declare a ManagedBean and scope it as the session level. Have a property of the bean be the username.

Resources