Spring permitAll() and ignorning() doesn't work - spring-boot

I'm trying to configure Spring-Boot 2 application with in-memory authorization and it drive me crazy...
I need to secure all resources except /news.
I have created this configuration beans following the Spring's docs but Spring Security isn't permit GET method on /news:
#Slf4j
#Configuration
#EnableWebSecurity
public class ApplicationAuthentication extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(HttpMethod.GET,"/news");
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER")
.and()
.withUser("admin")
.password("admin")
.roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/news")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}
I'm using spring-boot 2.0.4.RELEASE,
Can someone help me?

Related

Spring security - How to use role based authentication for different domains?

There is a project with Spring boot back-end on running on localhost:8080 and 2 front-end angular applications on localhost:4200 (User website) and localhost:4201(Admin website).How can i configure spring security so that it allows only users with role - ROLE_USER,ROLE_ADMIN in User website and users with role -ROLE_ADMIN should have access to Admin Website.
Currently both users are able to access both wesbite.Is there any way to restrict certain domains rather restricting paths(URLs) to users.
Current config -
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
Environment env;
#Autowired
UserSecurityService useSecurityService;
private BCryptPasswordEncoder passwordEncoder() {
return SecurityUtility.passwordEncoder();
}
private static final String[] PUBLIC_MATHCES= {
"/css/**",
"/js/**",
"/images/**",
"/book/**",
"/user/**",
"/media/**"
};
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(useSecurityService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(PUBLIC_MATHCES).permitAll()
.anyRequest().authenticated()
.and();
http.csrf().disable()
.cors()
.and()
.httpBasic();
}
#Bean
public HttpSessionIdResolver httpSessionStrategy() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
}
suppose all of your configurations configured properly, then you can make use of the role restriction mechanism as the below sample :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize - > {
authorize
.antMatchers("/h2-console/**").permitAll() //do not use in production!
.antMatchers("/css/**", "/js/**", "/images/**", "/book/**", "/user/**", "/media/**").permitAll()
.antMatchers("/website/find", "/main*").permitAll()
.antMatchers(HttpMethod.GET, "/userweb/v1/data/**").permitAll()
.mvcMatchers(HttpMethod.DELETE, "/userweb/v1/info/**").hasRole("ADMIN")
.mvcMatchers(HttpMethod.GET, "/userweb/v1/item/{upc}").permitAll()
.mvcMatchers("/admin/main").hasAnyRole("USER", "ADMIN")
.mvcMatchers(HttpMethod.GET, "/user/api/v1/normal")
.hasAnyRole("USER", "ADMIN", "FOO");
})
.authorizeRequests()
.anyRequest().authenticated()
.and()
.cors()
.and()
.httpBasic()
.and().csrf().disable();
}

Custom login REST endpoint

I am trying to change default POST /login spring security endpoint for logging in to POST /api/users/login
I already tried doing that through
formLogin().loginProcessingUrl("/api/users/login")
or
formLogin().loginPage("/api/users/login")
but it didn't work. How do i do that? I can't find tutorial describing it or stack overflow answer. I also tried reading Spring Security documentation but it didn't help too.
My security config looks like this:
private final MyUserDetailsService myUserDetailsService;
private final PasswordEncoder passwordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
//go from most restrictive url to least restrictive, from single urls to /**
httpSecurity.csrf().disable().cors().and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//to allow h2 console page
httpSecurity.headers().frameOptions().disable();
}
In the WebSecurityConfigurerAdapter class there is to configure methods that you should override like so:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(
unAuthorizedResponseAuthenticationEntryPoint)
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
http.addFilterBefore(authenticationTokenFilter,
UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring().antMatchers(HttpMethod.POST, "/api/auth/login")
.antMatchers(HttpMethod.OPTIONS, "/**")
.and().ignoring()
.antMatchers(HttpMethod.GET, "/").and().ignoring();
}
}
Please see in method:
public void configure(WebSecurity webSecurity) throws Exception
the line:
webSecurity.ignoring().antMatchers(HttpMethod.POST, "/api/auth/login")
This is where you put your custom authentication API endpoint!
And then you may proceed as I explained in the following question
How to use custom UserDetailService in Spring OAuth2 Resource Server?

Spring Security Multiple HTTPSecurity with Different User Details Services Not Working in Spring Boot

