chialin.lin
chialin.lin

Reputation: 143

Spring Security 3 - always return error 302

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 ========

Upvotes: 14

Views: 32423

Answers (4)

Сергей
Сергей

Reputation: 131

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>

Upvotes: 0

Dirk Schumacher
Dirk Schumacher

Reputation: 1655

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.

Upvotes: 1

Dani
Dani

Reputation: 4111

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.

Upvotes: 1

m4rtin
m4rtin

Reputation: 2475

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.

Upvotes: 7

Related Questions