access static content in secured Spring Boot application - spring

I have a standalone Spring Boot application with templates in /src/main/resources/templates and static content in /src/main/resources/static. I would like the static content to be accessible before authentication, so the CSS loads on the login page as well. Now it only loads after authentication. My security configuration looks like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = Logger.getLogger(SecurityConfig.class);
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.inMemoryAuthentication()
...
} catch (Exception e) {
logger.error(e);
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.defaultSuccessUrl("/projects", true)
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/static/**").permitAll()
.anyRequest().authenticated();
}
}

The static content in classpath:/static is served at the root of the application (i.e. /*), whether or not the application is secure, so you need to match on specific paths underneath the root. Spring Boot permits all access by default to /js/**, /css/**, /images/** (see SpringBootWebSecurityConfiguration for details), but you may have switched that off (can't see the rest of your code).

Related

Spring security how to allow root url without intefering with security 'below' the root

I have REST services and static pages, both delivered by my Spring Boot application.
The application action is to be reached under /myapp, while under /myapp/api there are services that are protected by a filter.
The filter expects a cookie.
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**")
.permitAll()
.and()
.addFilter(new CookieFilter(...));
}
The unprotected pages in the 'root-context (/myapp) have no cookie.
How can I configure that the static pages are 'ignored' by Spring security? While the REST endpoints below the static pages are checked by security?
When I try to configure the static pages for 'exclusion' via Web Security, all REST endpoints under /myapp/api are ignored as well
#Override
public void configure(final WebSecurity web) {
web.ignoring()
.antMatchers("/");
}
If I configure a permitAll():
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll();
http.authorizeRequests()
.antMatchers("/api/**")
.permitAll()
.and()
.addFilter(new CookieFilter(...));
}
Spring security complains that the static pages can not be checked by my security filter, so the authorization is performed.
This will make anything under /api require authentication and let everything else through.
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.anyRequest().permitAll()
.and()
.addFilter(new CookieFilter(...));

Spring Boot Security Authentication: Application having 2 different domain URL and need to authenticate with Spring Security

I need help with one of the issue that I am facing with Spring Boot Security. I have application which has 2 different Urls.(Infoblock CNAME)
domain1.com
domain2.com
both Url are point to the same application.
Due to business reason we need 2 different Url and we are planning to land on diff page based on the URL entered in browser. Issue is with Spring Security AntMatcher.
With AntMatcher we can only provide path but how we can address the domain with it.
Could you please guide me.
Thanks in Advance.
Instead of AntMatcher you can use
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.1:8080"))
with any other matcher from org.springframework.security.web.util.matcher package.
Here is an example:
#EnableWebSecurity
#Configuration
public static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public static class SecConfig1 extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.1:8080"))
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin();
}
}
#Configuration
#Order(2)
public static class SecConfig2 extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new RequestHeaderRequestMatcher("Host", "127.0.0.2:8080"))
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//default deny all
http.authorizeRequests().anyRequest().denyAll();
}
}

spring security + spring boot mvc index page before authentication looks like bare html

Before auth
After i log in by any account
Does anyone know what's the matter? No clue.
Seems like your css is not loading for unsecured context. For adding the resources make resource handler entry as below in WebMvcConfigurer
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!registry.hasMappingForPattern(URL_PATTERN_UICONTENT)) {
registry.addResourceHandler(URL_PATTERN_UICONTENT).addResourceLocations("classpath:/uicontent/").setCachePeriod(31556926);
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
Problem has been resolved!
I created class
#Configuration
#EnableWebMvc
public class WebMVCConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}
This way, I say /static/** if any page request by this prefix, so try to find in classpath:static
In my index thymeleaf file i including external css file by:
<link href="../static/css/bootstrap.min.css" th:href="#{static/css/bootstrap.min.css}" rel="stylesheet" />
This example above is shows how to add route where is app should find static resources, but this not necessary actually in my project.
The thing is when you trying to access to static resources before you logged in, you should give the permission to it in WebSecurityConfig class, like this:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/index", "/login","/css/**", "/webjars/**", "/images/**", "/js/**").permitAll()
.antMatchers("/subscribers", "/calldetails").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
.antMatchers("/divisions").access("hasAnyRole('ROLE_ADMIN')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();

Providing custom OAuth2AccessTokenResponseClient to spring

I have a demo spring boot app and I would like to configure oauth login as well my own custom token response client.
This is my configuration:
#Configuration
#EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.and()
.oauth2Client()
.authorizationCodeGrant()
.accessTokenResponseClient(customAccessTokenResponseClient());
}
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> customAccessTokenResponseClient() {
DefaultAuthorizationCodeTokenResponseClient client = new DefaultAuthorizationCodeTokenResponseClient();
client.setRequestEntityConverter(new CustomOAuth2AuthorizationCodeGrantRequestEntityConverter());
return client;
}
}
The login flow is working find, but it looks like my custom token response client is not getting registered. I put a break point in there, but the flow doesn't go through it. It looks like it is still using the defaults.
Am I missing something here or is the order wrong?
Figured out the issue.
The right way to configure is the following:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2Login()
.tokenEndpoint()
.accessTokenResponseClient(customAccessTokenResponseClient());
}

Spring Security: Multiple http elements with Multiple AuthenticationManagers

I am struggling with Java Config for Spring Security. I have multiple entry points but I cannot get the AuthenticationManagers provisioned correctly.
My first configuration file is like this:
#Configuration
#EnableWebSecurity
#Order(100)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.antMatcher("/service/**")
.addFilterAfter(requestHeaderAuthenticationFilter(), SecurityContextPersistenceFilter.class)
.authorizeRequests()
.antMatchers("/service/**").authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.csrf().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(preAuthenticatedAuthenticationProvider(null));
}
#Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception
{
// Takes the value of the specified header as the user principal
RequestHeaderAuthenticationFilter filter = new RequestHeaderAuthenticationFilter();
filter.setPrincipalRequestHeader("SECRET_HEADER");
filter.setAuthenticationManager(authenticationManager());
filter.setExceptionIfHeaderMissing(false);
return filter;
}
This all works correctly. When I set a breakpoint in the RequestHeaderAuthenticationFilter I see an AuthenticationManager with one AuthenticationProvider, and that is the preAuthenticatedAuthenticationProvider (not shown because is just a regular old bean).
I also have a special security chain for admin users and the like:
#Configuration
#Order(101)
public class AdminSecurity extends WebSecurityConfigurerAdapter
{
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authenticationProvider(mainSiteLoginAuthenticationProvider())
.authorizeRequests()
.antMatchers("/public/**").permitAll()
.antMatchers("/admin/**").access("SECRET ADMIN ACCESS EXPRESSION")
.antMatchers("/internal/**").access("SECRET INTERNAL ACCESS EXPRESSION")
.anyRequest().permitAll()
.and()
.formLogin()
.defaultSuccessUrl("/admin/thing")
.loginPage("/login")
.loginProcessingUrl("/do_login")
.defaultSuccessUrl("/admin/thing")
.failureUrl("/login?error=true")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.and()
.exceptionHandling()
//.authenticationEntryPoint(null) // entry-point-ref="loginEntryPoint"
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // create-session="ifRequired"
.and()
.csrf().disable();
}
This is now working (after a lot of struggle), but if I put a breakpoint in the UsernamePasswordAuthenticationFilter, I see that this filter has a different AuthenticationManager instance, which is provisioned with the mainSiteLoginAuthenticationProvider as expected. However, it has a parent AuthenticationManager which is provisioned with the default DaoAuthenticationProvider that generates a temporary password in the logs:
Using default security password: 47032daf-813e-4da1-a224-b6014a705805
So my questions are:
How can I get both security configs to use the same AuthenticationManager? I thought that the SecurityConfig, being order 100, would create one, and then AdminConfig, being 101, would just use it. But I have been unable to get them to use the same AuthenticationManager.
Failing that, how can I prevent the AuthenticationManger of AdminConfig from generating a parent that has the default DaoAuthenticationProvider?
I am using Spring Boot 1.5.9.RELEASE, which means Spring Security 4.2.3.RELEASE.

Resources