I have a tutorial i am following for Spring Security. Although the login woks well on localhost, after i deploy it to google cloud, Spring security login only works sometimes. For example, when i press login, sometimes it gets the login?error sometimes it doesn't.
I am very confused about this behaviour.
I have tried adding cutom authentication, but it hasn't worked. Even when i enter a 4 letter username, I either get nothing (login page refreshes) or logs in (but just 1 in 10 attempts).
If you were to test this in localhost it would work perfectly fine. Although : http://website-live-245110.appspot.com/ (gccloud hosted site) here it does not always work.
CustomAuthenticationProvider.java
package com.spring.authprovider;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider{
@Autowired
private ThirdPartyAuthProviderClient thirdPartyAuthProviderClient;
// one a user logs in, the authentication variable is filled with the details of the authentication
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// when the user logs in to the application, our object will be filled by spring
String name = authentication.getName();
Object password = authentication.getCredentials(); //object that encapsulates password that user types
// not printing or storing password anyone
if(thirdPartyAuthProviderClient.shouldAuthenticate(name,password)) {
// the array list is for roles, because we are not using it now, we are sending it an empty one
return new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
} else {
System.out.println("authentication failed for user: " + name);
}
return null;
}
@Override
public boolean supports(Class<?> authentication) {
// there are multiple ways of authentication, use use username and password
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
ThirdPartyAuthProviderClient.java
package com.spring.authprovider;
import org.springframework.stereotype.Component;
@Component
public class ThirdPartyAuthProviderClient {
//emulates request to third party application
public boolean shouldAuthenticate(String username, Object password) {
// 3rd party request to see if user is correct or no or should be logged in
// user with username with 4 digits can be logged in to the application
return username.length() == 4;
}
}
WebSecurityConfig.java
package com.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import com.spring.authprovider.CustomAuthenticationProvider;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomAuthenticationProvider authProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home", "/time").permitAll() // any request matching /, /home, /time
// can be accessed by anyone
.anyRequest().authenticated() // any other request needs to be authenticated
.and().authorizeRequests().antMatchers("/admin/**") // only admin can access /admin/anything
.hasRole("ADMIN")
.and().formLogin().loginPage("/login") // permit all to form login--- we use loginPage to use custom page
.permitAll()
.and().logout() // permit all to form logout
.permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//specify auth provider
auth.authenticationProvider(authProvider);
}
// configuration of static resources
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/templates/**", "/assets/**");
}
}
MvcConfig.java
package com.spring;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
}
}
Templates
hello.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
home.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</body>
</html>
I expect it to either log me in when a username with 4 characters is entered, Or output Invalid username and password. Error. Code is here : https://github.com/jeffpascal/Spring-and-springboot/tree/devs/SpringSecurity