Security configuration with Spring-boot - java

I created a Spring Security configuration class for Spring-Boot. My login page has resources css, js and ico files. The resources are getting denied for security reasons and redirected to login page each time. Why does EnableWebMVCSecurity not add the Classpath resource location. After changing the code as in the second snippet the I Classpath resource location is added. dont understand what I am missing for the resources in the first code snippet.
#Configuration
/*
* Enable Spring Security’s web security support and provide the Spring MVC integration
* It also extends WebSecurityConfigurerAdapter and overrides a couple of its methods to set some specifics of the web security configuration.
*/
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* The configure(HttpSecurity) method defines with URL paths should be
* secured and which should not.
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated();
// There is a custom "/login" page specified by loginPage(), and everyone
// is allowed to view it.
http
.formLogin()
.loginPage("/login.html")
.permitAll()
.and()
.logout()
.permitAll().logoutSuccessUrl("/login.html");
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
// As for the configure(AuthenticationManagerBuilder) method, it sets up
// an in-memory user store with a single user. That user is given a
// username of "user", a password of "password", and a role of "USER".
auth
.inMemoryAuthentication()
.withUser("user#domain.com").password("password").roles("USER");
}
}
I got this working by changing the code to
#Configuration
/*
* Enable Spring Security’s web security support and provide the Spring MVC integration
* It also extends WebSecurityConfigurerAdapter and overrides a couple of its methods to set some specifics of the web security configuration.
*/
public class WebSecurityConfig{
#Bean
public ApplicationSecurity applicationSecurity() {
return new ApplicationSecurity();
}
#Bean
public AuthenticationSecurity authenticationSecurity() {
return new AuthenticationSecurity();
}
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class ApplicationSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated();
http
.formLogin()
.loginPage("/login.html")
.permitAll()
.and()
.logout()
.permitAll().logoutSuccessUrl("/login.html");
}
}
#Order(Ordered.HIGHEST_PRECEDENCE + 10)
protected static class AuthenticationSecurity extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user#domain.com").password("password").roles("USER");
}
}
}
After changing the code I noticed that the Ignore paths were added to the filter and I see the following in logs:
[ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/css/**'], []
[ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/js/**'], []
[ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/images/**'], []
[ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: Ant [pattern='/**/favicon.ico'], []
[ost-startStop-1] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#4e3e0069, org.springframework.security.web.context.SecurityContextPersistenceFilter#3d2dd0cf, org.springframework.security.web.header.HeaderWriterFilter#33fc3b02, org.springframework.security.web.csrf.CsrfFilter#9b7a3ac, org.springframework.security.web.authentication.logout.LogoutFilter#267237ef, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#129495ef, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter#7db0a467, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#764d1dbd, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#25a5268d, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#15c01d0c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#37818a3b, org.springframework.security.web.session.SessionManagementFilter#3fe57e49, org.springframework.security.web.access.ExceptionTranslationFilter#4278af59, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#424bef91]

Per the docs you have disabled the spring boot autoconfig in the first example by using #EnableWebSecurity, so you would have to explicitly ignore all the static resources manually. In the second example you simply provide a WebSecurityConfigurer which is additive on top of the default autoconfig.

Create a Configuration file that extends WebSecurityConfigurerAdapter and annotate the class with #EnableWebSecurity
You can override methods like configure(HttpSecurity http) to add basic security like below
#Configuration
#EnableWebSecurity
public class AppWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.anyRequest().permitAll();
}
}

