I'm trying POST requests to login to the page with JWT Authentication.
I had initially tried to do JWT Authentication using WebSecurityConfigurerAdapter. But WebSecurityConfigurerAdapter is deprecated. I then tried to integrate it according to the new usage.But When I send POST request in Postman, I m getting this error.
"org.springframework.security.authentication.AuthenticationManager.authenticate(org.springframework.security.core.Authentication)" because "this.authenticationManager" is null
My Dependencies are:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.project</groupId>
<artifactId>questapp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>questapp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
My Controller Class is:
#RestController
#RequestMapping("/auth")
public class AuthenticationController {
private AuthenticationManager authenticationManager;
private JwtTokenProvider jwtTokenProvider;
#PostMapping("/login")
public String login(#RequestBody UserRequest userLoginRequest) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userLoginRequest.getUserName(), userLoginRequest.getPassword());
Authentication auth = authenticationManager.authenticate(authenticationToken);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
String jwtToken = jwtTokenProvider.generateJwtToken(auth);
return "Bearer "+jwtToken;
}
}
My SecurityConfig Class is:
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfig {
private final UserDetailsService jwtUserDetailsService;
private final JwtAuthenticationEntryPoint handler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Bean
public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
AuthenticationManagerBuilder authenticationManagerBuilder = http.getSharedObject(AuthenticationManagerBuilder.class);
authenticationManagerBuilder.userDetailsService(jwtUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
return authenticationManagerBuilder.build();
}
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{
httpSecurity
.cors()
.and()
.csrf().disable()
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().authenticationEntryPoint(handler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/auth/**")
.permitAll()
.antMatchers("/auth/**")
.permitAll()
.anyRequest().authenticated();
return httpSecurity.build();
}
}
Can anyone tell me where I made a mistake?
Related
I want to log when the token is wrong. I prepared the ServerAuthenticationFailureHandler class, but it doesn't work.
SecurityConfig class
#Configuration
public class SecurityConfig {
#Bean
public SecurityWebFilterChain configure(ServerHttpSecurity http) {
http.csrf().disable()
.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.oauth2Login().authenticationFailureHandler(authenticationFailureHandler())
.and().oauth2ResourceServer().jwt();
return http.build();
}
#Bean
public ServerAuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
}
CustomAuthenticationFailureHandler class
#Component
public class CustomAuthenticationFailureHandler implements ServerAuthenticationFailureHandler {
Logger logger = LogFactory.getLogger(CustomAuthenticationFailureHandler.class);
#Override
public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {
logger.error("invalidToken");
return null;
}
}
pom.xml
<properties>
<java.version>17</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.2.1</version>
</dependency>
</dependencies>
It does not fall under the CustomAuthenticationFailureHandler class.
How can I intervene when the token is invalid?
We are building a Web Application with Spring Boot and Vue.js. Currently we are migrating from Security OAuth 2.x to Spring Security 5.2.x and having issues with the Oauth2 flow.
Below is the security configuration:
#EnableWebSecurity
#Configuration
#PropertySource("classpath:application.properties")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(new StaticAllowFromStrategy(location)));
http.authorizeRequests()
.antMatchers("/login", "/static/**","/", "/actuator/prometheus")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login();
}
private static List<String> clients = Arrays.asList("authnext");
#Bean
public ClientRegistrationRepository clientRegistrationRepository() {
List<ClientRegistration> registrations = clients.stream()
.map(c -> getRegistration(c))
.filter(registration -> registration != null)
.collect(Collectors.toList());
return new InMemoryClientRegistrationRepository(registrations);
}
private ClientRegistration getRegistration(String client) {
if (client.equals("authnext")) {
return AuthNextOAuth2Provider.AUTHNEXT.getBuilder(client, "https://baseurl/auth/oauth2/realms/root/realms/intranetb2x/authorize",
"https://baseurl/auth/oauth2/realms/root/realms/intranetb2x/tokeninfo",
"https://baseurl/auth/oauth2/realms/root/realms/intranetb2x/userinfo")
.clientId("ID")
.clientSecret("SECRET")
.build();
}
return null;
}
#Bean
public OAuth2AuthorizedClientService authorizedClientService() {
return new InMemoryOAuth2AuthorizedClientService(
clientRegistrationRepository());
}
#Bean
public AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository() {
return new HttpSessionOAuth2AuthorizationRequestRepository();
}
}
Furthermore we have the following AuthNextOAuth2Provider:
public enum AuthNextOAuth2Provider {
AUTHNEXT {
#Override
public Builder getBuilder(String registrationId,String authUri,String tokenUri, String userInfoUri) {
ClientRegistration.Builder builder = getBuilder(registrationId, ClientAuthenticationMethod.BASIC,DEFAULT_LOGIN_REDIRECT_URL);
builder.scope("openid", "profile", "b2xroles");
builder.authorizationUri(authUri);
builder.tokenUri(tokenUri);
builder.userInfoUri(userInfoUri);
builder.userNameAttributeName(IdTokenClaimNames.SUB);
builder.clientName("authnext");
return builder;
}
};
private static final String DEFAULT_LOGIN_REDIRECT_URL = "{baseUrl}/login";
protected final ClientRegistration.Builder getBuilder(String registrationId, ClientAuthenticationMethod method,
String redirectUri) {
ClientRegistration.Builder builder = ClientRegistration.withRegistrationId(registrationId);
builder.clientAuthenticationMethod(method);
builder.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE);
builder.redirectUriTemplate(redirectUri);
return builder;
}
/**
* Create a new
* {#link org.springframework.security.oauth2.client.registration.ClientRegistration.Builder
* ClientRegistration.Builder} pre-configured with provider defaults.
*
* #param registrationId the registration-id used with the new builder
* #return a builder instance
*/
public abstract ClientRegistration.Builder getBuilder(
String registrationId,
String authUri,
String tokenUri,
String userInfoUri
);
}
The problem is the redirect isn't working correctly. We can be correctly directed to the auth server and login there but when redirected back to the spring application we get a 404 error.
How it works is as follows. We have a Spring Boot application which lives at /. I want to allow all requests to the / /login und /static/** so that the vue.js resources are correctly served. The vue.js application is calling an backend endpoint status to check if the broswer is currently authenticated. If this is not the case then the user is redirected to the Oauth2 auth server as follows:
checkLoggedIn: function() {
AXIOS({
method: "GET",
url: "/status",
responseType: "blob"
})
.then(response => {
var element = document.getElementById("step1");
element.classList.add("step-active");
document.getElementById("lock1").style.visibility = "hidden";
document.getElementById("lock2").style.visibility = "hidden";
document.getElementById("lock3").style.visibility = "visible";
document.getElementById("lock4").style.visibility = "hidden";
this.connect();
})
.catch(error => {
if(typeof error.response === 'undefined'){
var localStorage = window.localStorage;
window.localStorage.setItem('route', JSON.stringify(this.$route));
window.location.href = "/login";
}else if(error.response.status===403){
this.$parent.upload = false;
this.$parent.uploadResult = false;
this.$parent.checkData = false;
this.$parent.approveData = false;
this.$parent.checkout = false;
this.$parent.unauthorized=true;
}
});
}},
Forcing the browser to visit /login seems to begin the authentication workflow correctly but on the way back there is a problem with the following request:
How can I configure the login flow correctly. It also seems to create some endpoints in the backend of the form:
oauth2/authorization/authnext
What is this and is it necessary. With Spring OAuth2 we just used #EnableOauth2Sso and everything just worked.
Here are the dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${oauth-auto.version}</version>
</dependency>
-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-core</artifactId>
<version>1.1.44</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.1.44</version>
</dependency>
<!-- <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.1.44</version> </dependency> <dependency> <groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId> <version>1.1.44</version> </dependency> -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.metrics</groupId>
<artifactId>spring-metrics</artifactId>
<version>0.5.1.RELEASE</version>
</dependency>
<dependency>
<groupId>io.prometheus</groupId>
<artifactId>simpleclient_common</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
</dependencies>
I have a spring application that uses the following dependencies:
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.3.RELEASE</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-tools</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
The security application is configured as following:
#Configuration
public class SecurityConfiguration {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.csrf().disable()
.authorizeExchange()
.pathMatchers("/**").hasAuthority("myAuthority")
.anyExchange().authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(converter());
return http.build();
}
#Bean
public Converter<Jwt, Mono<AbstractAuthenticationToken>> converter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new GrantedAuthoritiesExtractor());
return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
}
static class GrantedAuthoritiesExtractor implements Converter<Jwt, Collection<GrantedAuthority>> {
public Collection<GrantedAuthority> convert(Jwt jwt) {
Collection<String> authorities = (Collection<String>) jwt.getClaims().get("roles");
if(authorities == null) {
authorities = List.of();
}
return authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}
}
so I need authenticated user to request the api and the authority myAuthority.
I would like to write some tests for this to be sure a test fails if someone changes the security configuration.
I use this:
protected WebTestClient webTestClient(Object controller) {
return WebTestClient.bindToController(controller)
.apply(springSecurity())
.configureClient()
.build()
.mutateWith(mockJwt().authorities(new SecurityConfiguration.GrantedAuthoritiesExtractor()));
}
but all tests pass and no authenticated user is needed nor authority.
I would like to use #MockUser to test roles.
EDIT for further info on tests
here is the test class
#ExtendWith(SpringExtension.class)
#WebFluxTest(controllers = MyController.class)
#Import({MyRepository.class, ValidationConfiguration.class})
public class MyControllerTest extends BaseControllerTest {
#Autowired
MyController controller;
#Test
public void test() {}
}
I am trying to access a welcome page after login using
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService customUserDetailsService;
#Autowired
private DataSource dataSource;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.successForwardUrl("/welcome")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/");
}
}
My UserDetailsService is:
#Service(value = "customUserDetailsService")
public class CustomUserDetailsServiceImpl implements UserDetailsService {
private static Logger logger = LoggerFactory.getLogger(CustomUserDetailsServiceImpl.class);
#Autowired
private UserService userService;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userService.findByEmail(email);
if (user == null) {
logger.error("User with email" + email + " not found.");
throw new UsernameNotFoundException("Oops! User not found with username: " + email);
} else {
logger.info("User {} successfully logged", user.getUsername());
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), getAuthorities(user));
}
}
private Collection<GrantedAuthority> getAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<>();
for (UserProfile userProfile : user.getUserProfileSet()) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + userProfile.getType()));
}
return authorities;
}
}
The relevant bits of the controllers are:
#RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Principal principal) {
if (logger.isDebugEnabled()) {
logger.debug("getWelcome is executed");
System.out.println(principal);
}
return principal == null ? "homeNotSignedIn" : "welcome";
}
#GetMapping("/login")
public String login(Model model, String error, String logout) {
if (error != null)
model.addAttribute("error", "Your username and password is invalid.");
if (logout != null)
System.out.println(">>>>>>>>>>>>>>>>>>> LOGOUT <<<<<<<<<<<<<<<<<<");
model.addAttribute("message", "You have been logged out successfully.");
return "login";
}
#GetMapping("/welcome")
public String welcome(Model model) {
System.out.println(">>>>>>>>>>>>>>>>>>>>>>> WELCOME <<<<<<<<<<<<<<<<<<<<<<<");
return "welcome";
}
My pom.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ie.gtludwig.pa</groupId>
<artifactId>pa</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>PA</name>
<modules>
<module>core</module>
<module>engine</module>
</modules>
<properties>
<!-- JAVA -->
<version.java>1.8</version.java>
<java.version>${version.java}</java.version>
<jdk.version>${version.java}</jdk.version>
<maven.compiler.target>${version.java}</maven.compiler.target>
<maven.compiler.source>${version.java}</maven.compiler.source>
<!-- Generic properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- External Dependency Versions -->
<spring-boot.version>2.1.3.RELEASE</spring-boot.version>
<jedis.version>2.9.1</jedis.version>
<junit.version>4.12</junit.version>
<logback.version>1.2.3</logback.version>
<thymeleaf.version>3.0.11.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.3.0</thymeleaf-layout-dialect.version>
<flyway.version>5.2.0</flyway.version>
<mysql.version>8.0.16</mysql.version>
<h2database.version>1.4.199</h2database.version>
<sendgrid-java.version>4.3.0</sendgrid-java.version>
<commons-lang3.version>3.7</commons-lang3.version>
<commons-io.version>2.6</commons-io.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<!--WEB-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>${thymeleaf-layout-dialect.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<!--SECURITY-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--OPERATIONS-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.jolokia</groupId>
<artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--SERVER-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!--DATABASE-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!--TEST DATABASE FOR TESTING PROCESSES AND RULES IN-MEMORY-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2database.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.17.Final</version>
<scope>runtime</scope>
</dependency>
<!--EMAIL-->
<!-- https://mvnrepository.com/artifact/com.sendgrid/sendgrid-java -->
<dependency>
<groupId>com.sendgrid</groupId>
<artifactId>sendgrid-java</artifactId>
<version>${sendgrid-java.version}</version>
</dependency>
<!--DEV/TEST-->
<!--DEV TOOLS CONFLICT WITH JREBEL - DISABLE THIS IF JREBEL IS BEING USED -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>5.0.7.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<!-- Resource plugin to enable expanding properties from this file so that they can be exposed by the zone (E.g. #project.version#) -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<nonFilteredFileExtensions>
<!--font/binary files must be excluded from filtering or they will be corrupted-->
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>jks</nonFilteredFileExtension>
</nonFilteredFileExtensions>
<delimiters>
<delimiter>#</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<!-- Add our project version to the manifest file -->
<version>${project.version}</version>
<description>${project.description}</description>
</manifestEntries>
</archive>
<failOnMissingWebXml>false</failOnMissingWebXml>
<attachClasses>false</attachClasses>
</configuration>
<version>3.1.0</version>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>external</id>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${spring-boot.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
</profiles>
What happens is:
When I access localhost:8080/core I get the correct homeNotSignedIn page, but there is no CSS or JS loaded from /resources/**.
I click a login redirection link to the login page (again without CSS or JS) and CAN login.
The logged username is displayed to the console, so the customUserDetailsService seems to be working alright, but I don't get redirected to /welcome.
At this point, I can only logout by typing /logout to the URL and it works and sends me to homeNotSignedIn.
I have been going back and forth at this and I can't seem to get it done.
What am I missing?
I have been going back and forth at this and I can't seem to get it done.
What am I missing?
EDIT
I managed to load CSS and JS by changing:
.antMatchers("/resources/**").permitAll()
to:
.antMatchers("/css/**", "/js/**").permitAll()
When you are using successForwardUrl you will be forwarded to the given URL, but not redirected.
That means that the URL in your browser will not change, however it will display the HTML in your welcome.html.
If you would like to redirect, you can use defaultSuccessUrl as mentioned on the spring-security documentation.
Then your security configuration would look like this.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/resources/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/welcome", true)
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/");
}
I've had developed the spring-security-jsp-authorize example. In this example I was using the spring-boot-starter-parent version 1.3.7.RELEASE till that version program was not giving any deprecation error for SpringBootServletInitializer. What's is the replacement of import org.springframework.boot.context.web.SpringBootServletInitializer in spring-boot-starter-parent in version 1.4.0.RELEASE?
Application.java
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john").password("123").roles("USER")
.and()
.withUser("tom").password("111").roles("ADMIN");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin().permitAll();
}
}
MvcConfig.java
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
public MvcConfig() {
super();
}
#Override
public void addViewControllers(final ViewControllerRegistry registry) {
super.addViewControllers(registry);
registry.addViewController("/").setViewName("forward:/index");
registry.addViewController("/index");
}
}
It is stated in docs for Spring Boot 1.4 > org.springframework.boot.context.web:
Deprecated. as of 1.4 in favor of
org.springframework.boot.web.support.SpringBootServletInitializer
Just change the deprecated import to this new package.
You can use WebMvcConfigurer interface.
public class Configuration implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurerconfigurer) {
configurer.enable();
}
}