Spring Security 3 - always return error 302
Asked Answered
R

4

14

I use Spring 4 to create a simple application. Recently, I'm adding Spring Security 3 to the project but always get the Error Code 302 ( so it redirect to home page always ).

Here is my SecurityConfig:

@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages = { "com.moon.repository" })
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("hello").password("world").roles("USER");
}

@Override
public void configure(WebSecurity web) throws Exception {
    web
    .ignoring().antMatchers("/resources/**", "/views/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests()
            .antMatchers("/","/home").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .loginPage("/home")
            .loginProcessingUrl("/acct/signin")
            .and()
            .logout()
            .permitAll();
}

}

I have a Controller called AccountController:

@Controller
@RequestMapping(value = "/acct")
public class AccountController {

private final Logger logger = LoggerFactory.getLogger(AccountController.class);

@RequestMapping(value = "/signin", method = RequestMethod.POST)
public String signin(@RequestParam("username") String username,
        @RequestParam("password") String password) {

    logger.info("======== [username:{0}][password:{1}] ========", username, password);

    if ("[email protected]".equalsIgnoreCase(username)) {
        return "error";
    } else {
        return "demo";
    }
}

}

My WEB-INF structure:

WEB-INF
----views
--------home.jsp
--------demo.jsp
--------error.jsp

The flow is like:

  1. User access the web site with http://mylocal:8080/moon => it shows home.jsp
  2. User press the button SignIn and it pops a sub-window asked for username and password => still in home.jsp
  3. User press Submit button => I assume it will go /acct/signin and return to /demo, but I see Error 302 in Google Chrome and then it goes to /home again

Any ideas ? I'm stuck in 2 full days and now i'm almost in despair...

thank you very much every one to take a look at my problem

=================================== 1st Update ===================================

Update: The form in home.jsp

<form:form role="form" method="POST" action="acct/signin"
class="form-signin">
<div class="row">
    <div class="col-lg-5">
        <input name="username" size="20" type="email"
            class="form-control" placeholder="Email address" required
            autofocus> 
            <input name="password" type="password"
                    class="form-control" placeholder="Password" required>
                <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </div>
</div>
</form:form>

=================================== 2nd Update ===================================

I tried to implement UserDetailsService(not to use in-memory auth) but still... the same problem - Error 302

AppUserDetailsServiceImpl.java

@Component
public class AppUserDetailsServiceImpl implements UserDetailsService {

    private final Logger logger = LoggerFactory.getLogger(AppUserDetailsServiceImpl.class);

    @Override
    public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {

        logger.info("loadUserByUsername username=" + username);
        logger.info("======== {} ========",SecurityContextHolder.getContext().getAuthentication());

        if (!username.equals("hello")) {
            throw new UsernameNotFoundException(username + " not found");
        }

        // creating dummy user details
        return new UserDetails() {

            private static final long serialVersionUID = 2059202961588104658L;

            @Override
            public boolean isEnabled() {
                return true;
            }

            @Override
            public boolean isCredentialsNonExpired() {
                return true;
            }

            @Override
            public boolean isAccountNonLocked() {
                return true;
            }

            @Override
            public boolean isAccountNonExpired() {
                return true;
            }

            @Override
            public String getUsername() {
                return username;
            }

            @Override
            public String getPassword() {
                return "world";
            }

            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                List<SimpleGrantedAuthority> auths = new java.util.ArrayList<SimpleGrantedAuthority>();
                auths.add(new SimpleGrantedAuthority("USER"));
                return auths;
            }
        };
    }

The log shows:

[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](24) loadUserByUsername username=hello
[14/08/19 15:16:32:200][INFO ][com.moon.repository.AppUserDetailsServiceImpl][loadUserByUsername](25) ======== org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f1e4f742: Principal: com.moon.repository.AppUserDetailsServiceImpl$1@e3dc1b1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@12afc: RemoteIpAddress: 127.0.0.1; SessionId: 023BC9A8B997ECBD826DD7C33AF55FC7; Granted Authorities: USER ========
Rollerskate answered 18/8, 2014 at 6:34 Comment(3)
Just to assert my answer, can you set a debug point anywhere in your signin method and evaluate the following expression : SecurityContextHolder.getContext().getAuthentication() and post the result please ? (and especially who is the principal)Schott
Hi @m4rtin, I use Log in the code for debugging so I make one in the begin of AccountController ("/signin"). Please see the edit. The strange thing is, I can't find this log in the log file... looks like it("acct/signin") was not triggered.Rollerskate
To be sure the method handling your login process is invoked, you can put a debug point in it and launch your app in debug mode. But in the solution I wanted you to try in my other comment, you won't be able to do that since Spring Security will take care of the processing of the login request (you can still put a debug point in your UserDetailsService though).Schott
S
7