Add below method to by pass security for css and js in security config -
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/** **","/js/** **");
}

Related

how to configure spring security for spring boot project

I'm trying to make a web application that uses:
SpringBoot,
Mysql,
JDBC
, MVC, DAO
Thymeleaf,
IntelliJ
And I'm trying to figure out how Spring security works (which I'm having a lot of difficulty with).
My views are organized as follows:
resources(folder): - ________static(folder)
|____templates(folder):__________images(folder)
|___userOnly(folder):_____header.html
| |__help.html
| |__menu.html
| |__newDocForm.html
| |__profil.html
|
|__firstPage.html
|__header.html
|__home.html
|__index.html
|__inscriptionForm.html
|__loginPage.html
I would like to do that unidentified users can access all views except those contained in "userOnly" and that my "loginPage" page is used as the login page.
If I understood correctly, I must create a class that inherits from "WebSecurityConfigurerAdapter".
What I have done.
And then configure "configure", which I can't do correctly :(
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/userOnly/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage.html");
}
}
Sorry if my questions seems strange but english is not my first language
As of Spring-Boot 2.7 the use of WebSecurityConfigurerAdapter is deprecated. If you're using Spring-Boot 2.6 or older the other answers might suit you better.
To my best knowledge the recommended way for defining security config in Spring-Boot 2.7 is as follows:
#Configuration
public class WebSecurityConfig
{
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
{
// #formatter:off
http.authorizeRequests()
.mvcMatchers("/userOnly/**").permitAll()
.anyRequest().permitAll();
http.formLogin()
.permitAll()
.loginPage("/loginPage.html");
http.logout()
.permitAll();
// #formatter:on
return http.build();
}
}
The use of web.ignoring() in the answer from voucher_wolves is, I believe, not recommended, instead one should add those cases to http.mvcMatcher().permitAll().
On a side note, I would personally recommend whitelisting the public pages and adding authentication to everything else, (for example a public folder). This way if you forget to add security to a link it's not public by default.
You need to tell Spring security what URL are public with something like this -
#Configuration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String[] PUBLIC_URLS = {"/public/*"};
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/userOnly/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/loginPage.html");
}
#Override
public void configure(WebSecurity web) {
List<RequestMatcher> matchers =
Arrays.asList(urls).stream().map(url -> new
AntPathRequestMatcher(url)).collect(Collectors.toList());
web.ignoring().requestMatchers(new OrRequestMatcher(matchers));
}
}
With OrRequestMatcher , you can create list of all URLs which you need to be public.
You can also use NegatedRequestMatcher to get all the private URL
RequestMatcher privateUrlMatcher = new
NegatedRequestMatcher(publicUrlMatcher);
I also suggest you to keep all public url under /src/main/resources/static/publicui and all private under /src/main/resources/static/privateui and have public permission for /publicui/*
try the following in your SecSecurityConfig class
#Configuration
#EnableAutoConfiguration
#EnableWebSecurity
public class SecSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/users").authenticated()
.anyRequest().permitAll()
.and()
.formLogin()
.usernameParameter("email")
.defaultSuccessUrl("/lib/allBooks")
.permitAll()
.and()
.logout().logoutSuccessUrl("/lib").permitAll();
http
.csrf().disable();
}
}
Just modify the parameters set for your application. if you don't have login form yo can skip
.usernameParameter("email")
.defaultSuccessUrl("/lib/allBooks")
.permitAll()

How do I enable OAuth2 for only certain classes in my Spring Boot Security OAuth2 app?

I followed this guide to add OAuth2
https://spring.io/guides/tutorials/bookmarks/#_securing_a_rest_service
But now it's requiring authentication for every single page!
$ curl -s http://localhost:8080/login
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
I only want to use OAuth2 on the API in one specific class. I tried reading the reference for Spring Boot
https://docs.spring.io/spring-boot/docs/1.5.14.BUILD-SNAPSHOT/reference/htmlsingle/#boot-features-security
But it wasn't helpful at all! It gave 0 examples.
To customize it you normally use external properties and beans of type WebSecurityConfigurerAdapter (e.g. to add form-based login).
All of the above can be switched on and off or modified using external properties (security.*). To override the access rules without changing any other auto-configured features add a #Bean of type WebSecurityConfigurerAdapter with #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) and configure it to meet your needs.
How do you customize it?! Which properties?! How do you configure to meet your needs?!
I tried setting application.properties
security.basic.enabled = false
security.ignored = /login
But it still requires OAuth2 authentication. I want to only enable OAuth2 for the class IShortUrlApiInteface and disable it for all other #Controllers.
Create a new class, extend ResourceServerConfigurerAdapter, and override method configure(HttpSecurity).
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
String [] ignoredPaths = new String[]{
"/robots.txt", "/error", "/login", "/doLogut", "/home", "/pageNotFound",
"/css/**", "/js/**", "/fonts/**", "/img/**", ...
};
#Override
public void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers(ignoredPaths).permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
In your case, you need to set the permission for login URI.
If you are in micro service architecture, you need create resource configuration in every project/service.
security.oauth2.resource.user-info-uri defines authorization service URI
clientId defines ur actual client id
In oauth For every resource server need to create unique resource-id
Below is the example for resource server.
#Configuration
#EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
#Value("${security.oauth2.resource.user-info-uri}")
private String userInfoUri;
#Value("${client-id}")
private String clientId;
#Override
public void configure(final ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("ig-user");
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/v1/user/activate/**").permitAll()//
.antMatchers("/api/v1/user/access/check/**").permitAll()//
.antMatchers("/api/v1/profile/exists/**").permitAll()//
.antMatchers("/api/v1/user/sign-up/**").permitAll()//
.antMatchers("/download/**").permitAll()//
.anyRequest().authenticated();
}
#Primary
#Bean
public UserInfoTokenServices tokenService() {
final UserInfoTokenServices tokenService = new UserInfoTokenServices(userInfoUri, clientId);
return tokenService;
}
}

Spring Security with JWT

I am trying to develop Spring Security project with JWT.
I want access Login api with out Spring Security (without JWT token). But with below configuration, every time (for login api as well) it is checking for JWT token giving me 403 error.
Below is my WebSecurityConfig.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthFilter jwtAuthFilter;
#Autowired
private TokenAuthenticationService jwtAuthenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(jwtAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().ignoringAntMatchers("/api/v1/login");
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/api/v1/login")
.permitAll()
.and()
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Thanks in advance
For login path configuration something like this can be used:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin()
.usernameParameter("username") // default is username
.passwordParameter("password") // default is password
.loginPage("/authentication/login") // default is /login with an HTTP get
.failureUrl("/authentication/login?failed") // default is /login?error
.loginProcessingUrl("/authentication/login/process"); // default is /login
// with an HTTP
// post
}
If some paths need to be ignored configure(WebSecurity web) can be overridden:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/v1/somepath").antMatchers("/static/**");
}
There is filter class named JwtAuthFilter that is being executed before every service you call.
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class)
this code provides to be executed filter before every request, but its okay, you have to see this FilterClass there must be some check if token doesnt exist filter class must be returned and request will directly go to the login service. if you can show that Filter class and I will help you.

Spring REST security - Secure different URLs differently

I have working REST API under Spring 4 using Basic authentication. These REST services are under /api/v1/** URL. However, I want to add another set of REST endpoints under different url /api/v2/**, but protected with token-based authentication.
Is it possible to do this with one servlet ? How to configure Spring Security to use different forms of authentication for different URLs ?
Thank you.
Here's a code sample in Java config that uses UserDetailsService and has different security configurations for different URL endpoints:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/v1/**")
.httpBasic()
.realmName("API")
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/v1/**").authenticated();
}
}
#Configuration
#Order(2)
public static class ApiTokenSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/v2/**")
/* other config options go here... */
}
}
}

