0

I am writing a Spring application which requires users to log in to access a page that has been secured using Spring security. When the user tries to access the secure page they are asked to log in. If the login is successful the user should be redirected straight to the secure page, otherwise the log in page should be reshown with an error message. Currently the unsuccessful scenario works but if the user does log in properly, the log in page is still reshown, albeit with no error message.

Here is the relevant Java code and Spring configuration:

UserCredentialsController:

//Methods omitted above.


@RequestMapping(value="/login", method = RequestMethod.GET)
public String login(Model model){
    System.out.println("In login() method");
    model.addAttribute("credentials", new User());
    return "login";
}
@RequestMapping(value="/checkcredentials", method = RequestMethod.POST)
public String checkCredentials(@ModelAttribute ("credentials") User user, Model model, HttpServletResponse response){
    if(userService.getUser(user)){
       //I am trying to redirect the user here in the event of a successful log in. Does not work at present. 
        return "redirect:/addincident"; 

        }
        else{
         model.addAttribute("message", "Username and/or password is/are not valid");
            //This works at the moment.
            return "login";
        }
}

spring-security.xml:

<beans:beans xmlns="http://www.springframework.org/schema/security"
       xmlns:beans="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.2.xsd">


 <http auto-config="true">
     <intercept-url pattern="/addincident" access="ROLE_USER, ROLE_ADMIN"/>
     <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
     <form-login login-page="/login"/>
 </http>

<authentication-manager>
  <authentication-provider>
      <user-service>
            <user name="daj" password="123" authorities="ROLE_USER, ROLE_ADMIN" />
            <user name="eoj" password="123" authorities="ROLE_USER" />
      </user-service>
  </authentication-provider>
</authentication-manager>

My thoughts at the moment are that this is a security issue. This is because previously I used Spring's default login page which worked fine when I was using XML-based users. But now I save users in a database and I have my own login page and the navigation no longer works in the way I expect it to.

EDIT: Here is the addIncident method. It loads properly when I use the default Spring log in form.

GeneralIncidentController:

//Methods omitted above.
@RequestMapping(value = "/addincident", method = RequestMethod.GET)
public String addIncident(@RequestParam(value="name", required=false, defaultValue="World") String name, Model model){
    model.addAttribute("message", "Spring 3 MVC Hello World");
    model.addAttribute("name", name);
    model.addAttribute("details", new GeneralIncident());      //Need this to populate bean with submitted data for validation.
    return "myform";
}
user1849060
  • 621
  • 3
  • 10
  • 20
  • try the solution in http://stackoverflow.com/questions/14573654/spring-security-redirect-to-previous-page-after-succesful-login – Neelam Mehta Nov 19 '14 at 11:12
  • I'm not sure this is applicable in my situation? It looks like that configuration is for using the default log in page. I have tags called authentication-manager but not a bean. – user1849060 Nov 19 '14 at 11:30

1 Answers1

0

You need to add a default-target-url attribute to <form-login login-page="/login"/>, the value will lead to the page the user should meet after successful login, if omitted (like in your case) it leads to the root of the app. So try something like

<security:form-login login-page="/admin/login" default-target-url="/loginsuccess"

UPDATE, to authenticate from service you can try like this

  1. Register your custom provider with spring security

    <sec:authentication-manager alias="authenticationManager" erase-credentials="false">
      <sec:authentication-provider ref="customAuthenticationProvider"/>
    </sec:authentication-manager>
    <bean id="customAuthenticationProvider" class="your.package.CustomAuthenticationProvider"/>
    
  2. Implement your CustomProvider

    public class CustomAuthenticationProvider implements AuthenticationProvider {
    
    @Autowired
    private YourUserService userService;
    
    
    @Override
    public boolean supports(Class<? extends Object> authentication) {
        return (authentication.equals(UsernamePasswordAuthenticationToken.class) || authentication.equals(UrlAuthenticationToken.class));
    }
    
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationServiceException {
        YourUser user = userService.loginByEmailAndPassword((String) authentication.getPrincipal(), (String) authentication.getCredentials());
        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
        Authentication endUserAuth = new UsernamePasswordAuthenticationToken(user, user.getPassword(), grantedAuthorities);
        return endUserAuth;
    }
    

    }

Master Slave
  • 27,771
  • 4
  • 57
  • 55
  • I've just tried this (although my values are slightly different to reflect my application) and I still get the same problem. Do you need any other code/config information? – user1849060 Nov 19 '14 at 11:05
  • you can post the method mapped against /addincident. Also, I'm not sure if the specificity rule applies also on the form-login, but do push you form-login element to be the first in the list, and than list the the intercept from the most specific downwards – Master Slave Nov 19 '14 at 11:24
  • Posted the method and moved the form-login element but it still doesn't work. – user1849060 Nov 19 '14 at 11:31
  • in fact everything appears correct for what concerns the spring security. What I answered accounts only when you land on login page, when read again you mention that you have the issue on attempt of an unsecure page. I'm thinking of deleting my response. You can also post your authentication-manager, maybe there's something to it – Master Slave Nov 19 '14 at 11:41
  • Added the `authentication-manager` tag. Note that if I attempt to log in using those credentials it won't work on the custom log in page but it does on the default one. – user1849060 Nov 19 '14 at 11:47
  • Is it possible that the users that I have in the database aren't authorised to see this page? If you look at the spring-security.xml file I provided the addIncident page can be accessed by those with the `ROLE_USER` and `ROLE_ADMIN` roles. But I'm not sure if this can be mapped to users in the database? – user1849060 Nov 19 '14 at 12:30
  • according to the config the only user that can reach addincident is daj=123. If you want to assign roles to DB users you have to configure differently. I can provide help if this is what you need – Master Slave Nov 19 '14 at 12:50
  • I tried to log in with daj but I get the failed scenario because that user isn't in the database. With the default Spring login page I can log in with daj because the users are assumed to be in the XML. Yes I'd like help configuring roles to users in a DB. – user1849060 Nov 19 '14 at 13:04
  • I'm gussing `YourUser` is the Bean that the username and password are sent to when they are checked? I ask because I don't have a method called "loginByEmailAndPassword". – user1849060 Nov 19 '14 at 14:10
  • yeps, that your implementation of a login service – Master Slave Nov 19 '14 at 14:11
  • OK then the method I'd have accepts a User single object, unlike your example. I guess I'd pass this in by calling my AuthenticationProvider class in my controller? – user1849060 Nov 19 '14 at 14:20