How to set WebSSOProfileConsumerImpl in your Spring Configuration file - spring

I am facing issue of specifying WebSSOProfileConsumerImpl to my Spring Configuration file. I am trying to modify responseSkew in this bean but after adding configuration for WebSSOProfileConsumerImpl I am getting MetadataManager issue
APPLICATION FAILED TO START
Description:
Parameter 0 of method setMetadata in org.springframework.security.saml.websso.AbstractProfileBase required a bean of type 'org.springframework.security.saml.metadata.MetadataManager' that could not be found.
Action:
Consider defining a bean of type 'org.springframework.security.saml.metadata.MetadataManager'
Can anyone help me in resolving this issue?
I have already gone through the link : http://docs.spring.io/spring-security-saml/docs/current/reference/html/configuration-advanced.html but it does not specify how to set this in configuration.
My Code
import static org.springframework.security.extensions.saml2.config.SAMLConfigurer.saml;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.saml.websso.WebSSOProfileConsumer;
import org.springframework.security.saml.websso.WebSSOProfileConsumerImpl;
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${security.saml2.metadata-url}")
String metadataUrl;
#Value("${server.ssl.key-alias}")
String keyAlias;
#Value("${server.ssl.key-store-password}")
String password;
#Value("${server.port}")
String port;
#Value("${server.ssl.key-store}")
String keyStoreFilePath;
#Value("${security.saml2.responseSkew}")
int responseSkew = 0;
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.serviceProvider()
.keyStore()
.storeFilePath(this.keyStoreFilePath)
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s:%s", "localhost", this.port))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl).and();
/* Map<? extends Object, Object> sharedObjects = new Map<? extends Object>, Object>(http.getSharedObjects());
sharedObjects.put(WebSSOProfileConsumer.class, webSSOprofileConsumerImpl());*/
}
#Bean
#Qualifier("webSSOprofileConsumer")
public WebSSOProfileConsumer webSSOprofileConsumerImpl() {
WebSSOProfileConsumerImpl consumerImpl = new WebSSOProfileConsumerImpl();
consumerImpl.setResponseSkew(this.responseSkew);
return consumerImpl;
}
}

