MarquisDeMizzle
MarquisDeMizzle

Reputation: 514

How to force re-authentication of credentials in Spring Security?

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?

Upvotes: 6

Views: 7699

Answers (1)

user3151168
user3151168

Reputation:

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; }
    }
}

Upvotes: 7

Related Questions