I believe Spring is redirecting you to /home because you didn't actually authenticated a User through the login process.

  1. You access your web-app through http://mylocal:8080/moon returning the home.jsp view
  2. You click the SignIn button, submitting your login form since no form login is explicitly declared, Spring Security will display the username and password prompt box for the end-user to enter its credentials
  3. These credentials are then POSTed to the login processing URL (/acct/signin) for which you happen to have a mapping with the signin method in the AccountController
  4. Such controller fails to authenticate a User the Spring way, but still redirect the request to /demo by returning a String
  5. The /demo path is protected (.anyRequest().authenticated()) to any unauthenticated user, since the current user is indeed unauthenticated, Spring Security will automatically redirect the request to the login page
  6. You end up on /home (.loginPage("/home"))

Using a InMemoryUserDetailsManagerConfigurer (see inMemoryAuthentication javadoc), you can only successfully login through the configured credentials. If you want a fully-fledged Authentication system, you must provide an UserDetailsService implementation to your Spring Security configuration (through the userDetailsService method).


EDIT : Following the conversation with chialin.lin, it seems the missing configuration was a defaultSuccessfulUrl for Spring Security to know where to redirect the user once authenticated.

Schott answered 18/8, 2014 at 7:23 Comment(7)
Hi @m4rtin, Sorry that I forget to put home.jsp information. Basically, I put the login form in home.jsp. Please see my update editRollerskate
Oh ok, so you do provide the input fields to enter the credentials, I'll update my answer accordingly. Still, I believe the rest of my answer is correct.Schott
Hi @m4rtin, I implement UserDetailsService(named AppUserDetailsServiceImpl) but the problem is still there. I've updated in the postRollerskate
Well, it seems things are certainly not going after what I wrote in my answer because you are indeed authenticated so there should be no problem for you to continue your navigation. Maybe a mapping problem ? Could you try removing your loginProcessingUrl config and add a defaultSuccessUrl to /demo for example ?Schott
Hi @m4rtin, I did the test (1) removed loginProcessingUrl and added defaultSuccessUrl(/demo), this did not work; (2) added loginProcessingUrl and defaultSuccessUrl together, this did WORK!!! Looks like there are only 2 things I need: (a) a form with action='acct/signin', POST (b) a config (.loginProcessingUrl("/acct/signin")) in SecurityConfig. I don't need to code a method with mapping "acct/signin" in any Controller... is it correct?Rollerskate
@Rollerskate Exactly : Spring Security will handle user authentication with one of its own filter within the Spring Security filter chain (usually a UsernamePasswordAuthenticationFilter) so that you don't have to do it yourself. I thought the loginProcessingUrl was meant to bypass such process and letting dev handles its own authentication process but apparently I was wrong. Anyway, I'm glad you found a solution to your problem, I'll edit my answer. Happy coding :)Schott
For my usecase(in spring-security version 5.3.1), Have to override successfulAuthentication method in Filter (AbstractAuthenticationProcessingFilter) in order to workHint
F
1

To avoid having to create a new trivial SuccessHandler, override the successfulAuthentication method in your filter and just call the chain.doFilter() method after having set the Authentication object in the security context.

Flyfish answered 11/6, 2017 at 5:29 Comment(0)
P
1

For me I came from a little different use-case but 'suddenly' had the same problem before it perfectly worked.
My Setup Spring with a ExtJs frontend where I now build in a rest interface.
It all worked super nice and then suddenly I started having http status 302 responses (WTH?)

Since I implemented by code by following this example: https://octoperf.com/blog/2018/03/08/securing-rest-api-spring-security/
there is a declaration of a SimpleUrlAuthenticationSuccessHandler.
See 4.4 SecurityConfig where the TokenAuthenticationFilter is constructed with a class NoRedirectStrategy; see 4.1 Redirect Strategy

In turn not having this NoRedirectStrategy set up in my extension of the AbstractAuthenticationProcessingFilter it would show me http 302 responses.

Pina answered 18/1, 2019 at 10:13 Comment(0)
F
0

I had a problem with the following: In my html that I set in the login settings I didn't put /

In the end I was able to

<form class="form-signin" method="post" action="auth/login">

but it should have been

<form class="form-signin" method="post" action="/auth/login">

As a result, i could not login > got a 302 redirect error > and redirected again to a broken login page. This is what the full working page looks like.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login customer</title>
</head>
<body>
<div class="container">
    <form class="form-signin" method="post" action="/auth/login">
        <h2 class="form-signin-heading">Login</h2>
        <p>
            <label for="username">Username</label>
            <input type="text" id="username" name="username" class="form-control" placeholder="Username" required>
        </p>
        <p>
            <label for="password">Password</label>
            <input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
        </p>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
    </form>
</div>
</body>
</html>
Flyweight answered 6/4, 2022 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.