If you do not need the WebSSOProfileConsumer to be accessible as a bean to the rest of the application, you can create it inside the configure method like this:
#Override
protected void configure(final HttpSecurity http) throws Exception {
WebSSOProfileConsumerImpl consumerImpl = new WebSSOProfileConsumerImpl();
consumerImpl.setResponseSkew(this.responseSkew);
http
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.serviceProvider()
.ssoProfileConsumer(consumerImpl) // <-- added here
.keyStore()
// Your method continues as before
I do not remember the exact reason regular wiring fails in your case, but the gist of it is that configure sets up a builder object rather than regular beans. Normally the ServiceProviderBuilder provides the MetadataManager needed by your WebSSOProfileConsumer during its build step, but if you autowire the profile consumer you won't get the MetadataManager provided for you since your autowired object is assumed to be complete already.
(I learned this when looking for a way to configure the max authentication age, since the two hour default in spring-security-saml in some cases is lower than the defaults used by identity providers. This effectively locks your users out of your application until the identity provider's max authentication age has passed.)

Related

401 sent to angular frontend by spring boot backend after successful oauth2 authetication with google

Spring Boot rest api in the back and angular in the front.
Hi all, I have a problem after successful oauth2 authentication with google.
In srping boot debug I can read the following:
o.s.web.cors.DefaultCorsProcessor : Skip: response already contains "Access-Control-Allow-Origin".
Then a 401 is sent to angular with full authentication required to access /api/user/ resource which is the root to access user details in the backend side.
WebConfig.java
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
#Configuration
public class WebConfig implements WebMvcConfigurer {
private final long MAX_AGE_SECS = 3600;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOrigins("*")
.allowedMethods(
"HEAD",
"OPTIONS",
"GET",
"POST",
"PUT",
"PATCH",
"DELETE"
)
.maxAge(MAX_AGE_SECS);
}
#Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
#Bean
public LocaleResolver localeResolver() {
final CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
cookieLocaleResolver.setDefaultLocale(Locale.ENGLISH);
return cookieLocaleResolver;
}
#Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
}
SecurityConfig.java
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.endpoint.DefaultAuthorizationCodeTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.client.RestTemplate;
import com.springboot.dashboard.security.jwt.TokenAuthenticationFilter;
import com.springboot.dashboard.security.oauth2.DashBoardOAuth2UserService;
import com.springboot.dashboard.security.oauth2.DashBoardOidcUserService;
import com.springboot.dashboard.security.oauth2.HttpCookieOAuth2AuthorizationRequestRepository;
import com.springboot.dashboard.security.oauth2.OAuth2AccessTokenResponseConverterWithDefaults;
import com.springboot.dashboard.security.oauth2.OAuth2AuthenticationFailureHandler;
import com.springboot.dashboard.security.oauth2.OAuth2AuthenticationSuccessHandler;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private DashBoardOAuth2UserService dashBoardOAuth2UserService;
#Autowired
private DashBoardOidcUserService dashBoardOidcUserService;
#Autowired
private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
#Autowired
private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf()
.disable()
.formLogin()
.disable()
.httpBasic()
.disable()
.exceptionHandling()
.authenticationEntryPoint(new RestAuthenticationEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/", "/error", "/api/all", "/api/auth/**", "/oauth2/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.authorizationEndpoint()
.authorizationRequestRepository(cookieAuthorizationRequestRepository())
.and()
.redirectionEndpoint()
.and()
.userInfoEndpoint()
.oidcUserService(dashBoardOidcUserService)
.userService(dashBoardOAuth2UserService)
.and()
.tokenEndpoint()
.accessTokenResponseClient(authorizationCodeTokenResponseClient())
.and()
.successHandler(oAuth2AuthenticationSuccessHandler)
.failureHandler(oAuth2AuthenticationFailureHandler);
// Add our custom Token based authentication filter
http.addFilterBefore(
tokenAuthenticationFilter(),
UsernamePasswordAuthenticationFilter.class
);
}
#Bean
public TokenAuthenticationFilter tokenAuthenticationFilter() {
return new TokenAuthenticationFilter();
}
/*
* By default, Spring OAuth2 uses
* HttpSessionOAuth2AuthorizationRequestRepository to save the authorization
* request. But, since our service is stateless, we can't save it in the
* session. We'll save the request in a Base64 encoded cookie instead.
*/
#Bean
public HttpCookieOAuth2AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
return new HttpCookieOAuth2AuthorizationRequestRepository();
}
// This bean is load the user specific data when form login is used.
#Override
public UserDetailsService userDetailsService() {
return userDetailsService;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> authorizationCodeTokenResponseClient() {
OAuth2AccessTokenResponseHttpMessageConverter tokenResponseHttpMessageConverter = new OAuth2AccessTokenResponseHttpMessageConverter();
tokenResponseHttpMessageConverter.setTokenResponseConverter(
new OAuth2AccessTokenResponseConverterWithDefaults()
);
RestTemplate restTemplate = new RestTemplate(
Arrays.asList(
new FormHttpMessageConverter(),
tokenResponseHttpMessageConverter
)
);
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
tokenResponseClient.setRestOperations(restTemplate);
return tokenResponseClient;
}
}
Thanks in advance for your help.
oauth2 login successful cause user data is successfully to database, but can access to full authentication resource.
WebSecurityConfigurerAdapter is deprecated, don't use it (it is not even there any more in spring-boot 3). Expose a SecurityFilterChain bean instead:
#Bean
SecurityFilterChain filterChain(HttpSecurity http) {
// http configuration
return http.build();
}
Resource-server (REST API)
Instead of writing all of spring-boot-starter-oauth2-resource-server security configuration in java #Configuration (CSRF, CORS, JWT decoder or token introspector, authorities mapping, public routes), you can use one of the spring-boot starters here:
<dependency>
<groupId>com.c4-soft.springaddons</groupId>
<!-- replace "webmvc" with "weblux" if your app is reactive -->
<!-- replace "jwt" with "introspecting" to use token introspection instead of JWT decoding -->
<artifactId>spring-addons-webmvc-jwt-resource-server</artifactId>
<!-- this version is to be used with spring-boot 3.0.0-RC2, use 5.x for spring-boot 2.6.x or before -->
<version>6.0.5</version>
</dependency>
#EnableMethodSecurity
public static class WebSecurityConfig { }
com.c4-soft.springaddons.security.issuers[0].location=https://localhost:8443/realms/master
com.c4-soft.springaddons.security.issuers[0].authorities.claims=realm_access.roles,ressource_access.client-id.roles
com.c4-soft.springaddons.security.cors[0].path=/**
Client (Angular app)
Use an OAuth2 client library. My favorite for Angular is angular-auth-oidc-client. It will save you tones of efforts to:
redirect users to authorisation-server for login
handle redirect back from authorization-server with authorization-code
exchange authorization-code for tokens (access-token of course, but also refresh and ID tokens if you requested offline_access and openid scopes)
auto-refresh access tokens before it expires (if you got a refresh-token)
automatically authorize request matching configured patterns (add Authorization Bearer header with access-token)
provide with Angular route guards
...
Authorization-server
Unless you deploy your resource-server to Google cloud, it is likely it can't use Google authorization-server directly. You might use an other authorization-server capable of identity federation in front of it. Keycloak does it pretty well:
run a Keycloak instance and configure it with Google as identity provider
configure your resource-server to use Keycloak as authorization-server (as done in code above)
configure Angular to use Keycloak as authorization-server too
I refer to Keycloak here, but most serious OIDC providers (either on premize or SaaS like Auth0, Okta, etc.) support "social" login and will allow Google users to login (as well as Facebook, Github, Tweeter, etc.)

Spring security configuration does not apply with Spring SimpleUrlHandlerMapping

I am writing a spring boot application in which I am registering a URL to a bean via the SimpleUrlHandlerMapping configuration. Why am I not using the #Controller or #RequestMapping classes to do this ?!! Because I want to dynamically register URL's during runtime.
I am using the following code to register a simple URL to a controller
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MAX_VALUE - 2);
Properties urlProperties = new Properties();
urlProperties.put("/index", "myController");
mapping.setMappings(urlProperties);
return mapping;
}
The above code is working fine, I am able to hit the controller bean registered with the name "myController".
The issue appears when I use spring security. I introduced spring security and configured InMemoryAuthentication, and set my configuration as follows.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index").permitAll()
.anyRequest()
.permitAll();
}
After doing this when I try to access /index path, it throws a 403, forbidden error. I have tried with permitAll() and fullyAuthenticated() configurations. It doesn't seem to work. However, any Controller class registered with the #Controller and #RequestMapping annotations are perfectly working fine with Security.
So, my assumption is that Spring Security is not aware of the dynamically registered URL's via the SimpleUrlHandlerMapping.
How do I solve this ? Is there a way I can tell spring security to include my dynamic URL registrations ? Unable to find any article on this online.
Suggestions and help much appreciated.
UPDATE:
Why csrf().disable() does works
CSRF stands for Cross Site Request Forgery
In simple words, it is one kind of token that is sent with the request to prevent the attacks. In order to use the Spring Security CSRF protection, we'll first need to make sure we use the proper HTTP methods for anything that modifies the state (PATCH, POST, PUT, and DELETE – not GET).
CSRF protection with Spring CookieCsrfTokenRepository works as follows:
The client makes a GET request to Server (Spring Boot Backend), e.g. request for the main page
Spring sends the response for GET request along with Set-cookie header which contains securely generated XSRF Token
The browser sets the cookie with XSRF Token
While sending a state-changing request (e.g. POST) the client (might be angular) copies the cookie value to the HTTP request header
The request is sent with both header and cookie (browser attaches the cookie automatically)
Spring compares the header and the cookie values, if they are the same the request is accepted, otherwise, 403 is returned to the client
The method withHttpOnlyFalse allows angular to read XSRF cookie. Make sure that Angular makes XHR request with withCreddentials flag set to true.
For more details, you may explore the following
Will Spring Security CSRF Token Repository Cookies Work for all Ajax Requests Automatically?
AJAX request with Spring Security gives 403 Forbidden
Basic CSRF Attack Simulation & Protection with Spring Security
Updated method configure(HttpSecurity http)
http
.csrf()
.ignoringAntMatchers("endpoint-to-be-ignored-for-csrf")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/index").permitAll()
.anyRequest().authenticated();
Endpoint specified in antMatchers with permitAll() should not required authentication and antMatchers("/index").permitAll() should work fine.
Make sure your security configuration class is annotated with #EnableWebSecurity and #EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
The security configuration class is in follows the package structure and scanned by Spring. spring-component-scanning
You may find the minimal working example here
SecurityConfiguration.java
import org.springframework.context.annotation.Bean;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// https://stackoverflow.com/a/56389047/10961238 -> WebSecurity vs HttpSecurity
// Add this method if .antMatchers("/index").permitAll() does not work
#Override
public void configure(WebSecurity web) throws Exception {
web.debug(true);
// web
// .ignoring()
// .antMatchers("/index");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/index").permitAll() //commenting this line will be results in 403
.anyRequest().authenticated();
}
}
SampleController.java
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#Controller("myController")
public class SampleController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("::::::::::::::::::::::::::::::::Controller:::::::::::::::::::::::::::::::::");
response.getWriter().print("Hello world!");
return null;
}
}
MainApplication.java
import com.example.mappings.controller.SampleController;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import java.util.Properties;
#SpringBootApplication
public class MappingsApplication {
public static void main(String[] args) {
SpringApplication.run(MappingsApplication.class, args);
}
#Bean
public SimpleUrlHandlerMapping sampleServletMapping() {
System.out.println("::::::::::::::::::::::::::::::::SimpleUrlHandlerMapping:::::::::::::::::::::::::::::::::");
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Integer.MAX_VALUE - 2);
Properties urlProperties = new Properties();
urlProperties.put("/index", sampleController());
mapping.setMappings(urlProperties);
return mapping;
}
#Bean
public SampleController sampleController() {
System.out.println("::::::::::::::::::::::::::::::::Setting SampleController:::::::::::::::::::::::::::::::::");
return new SampleController();
}
}
application.properties
spring.security.user.name = user
spring.security.user.password = user
spring.security.user.roles = ADMIN

Spring Security WebFlux IP Whitelist

In the latest Spring Security which leverages WebFlux, the security config works like below,
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange().pathMatchers("/**") ....
Before there is a method hasIpAddress("xxx.xxx.xxx.xxx") we can use to config IP whitelist, now it's gone.
How to specify IP whitelist for new Spring Security Webflux?
Based on idea from #özkan pakdil below, here is my code, but IP filter does not work - The request from IP which is not on whitelist still can go through.
private Mono<AuthorizationDecision> isAuthorizedIP(Mono<Authentication> authentication, AuthorizationContext context) {
String ip = context.getExchange().getRequest().getRemoteAddress().getAddress().toString().replace("/", "");
return authentication.map((a) -> new AuthorizationDecision(
ipWhiteList.contains(ip)));
}
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) throws Exception {
http.authorizeExchange().anyExchange().access(this::isAuthorizedIP).and().oauth2Login();
return http.build();
}
Took me a while to figure out but finally, I found a way it works. please check https://github.com/ozkanpakdil/spring-examples/tree/master/webflux-ip-whitelist and tell me if that does not help.
simply you can define WebSecurityConfig like this
import org.springframework.context.annotation.Bean;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
#EnableWebFluxSecurity
public class WebSecurityConfig {
ArrayList<String> whiteListIp = new ArrayList();
public WebSecurityConfig() {
whiteListIp.add("0:0:0:0:0:0:0:1");
whiteListIp.add("192.168.1.1");
whiteListIp.add("127.0.0.1");
}
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.anyExchange()
.access(this::whiteListIp)
.and()
.httpBasic();
return http.build();
}
private Mono<AuthorizationDecision> whiteListIp(Mono<Authentication> authentication, AuthorizationContext context) {
String ip = context.getExchange().getRequest().getRemoteAddress().getAddress().toString().replace("/", "");
return authentication.map((a) -> new AuthorizationDecision(a.isAuthenticated()))
.defaultIfEmpty(new AuthorizationDecision(
(whiteListIp.contains(ip)) ? true : false
));
}
}
and have your IP whitelisted.

Spring security always returning 403

Can someone tell me why this code is always returning 403?
I mapped /login to trigger the security login but it is not working properly.
package esercizio.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("q#q").password("pluto").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").anonymous()
.antMatchers("/auth/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.jsp")
.defaultSuccessUrl("/auth/list-student")
.failureUrl("/errorPage")
.and()
.logout().logoutSuccessUrl("/login.jsp");
}
}
It should let anyone in if the URL doesn't start with /auth, I don't know why it doesn't happen.
I think, you must prepend 'ROLE_' to you authority like ROLE_USER.
For more visit :
Spring Security always return the 403 accessDeniedPage after login

Add CSS file to Spring Boot + Spring Security Thymeleaf file

I wanted to add CSS file to my HTML file.
The problem appeared when I tried to add CSS to Spring Security application (I work on basic Spring Getting Started Content). I blame Spring Security because without it the CSS file loads properly.
Application.java file:
package mainpack;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Application {
public static void main(String[] args) throws Throwable {
SpringApplication.run(Application.class, args);
}
}
MvcConfig.java file:
package mainpack;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/home").setViewName("home");
registry.addViewController("/").setViewName("home");
registry.addViewController("/hello").setViewName("hello");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/register").setViewName("register");
registry.addViewController("/whatever").setViewName("whatever");
}
}
WebSecurityConfig.java file:
package mainpack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/index", "/register", "../static/css", "../static/images").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
I load CSS with line:
<link href="../static/css/index.css" th:href="#{/css/index.css}" rel="stylesheet" />
in index.html file.
Your pattern ../static/css is not matching your relative URL ../static/css/index.css, see AntPathMatcher:
PathMatcher implementation for Ant-style path patterns.
Part of this mapping code has been kindly borrowed from Apache Ant.
The mapping matches URLs using the following rules:
? matches one character
* matches zero or more characters
** matches zero or more directories in a path
{spring:[a-z]+} matches the regexp [a-z]+ as a path variable named "spring"
and Spring Boot Reference:
By default, resources are mapped on /** but you can tune that via spring.mvc.static-path-pattern.
Your request will be redirected to login form, because your are not logged in and all other requests need authentication.
To fix it, change your pattern to /css/** and /images/**.
A better solution for static resources is WebSecurity#ignoring:
Allows adding RequestMatcher instances that Spring Security should ignore. Web Security provided by Spring Security (including the SecurityContext) will not be available on HttpServletRequest that match. Typically the requests that are registered should be that of only static resources. For requests that are dynamic, consider mapping the request to allow all users instead.
Example Usage:
webSecurityBuilder.ignoring()
// ignore all URLs that start with /resources/ or /static/
.antMatchers("/resources/**", "/static/**");
The web.ignore()worked the best for me. just add the following method to your WebSecurityConfig class.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/img/**", "/icon/**");
}
.antMatchers("/**/*.js", "/**/*.css").permitAll();
This allows all the js and css files present in resources/static folder to be permitted for request access.

Resources