Failing to configure two HttpSecurity setups with JavaConfig

I have followed the advice from the official documentation on how to configure two separate HttpSecurity instances:
#Configuration
#EnableWebSecurity
public class SoWebSecurityConfig
{
#Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(username -> {
log.info("\n\n\n ********* authenticating {} ************************************\n\n\n", username);
return new User(username, "", asList(new SimpleGrantedAuthority("TV")));
});
}
#Configuration
#Order(1)
public static class SwiperSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception { configureHttpSec(http, "/swiper"); }
}
#Configuration
#Order(2)
public static class TvSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception { configureHttpSec(http, "/tv"); }
}
static HttpSecurity configureHttpSec(HttpSecurity http, String urlBase) throws Exception {
http .csrf().disable()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and() .authorizeRequests().antMatchers(urlBase+"/**").authenticated()
.and() .httpBasic()
.and() .logout().logoutUrl(urlBase+"/logout").logoutSuccessHandler((req,resp,auth) -> {})
;
return http;
}
}
In the logs I do see two filter chains being created:
2014-06-30 12:44:22 main INFO o.s.s.w.DefaultSecurityFilterChain - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.as
ync.WebAsyncManagerIntegrationFilter#806996, org.springframework.security.web.context.SecurityContextPersistenceFilter#1937eaff, org.springframework.security.web.header.HeaderWriterFilter#71e4b308, org.springfr
amework.security.web.authentication.logout.LogoutFilter#1d1cbd0f, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#9b9a327, org.springframework.security.web.savedrequest.RequestCach
eAwareFilter#4993febc, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#67064bdc, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#78b612c6, org.s
pringframework.security.web.session.SessionManagementFilter#6d11ceef, org.springframework.security.web.access.ExceptionTranslationFilter#6e7c351d, org.springframework.security.web.access.intercept.FilterSecurit
yInterceptor#571a01f9]
2014-06-30 12:44:22 main INFO o.s.s.w.DefaultSecurityFilterChain - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.as
ync.WebAsyncManagerIntegrationFilter#30c1da48, org.springframework.security.web.context.SecurityContextPersistenceFilter#427ae189, org.springframework.security.web.header.HeaderWriterFilter#4784efd9, org.spring
framework.security.web.authentication.logout.LogoutFilter#187e5235, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#514de325, org.springframework.security.web.savedrequest.RequestC
acheAwareFilter#16a9eb2e, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#76332405, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#43a65cd8, or
g.springframework.security.web.session.SessionManagementFilter#3fba233d, org.springframework.security.web.access.ExceptionTranslationFilter#376c7d7d, org.springframework.security.web.access.intercept.FilterSecu
rityInterceptor#3b48e183]
but only the one I designate with Order(1) will actually get used; the URLs matching the other one will not get authenticated.
I have also tried following the docs more closely, using anyRequest() instead of ant matchers for the #Order(2) configuration, but the result was the same.
What are my options to get around this problem?
I am using Spring 4.0.5, Spring Security 3.2.4.
You have failed to follow the documentation in one crucial aspect. You have
http.authorizeRequests().antMatchers(urlBase+"/**").authenticated()
which means that you register this HttpSecurity as a global security module, which applies to all URLs, but only requires authentication on those selected with the Ant matcher. When you do this twice, you end up with two chained global security modules, so naturally only the first one will be responsible for all URLs.
The documentation instead advises this:
http.antMatcher(urlBase+"/**").authorizeRequests().anyRequest().authenticated()
which means that the Ant matcher will used to select which URL this security module is responsible for, and bypass it for all others. This way the second module in line gets its chance when appropriate.
So all you need to do is slightly adjust your static configurer method to the following:
static HttpSecurity configureHttpSec(HttpSecurity http, String urlBase) throws Exception {
http .csrf().disable()
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
.and() .antMatchers(urlBase+"/**").authorizeRequests().anyRequest().authenticated()
.and() .httpBasic()
.and() .logout().logoutUrl(urlBase+"/logout").logoutSuccessHandler((req,resp,auth) -> {})
;
return http;
}

Categories