Spring boot security allow anonymous user
I am trying configure Spring Boot Security to allow anonymous user reach all URLs except one. By default user and generated security password by Spring.
I need just one page for maintanance application
I already tried a lot tips and tutorials.
1
2
3
4
And others.
But Spring still required authetification for all pages.
My current security config
#EnableWebSecurity
#Configuration
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest()
.anonymous()
.antMatchers("/secure")
.authenticated();
}
}
Web configuration
#Configuration
#EnableWebMvc
#EnableAsync
public class WebConf implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
WebMvcConfigurer.super.addResourceHandlers(registry);
registry.addResourceHandler("/webjars/**").addResourceLocations("/webjars/**");
}
#Bean
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(5);
executor.setQueueCapacity(500);
executor.setThreadNamePrefix("Asynchronous Process-");
executor.initialize();
return executor;
}
}
And main method
#ComponentScan
#SpringBootApplication
#EnableScheduling
public class MainServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MainServiceApplication.class, args);
}
}
I tried
.permitAll()
.anonymous()
without success.
Edit 1
Project structure
Project structure
Edit 2
Project structure
#ComponentScan()
#SpringBootApplication
#EnableScheduling
public class MainServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MainServiceApplication.class, args);
}
}
Login page
Solved by move config package. Spring did not scan configuration package.
You may need to change the order. Possible issue is antMatchers("/secure").authenticated() has no effect due to /secure endpoint will be considerd in the anyRequest(). Also make sure SecurityConf is in correct package as required for scanning.
#EnableWebSecurity
#Configuration
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/secure").authenticated()
.anyRequest().anonymous();
}
}
OR
#EnableWebSecurity
#Configuration
public class SecurityConf extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/secure").authenticated()
.anyRequest().permitAll();
}
}
UPDATE
You need to create a configs package inside cz.lh.main_service and SecurityConf and WebConf should be part of the cz.lh.main_service.configs
OR
You can use #ComponentScan and can specify the current package in which you have SecurityConf and WebConf
#ComponentScan(“your-config-package”)
Related
I'm trying to rewrite following class in order to get rid of the depricated WebSecurityConfigurerAdapter:
#EnableWebSecurity
public class MyWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity security) throws Exception {
security.mvcMatcher("/my/path/*").securityContext().disable();
}
}
And I've tried to rewrite this with the help of the official Spring documentation. The following two attempts resulted in 403 Errors when trying to access resources on that path:
#EnableWebSecurity
public class MyWebSecurityConfiguration {
#Bean
public SecurityFilterChain filterChain(HttpSecurity security) throws Exception {
security.mvcMatcher("/my/path/*").securityContext().disable();
return security.build();
}
}
#EnableWebSecurity
public class ConsentWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
public WebSecurityCustomizer webSecurityCustomizer() throws Exception {
return (web) -> web.ignoring().mvcMatchers("/v1/containers/*");
}
}
While in the original code everything is running
I also faced the same scenario of discarding the deprecated method and replacing it with SecurityFilterChain
if you want to disable the security on given path then try this:
security.mvcMatcher("/my/path/*").permitAll();
Edit: Here is my migrated code which worked fine with permitting every request without authentication.
#Configuration
#EnableWebMvc
public class SecurityConfig {
#Autowired
private UserDetailsService userDetailsService;
#Bean
protected SecurityFilterChain authorizationConfig(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.authorizeRequests()
.antMatchers("/login", "/post/**", "/newcomment/**", "/page/**","/api/","/api/posts/filter",
"/api/comments").permitAll();
return httpSecurity.build();
}
You can use below code for reference
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration {
private final String[] WHITE_LABEL_URLS = {"/blogapp", "/usercreation", "/css/**", "/saveuser", "/page/**"};
#Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.httpBasic()
.and()
.authorizeHttpRequests()
.antMatchers(WHITE_LABEL_URLS).permitAll()
.anyRequest().authenticated()
.securityContext().disable();
return httpSecurity.build();
}
}
I'm trying to build a microservice architecture. But i'm struggling since two days with OAuth2 and Zuul. I managed to run a Auth/Resource-Server on the same service, but not with Zuul. At the moment i'm swichting to another service, the authorization doesn't work anymore. I tried many guides (as an example Baeldung) but no one works for me. Probably because i'm using Spring Boot 2.0.3? Most guides using Spring Boot 1.5.x.
I think it's a problem of configuration. I'm using Eureka for service discovering, Zuul as Gateway and entry point. When the user request a protected service, he should be redirectet to my auth-service (OAuth2/JWT). The token he gets after login should be stored by Zuul (right ?). Actually Zuul doesn't get the token or doesn't store it. Do I have to do this by my own or should Zuul and OAuth manage this and I just have bad configurations? Could someone show me, how you configure this architecture or a new/working guide for Spring Boot 2.0.3? I'm actually really frustrated, need help. I'm new to Spring, but have to learn it for work. But at the moment i'm just overstrained.
Additional infos:
I didnt create any views now. I just defined some default controller which return Strings and are secured by #PreAuthorize.
Gateway-Service:
GatewayServiceApplication.java
#SpringBootApplication
#EnableZuulProxy
#EnableDiscoveryClient
#Configuration
public class GatewayServiceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayServiceApplication.class, args);
}
}
SecurityConfig.java
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/", "/core/", "/core/login**", "/oauth/authorize",
"/core/oauth/authorize", "/login")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin().permitAll();
}
}
Here I had a lot of different antMatchers.
application.properties
server.port=8000
spring.application.name=gateway-service
eureka.client.service-url.defaultZone=http://localhost:8001/eureka/
security.oauth2.sso.login-path=http://localhost:8000/core/login
security.oauth2.client.client-id=zuul
security.oauth2.client.client-secret=zuul
security.oauth2.client.access-token-uri=http://localhost:8000/core/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:8000/core/oauth/authorize
#security.oauth2.resource.user-info-uri=http://localhost:8000/core/user/me
security.oauth2.resource.user-info-uri=http://localhost:8000/core/secured
spring.thymeleaf.cache=false
I think here's a failure.
Core-Service
CoreApplication.java
#SpringBootApplication
#EnableDiscoveryClient
#EnableResourceServer
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
AuthServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
public void configure(
AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("zuul")
.secret(passwordEncoder.encode("zuul"))
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.autoApprove(true)
.redirectUris("http://localhost:8000/core/secured");
}
}
SecurityConfig
#Configuration
#Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john")
.password(passwordEncoder().encode("123"))
.roles("USER");
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
application.properties
server.port=8003
spring.application.name=core
eureka.client.service-url.defaultZone=http://localhost:8001/eureka
Ok, especially here I changed many things. So probably I destroyed much from older guides. (Sorry my english is bad!)
Below is my test class. The hello-world endpoint simply returns an HTML page containing text i.e. Hello Stranger!
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloWorldTest {
#Autowired
private HelloWorldController controller;
#Autowired
private TestRestTemplate restTemplate;
#LocalServerPort
private int port;
#Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
#Test
public void greetingShouldReturnDefaultMessage() throws Exception {
String baseUrl = "http://localhost:" + port;
assertThat(this.restTemplate.getForObject(baseUrl+"/hello-world", String.class))
.contains("Hello Stranger!");
}
}
This is my Security Config:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
It simply redirects all authenticated users to the login page
I have tried adding #WithMockUser annotation or adding another security config class in my test directory to override the default config. But so far nothing has seemed to work.
Any help or suggestions on documentation to read is appreciated!
Another way to do it that worked for me was to override the normal security configation for running the integration test like so:
#TestConfiguration
#Order(-101)
#EnableWebSecurity
class TestSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity security) throws Exception {
security.httpBasic().and().formLogin().disable();
}
}
I have managed to solve this issue by first creating another web security config without requiring login/authorization, then by adding #Profile to my config class and production/dev/test profile via application.properties in my test directory (i.e. adding "spring.profiles.active=test").
Not sure if this is the best way to solve this issue, but it works for now.
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... */
}
}
}
My spring boot application has an Application class. When I run it (as an application), it launches itself within an embedded servlet container (Tomcat, in my case). Somehow (through Application's #annotations, I suppose), WebSecurityConfig (extending WebSecurityConfigurerAdapter) in the same package is loaded.
WebSecurityConfig contains two important blocks of configuration information:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(prePostEnabled = true) // enables method-level role-checking
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userSearchBase("CN=Users,DC=some,DC=domain,DC=com")
.userSearchFilter("(sAMAccountName={0})")
.groupSearchBase("OU=Groups,DC=some,DC=domain,DC=com")
.groupSearchFilter("(member={0})")
.contextSource()
.managerDn("cn=ad-bind,cn=users,dc=some,dc=domain,dc=com")
.managerPassword("APASSWORD!")
.url("ldaps://some.domain.com:636");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("***************** WebSecurityConfig.configure *************************");
http.csrf().disable();
http
.headers()
.frameOptions()
.disable();
http
.authorizeRequests()
.antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/me")
.permitAll()
.and()
.logout()
.permitAll();
http.logout().logoutSuccessUrl("/me");
}
}
configureGlobal() contains the configuration for our internal LDAP system and it works just fine.
configure() specifies which URLs are public, which are only to be shown to logged-in users and which relative URLs to send users to as they log in.
Now I'm into integration testing and have written some methods to test controllers that do not require authentication. Those tests work as expected. The Application class fires up and the tests execute against it.
But now I want to test controller methods that DO require authentication. The way I think this is accomplished is by telling the test class to fire up an alternative Application class (TestApplication, in my case) and WebSecurityConfig that creates dummy users:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = TestApplication.class) // fires up with TestApplication.class instead of Application.class
#WebAppConfiguration
public class ProductControllerTests {
// test methods here, this time with username/password included
}
#Configuration
#EnableAutoConfiguration
public class TestApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<TestApplication> applicationClass = TestApplication.class;
}
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("testuser").password("userpass").roles("USER");
auth.inMemoryAuthentication().withUser("testadmin").password("adminpass").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("***************** WebSecurityConfig.configure *************************");
http.csrf().disable();
http
.headers()
.frameOptions()
.disable();
http
.authorizeRequests()
.antMatchers("/resources/images/*", "/me", "/products", "/product/**", "/offerings", "/offering/**", "/client/**")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/me")
.permitAll()
.and()
.logout()
.permitAll();
http.logout().logoutSuccessUrl("/me");
}
}
So my question is: When I execute the unit test class, I believe TestApplication is firing. However, it is NOT picking up the alternative WebSecurityConfig class and its auth.inMemoryAuthentication() test users. How do I force my application to use one WebSecurityConfig when running the application normally, but a different WebSecurityConfig when running the unit tests?
You can configure your TestApplication to include just the beans that you would like to test. In other words, make sure that your WebSecurityConfig is not part of the test configuration. If you read the javadoc of #SpringBootApplication you will notice that it is a composite annotation that consists of (among others) the #ComponentScan annotation. Consequently your Application and your TestApplication will perform a recursive scan from the package in which the class is located. The Spring reference docs has a specific chapter about Using filters to customize scanning.
Alternatively, if you are using Spring Security version 4 or greater you may find the additions of #WithMockUser and #WithUserDetails interesting.
In your security configuration class, add #Profile annotation to disable in unit test profile. like:
#Configuration
#Profile("!" + Constants.SPRING_PROFILE_UNITTEST)
public class WebSecurityConfig { ....}
And let your another security config for test just in test dir.