I have Spring web app with REST WS built using spring-security-oauth2:2.3.3 and spring-boot-starter-security:2.0.2. But I am not able to set which endpoints are protected.
ResourceServerConfig
#EnableResourceServer
#Configuration
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/customers", "/v2/**").permitAll()
.antMatchers("/api/**").authenticated();
}
#Bean
public AuthenticationManager authenticationManager(AuthenticationProvider authenticationProvider) {
return new CustomAuthenticationManager(authenticationProvider);
}
#Bean
public AuthenticationProvider authenticationProvider(UserRepository userRepository, PasswordEncoder passwordEncoder) {
return new DBAuthenticationProvider(userRepository, passwordEncoder);
}
}
AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("ClientId")
.secret("secret")
.authorizedGrantTypes("password")
.scopes("read", "write");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager);
}
}
When I obtain access token first, everything works perfectly, but I expect endpoints "/", "/customers", "/v2/**" to be permited for all without any authorization. But when I call 'curl http://{{host}}/' or http://{{host}}/customers I still get 401:
{"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
adding "--header "Authorization: Basic {{base64 client id:password}}" doesnt help either. How is that possible?
EDIT
according to spring security permitAll still considering token passed in Authorization header and returns 401 if token is invalid solved by adding #Order(1) to ResourceServerConfig to override default OAuth2. But that should kick in only when "Authorization" header is added, which is not my case. So how is this possible?
Add this to your project.
#Configuration
public class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user/**")
.authorizeRequests().anyRequest().authenticated();
}
}
If you want to make any request to /user/** you need to pass your access token in the header as Authorization: Bearer {access_token}. All other endpoints will not ask for a token.
Related
I have 2 class that extends WebSecurityConfigurerAdapter, one with #Order(1) the other with #Order(2).
I want the first one to filter my APIs starting with /user/** and the other to filter /client/** so I can access localhost:8080/client (to have a login page from Salesforce, then it will allow the client to acess some other /client API).
I have :
#EnableWebSecurity
#Configuration
#Order(1)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private OpenLdapAuthenticationProvider openLdapAuthenticationProvider;
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
private JwtRequestFilter jwtRequestFilter;
public WebSecurityConfig(OpenLdapAuthenticationProvider openLdapAuthenticationProvider,
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint,
JwtRequestFilter jwtRequestFilter) {
this.openLdapAuthenticationProvider = openLdapAuthenticationProvider;
this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint;
this.jwtRequestFilter = jwtRequestFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(openLdapAuthenticationProvider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// CORS
httpSecurity.cors().and().antMatcher("/**").csrf().disable().sessionManagement();
httpSecurity
.csrf().disable().headers().frameOptions().deny()
.and()
.authorizeRequests().antMatchers("/user/login").permitAll()
.antMatchers("/user/**").authenticated()
.and().exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// JWT Filter
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
And the second configuration :
#EnableWebSecurity
#Order(2)
#Configuration
public class WebSecurityConfigSF extends WebSecurityConfigurerAdapter {
#Autowired
MyOAuth2UserService myOAuth2UserService;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
// Configuration du CORS
httpSecurity.cors().and().antMatcher("/**").csrf().disable().sessionManagement();
httpSecurity.csrf().disable().headers().frameOptions().deny()
.and().authorizeRequests().antMatchers("/client/**","/client").authenticated()
.and()
.oauth2Login();
}
}
What happens is that when I call /user it works (can access all /user APIs), but when I try /client it doesn't (error Oauth2).
When I switch order, I can access localhost8080:/client and log in into Salesforce no problem but all /user APIs are not filtered, meaning I can access them without any JWT in the header.
Is what I want even possible ?
In my Spring boot project I have some endpoints that require authentication and others don't. I'm using spring-security-oauth2-autoconfigure dependency. The problem is when I want to access a resource that don't require authentication with an invalid access_token I get an error "error": "invalid_token".
How can I prevent checking access token when if my method is not secured?
ResourceServerConfiguration.java
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable().and().authorizeRequests().antMatchers("/graphql/**")
.permitAll();
}
}
WebSecurityConfiguration.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll()
.anyRequest().authenticated().and().httpBasic().and().csrf().disable();
}
}
to disable spring security chain for a particular resource you can add ignore web request for pattern like below in your WebSecurityConfiguration class
#Override
public void configure(WebSecurity webSecurity) throws Exception
{
webSecurity
.ignoring()
.antMatchers("/resourcename**");
}
I am trying to secure REST api in my Spring Boot application by oAuth2 standard. I created classes extending AuthorizationServerConfigurerAdapter, ResourceServerConfigurerAdapter and WebSecurityConfigurerAdapter and unfortunately it works only with login scenario. /oauth/token request returns access_token etc, but in every other case I get 401, Unauthorized, Bad credentials. I thought that wrong cliendId/secret was the case, but it would also affect login, right?
P.S Application is connected to MySql database.
I already ran out of ideas, so maybe you guys are able to help me.
WebSecurityConfig.java :
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AuthorizationServerConfig.java :
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.authorizedGrantTypes("client-credentials", "password","refresh_token")
.authorities("ROLE_CLIENT", "ROLE_ANDROID_CLIENT")
.scopes("read", "write", "trust")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(5000)
.secret("secret")
.refreshTokenValiditySeconds(50000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
}
ResourceServerConfig.java :
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/**").authenticated();
}
}
MainApplication.java :
#SpringBootApplication
#ComponentScan({"com.user.app"})
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
#Autowired
public void authenticationManaget(AuthenticationManagerBuilder builder, UserRepository repository) throws Exception {
builder.userDetailsService(new UserDetailsServiceImpl());
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
Ok, somehow oAuth2 configuration was overwritten by base configuration in some places. Those places still weren't protected by oAuth, so that's why "Bad Credentials" error was occurring even after providing proper access token. Commenting configure() method inside WebSecurityConfig solved the problem.
I'm trying to authenticate with Basic Auth though LDAP but I only need to do so with /login route. All the other routes need to be authenticated through a custom JWT Filter that I implemented. Actually, what I've done just doesn't work.
Edit : just to be more clear, at the moment when I call on /auth/login, it goes through the LDAP filter and not the JWT Filter. But when I call any other route, it goes through JWT Filter and then still goes through the LDAP one and always makes my request fail. The behaviour is only correct when it's the /auth/login call.
Here's the configuration :
public class SecurityConfiguration {
#Configuration
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE + 21)
public static class CompanySecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private LdapContextSource ldapContextSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().contextSource(ldapContextSource).userDnPatterns("uid={0},ou=people");
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.httpBasic().and()
.requestMatchers()
.antMatchers("/auth/login")
.and().authorizeRequests().anyRequest().authenticated()
.and().csrf().disable();
}
}
#Configuration
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE + 20)
public static class JWTSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requestMatchers()
.antMatchers("/projects", "/projects/**", "/credential/**")
.and()
.addFilterAfter(new JWTFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().anyRequest().authenticated()
.and().cors().disable();
}
}
}
I would like to make some urls of my api public. But once I configure one single url, all my api become exposed without authorization.
Below my configure method of ResourceServerConfiguration class :
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/books","/api/plainOffers","/api/offers","/api/public/*").permitAll();
}
ResourceServer configuration :
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/books").permitAll();
http.authorizeRequests().antMatchers("/api/plainOffers").permitAll();
http.authorizeRequests().antMatchers("/api/offers").permitAll();
http.authorizeRequests().antMatchers("/api/public/*").permitAll();
//http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
Authorization server :
#CrossOrigin
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig
extends AuthorizationServerConfigurerAdapter{
#Autowired
#Qualifier("userDetailsService")
private UserDetailsService userDetailsService;
#Autowired
private AuthenticationManager authenticationManager;
#Value("${api.oauth.tokenTimeout:3600}")
private int expiration;
#Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
configurer.authenticationManager(authenticationManager);
configurer.userDetailsService(userDetailsService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("api")
.secret("secret")
.accessTokenValiditySeconds(expiration)
.scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.resourceIds("oauth2-resource");
}
}
I guess you'll have to add the required restricions on other urls :
http.authorizeRequests().antMatchers("/api/books","/api/plainOffers","/api/offers","/api/public/*").permitAll();
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
I would like to point out that if you have provided resource_id = api then remove /api and add urls like this ("/books","/plainOffers","/offers","/public/*") in rules.
Then it will work.