I have two types of users: Application User and End User and I have separate tables for these. Now, I want to apply security on these two tables.
I provided custom implementation of UserDetailsService for Application users:
#Component("applicationUserDetailsService")
public class ApplicationUserDetailsService implements UserDetailsService {}
And, I provided another second custom implementation of UserDetailsService for End users:
#Component("endUserDetailsService")
public class EndUserDetailsService implements UserDetailsService {}
Now, in the following code snippet, I have registered two endpoints for both type of users. I have injected both implementation of UserDetailsService and registered by #Overide configure(AuthenticationManagerBuilder auth) method for both application and end user separately.
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration {
// Injected via Constructor Injection
private final EndUserDetailsService endUserDetailsService;
private final ApplicationUserDetailsService applicationUserDetailsService;
#Configuration
#Order(1)
public class ApplicationUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/api/customer/**")
.authorizeRequests()
.antMatchers("/api/customer/authenticate").permitAll()
.antMatchers("/api/customer/**")
.authenticated()
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
//no #Order defaults to last
#Configuration
public class EndUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService);
}
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
And, I'm trying to authenticate the user like this:
//Injected via Constructor Injection
private final AuthenticationManagerBuilder authenticationManagerBuilder;
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
When the above code snippet is executed, I get the Null Pointer Exception because authenticationManagerBuilder.getObject() returns NULL. And when I use just when implementation of UserDetailService with #Component("userDetailsService") and not set UserDetailService in security config like auth.userDetailsService("..."), it works fine but by that way I can't achieve authentication from multiple tables.
What I want to Achieve:
In simple words, I want spring security to authenticate user from two tables.
requestMatchers() is the call that you need as it allows you to isolate adapters by URL:
#Order(1)
#EnableWebSecurity
class EndUserConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/customer/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("CUSTOMER")
.and()
.apply(yourJointConfigurations());
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
Regarding calling the AuthenticationManager directly, it would be ideal if you could rely on the existing filter chain to do the work for you. For example, since you are stateless, HTTP Basic might be a better fit for you, which you could apply to both configurations, instead of trying to have a dedicated /authenticate endpoint.

Spring Security WebSecurityConfigurerAdapter Configuration

I have a simple Spring Boot application with the following 2 endpoints:
int: requires Shibboleth SSO && Authorized Role
ext: no SSO, no authorization required
I've implemented a PreAuthenticationFilter to work with SSO. Below is
the configuration that is not working:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/ext/**").permitAll()
.anyRequest().authenticated()
.and()
.authorizeRequests()
.and()
.addFilter(preAuthenticationFilter());
}
}
Shouldn't PreAuthenticationFilter bypass the /ext endpoint? However, the above configuration forces both endpoints to go to the PreauthenticationFilter. Also tried
web.ignoring().antMatchers("/ext/**")
to no avail.
Here's the rest of my program:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/ext/**").permitAll()
.anyRequest().authenticated()
.and()
.authorizeRequests()
.and()
.addFilter(preAuthenticationFilter());
}
#Override
public void configure(WebSecurity web) throws Exception {
//web.ignoring().antMatchers("/ext/**");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider();
authenticationProvider.setPreAuthenticatedUserDetailsService(new ShibbolethUserDetailsService());
auth.authenticationProvider(authenticationProvider);
}
#Bean
RequestHeaderAuthenticationFilter preAuthenticationFilter() throws Exception {
ShibbolethRequestHeaderAuthenticationFilter filter = new ShibbolethRequestHeaderAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
return filter;
}

Spring boot: Securing api endpoint with oauth2 while having mvc UI pages

I'm trying to get a spring-boot mvc application working with standard login while exposing some API endpoints with oAuth2 security.
Basically my requirements are as follows:
If a user hits the home page ("/") check if it's authenticated.
If not show the login form, else show the home page.
But a user should also be able to ask for an oauth authentication token and with that token acces /api/assignment/{id}.
I can get the standard login to work, and I can get the oauth2 to work but I can not get them to work together.
This is my configuration at the moment:
WebSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource).passwordEncoder(new BCryptPasswordEncoder());
}
}
OAuth2Config
#Configuration
#EnableResourceServer
#EnableAuthorizationServer
public class OAuth2Config {
protected static final String RESOURCE_ID = "oauthdemo";
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/images/**", "/webjars/**", "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthServer extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_USER")
.scopes("read")
.resourceIds(RESOURCE_ID)
.secret("secret").accessTokenValiditySeconds(3600);
}
}
}
The problem is I always get the following error when trying to open the home page ("/")
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
It does not redirect to the login page.
I do not need this page to be protected by oauth2, but even if i go directly to the login page ("/login", which i can access) and supply credentials I still get the 'full authentication is required' error.
Even though i disabled basic http authentication.
Does anyone know how to separate the normal user UI from the api endpoints that need to be protected by OAuth2?
Can you try this
http
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/images/**", "/webjars/**", "/login").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/home").authenticated();
Considering /home is a page that needs to be authorized.
Hi you have to specify filters used for each config in your case you need:
in web security configurtion
http
.authorizeRequests()
.antMatchers("/api/**","/oauth/**")
.permitAll()
.and()
.......
this will let web security bypass authorization/resource servers URLs
and in resource server security configuration
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest()
.authenticated();
this will let resource security bypass all URLs except "/api/**".
in this way you can ignore orders of configuration there is another option by make one of above actions and put its configuration in early order using #Order

Resources