I would like to force a re-authentication of credentials before allowing execution of particularly sensitive actions in my web application, such as adding a signature to a set of data.
The scenario is that the user is already logged in, clicks to add their signature on the data, and gets presented with fields to enter their credentials which then get passed along to the server for authentication. Failure would not affect the login state, simply deny the action.
I am using the Grails spring-security plugin and authenticating against LDAP (spring-security-ldap) but I'm assuming a solution would be independent of these exact details.
I have the username and password values on the server-side (controller/servlet), how do I authenticate these new credentials?
To, let's manually trigger authentication and then set the resulting Authentication object into the current SecurityContext used by the framework to hold the currently logged-in user: UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user, pass); Authentication auth = authManager.
The HttpServletRequest.getUserPrincipal() will return the result of SecurityContextHolder.getContext().getAuthentication() . This means it is an Authentication which is typically an instance of UsernamePasswordAuthenticationToken when using username and password based authentication.
You can reuse your user credentials and Spring Security
infrastructure in your controller without manipulating the current authentication.
Basically, your application requests via a simple form username and password and validates it with the authenticationManager
. Depending on the outcome you can proceed with your application logic or do something else.
This example shows the usage of authenticationManager
inside an Spring MVC
Controller.
Unfortunately, I'm not a Grails user. To give you an example that works this example is using Java and Spring MVC.
JSPs are omitted for the sake of brevity.
A complete example can be found here (under Approval page).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.Map;
@Controller
@RequestMapping("approval")
public class ApprovalController {
@Autowired
private AuthenticationManager authenticationManager;
@RequestMapping(value="confirm.do", method = RequestMethod.GET)
public String get() {
return "approval/confirm";
}
@RequestMapping(value="confirm.do", method = RequestMethod.POST)
public String post(@ModelAttribute ApprovalRequestForm form, Map<String, Object> model, Authentication authentication) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(form.getUsername(), form.getPassword());
Authentication authenticate = authenticationManager.authenticate(token);
if(authenticate.isAuthenticated() && isCurrentUser(authentication, authenticate)) {
//do your business
return "approval/success";
}
model.put("reason", "credentials doesn't belong to current user");
return "approval/denied";
}
private boolean isCurrentUser(Authentication left, Authentication right) {
return left.getPrincipal().equals(right.getPrincipal());
}
@ExceptionHandler(Exception.class)
public ModelAndView handleException(Exception exception) {
ModelAndView model = new ModelAndView("approval/denied");
model.addObject("reason", exception.getMessage());
return model;
}
public static class ApprovalRequestForm {
private String username;
private String password;
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With