Multiple oauth2 providers with spring security - spring-security

I have a mobile client and a browser client and I am using oauth2.
How is it possible to define multiple providers in the oauth szenario in the yaml file?
For e.g. oauth2-1 oauth2-2
security:
user:
password: none
oauth2:
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
tokenName: oauth_token
clientId: acme
clientSecret: acmesecret
code looks like this:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
String clientId = authProperties.getSecurity().getAuthentication().getOauth().getClientid();
// #formatter:off
clients.inMemory()
.withClient(clientId).scopes("read", "write")
.autoApprove(true)
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit", "client_credentials")
.secret(authProperties.getSecurity().getAuthentication().getOauth().getSecret())
.accessTokenValiditySeconds(authProperties.getSecurity().getAuthentication().getOauth().getTokenValidityInSeconds())
.and()
.inMemory()
.withClient("readonlyClient")
.scopes("read")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit",
"client_credentials")
.secret(authProperties.getSecurity().getAuthentication().getOauth().getSecret())
.accessTokenValiditySeconds(authProperties.getSecurity().getAuthentication().getOauth()
.getTokenValidityInSeconds())
.and()
.inMemory()
.withClient("imp")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.autoApprove(true)
.accessTokenValiditySeconds(authProperties.getSecurity().getAuthentication().getOauth()
.getTokenValidityInSeconds());
// #formatter:on
}

Related

Getting token claim inside security configuration

I'm trying to make security using oauth2 resource server with google as authentication provider and add custom roles from database by getting email from JWT token and searching for it in database.
This is my configuration
#Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/csrf").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.oauth2ResourceServer().jwt().decoder(jwtDecoder()).jwtAuthenticationConverter(jwtAuthenticationConverter())
.and()
.and()
.cors().and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
return http.build();
}
JWT decoder and authentication converter
#Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
MappedJwtClaimSetConverter converter = MappedJwtClaimSetConverter.withDefaults(Collections.singletonMap("roles", customClaim -> getUserRolesFromDatabase()));
jwtDecoder.setClaimSetConverter(converter);
jwtDecoder.setJwtValidator(withIssuer);
return jwtDecoder;
}
#Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter grantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
grantedAuthoritiesConverter.setAuthorityPrefix("ROLE_");
grantedAuthoritiesConverter.setAuthoritiesClaimName("roles");
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
return jwtAuthenticationConverter;
}
public List<String> getUserRolesFromDatabase() {
return Collections.singletonList("USER");
}
How do I get email claim from bearer token to use it in getUserRolesFromDatabase() and search for roles in database?

Spring cloud gateway returns 403 for all post requests when security enabled

I have the following services:
Eureka server
Auth server
Spring Gateway
This will pass the login request to the login service
All other requests will be authenticated(using jwt token and secret key) and passed to other services
Login Service
To validate login and issue jwt token
Below is my config. The flow is not even reaching to this code..
#Configuration
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private SecurityContextRepository securityContextRepository;
#Bean(value="org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration.WebFilterChainFilter")
public SecurityWebFilterChain springSecurityWebFilterChainFilter(ServerHttpSecurity http) {
LOGGER.info("In the securiry config..................");
return http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((swe, e) -> {
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
});
}).accessDeniedHandler((swe, e) -> {
return Mono.fromRunnable(() -> {
swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
});
})
.and()
.authenticationManager(authenticationManager)
.securityContextRepository(securityContextRepository)
.authorizeExchange()
.pathMatchers(HttpMethod.OPTIONS).permitAll()
.pathMatchers("/login-service/api/login").permitAll()
.anyExchange().authenticated()
.and().build();
}
}
I always get 403 with An expected CSRF token cannot be found this error even though I have disabled csrf.
Can anyone help what can be wrong here?
Have you tried adding your role:
.authorizeExchange()
.pathMatchers("/login-service/api/login").hasAuthority("ROLE_ADMIN")
.anyExchange().authenticated()
.and().build();

Spring Security redirects to wrong /login url in combination with Spring-Cloud-Gateway

I have 3 spring-boot services up and running.
gateway-service -> localhost:8090
eureka-service -> localhost:8091
my-service (using Spring-Security + Web) -> localhost:8092
Gateway - application.yml
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: my-service
uri: lb://my-service
predicates:
- Path=/my-service/**
my-service has 2 endpoints
/info
/secured
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.formLogin()
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/secured").authenticated()
.anyRequest().permitAll();
}
...
localhost:8090/my-service/info works fine.
localhost:8090/my-service/secured redirects to localhost:8092/login.
Is it possible to configure spring-security redirect to localhost:8090/my-service/login ?
The solution is to use X-Forwared-Headers with Spring Boot ForwardedHeaderFilter.
#Bean
public FilterRegistrationBean<ForwardedHeaderFilter> forwardedHeaderFilter() {
ForwardedHeaderFilter filter = new ForwardedHeaderFilter();
FilterRegistrationBean<ForwardedHeaderFilter> registration = new FilterRegistrationBean<>(filter);
registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR);
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
registration.setUrlPatterns(List.of("/login", "/secured"));
return registration;
}
I found it here.
https://tomgregory.com/spring-boot-behind-load-balancer-using-x-forwarded-headers/

Spring Security and Cognito : CustomAuthenticationProvider never invoked

I'm trying to make a project with APIs with cognito authentication. For this, I need a CustomAuthenticationProvider to get user's roles from another microservice. But it is never invoked.
application.yml
spring:
security:
oauth2:
client:
registration:
cognito:
clientId: xxxx
clientSecret: xxxxx
scope: openid
redirectUriTemplate: "http://localhost:8080/login/oauth2/code/cognito"
clientName: xxxx
provider:
cognito:
issuerUri: https://cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxx
usernameAttribute: cognito:username
build.gradle
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
compile 'org.springframework.security:spring-security-oauth2-jose:5.3.3.RELEASE'
compile 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework:spring-tx:5.2.7.RELEASE'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
securityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity( securedEnabled = true )
#ComponentScan( "com.project" )
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure ( final AuthenticationManagerBuilder auth ) throws Exception {
auth.authenticationProvider( this.authProvider );
}
#Override
protected void configure ( final HttpSecurity http ) throws Exception {
http.cors();
http.csrf().disable();
http.authorizeRequests()
.antMatchers( "/public/**" )
.permitAll()
.antMatchers( "/user/**" )
.hasRole( "USER" )
.anyRequest()
.authenticated()
.and()
.oauth2Client()
.and()
.authenticationProvider( new CustomAuthenticationProvider() );
}
}
CustomAuthenticationProvider
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate ( final Authentication authentication ) throws AuthenticationException {
String userName = authentication.getName();
System.out.println( userName );
return new AWSAuthentication( userName, Arrays.asList( new SimpleGrantedAuthority( "ROLE_USER" ) ) );
}
#Override
public boolean supports ( Class<?> authentication ) {
return authentication.equals( AWSAuthentication.class );
}
}
No error occur, only 403.
I saw this example, but it is deprecated.
Could anyone help me with some clue or example?
I solved my problem adapting the code of this lib to my necessity.

Spring Boot OAuth2 - GoogleApi- Could not obtain user details from token

I am working on a project which has requirements for Gmail Authentication and also which can be extended.
I was following this tutorial here which had examples for Facebook and GitHub authentication. So I tried for Gmail and I am getting this error which I am not able to resolve and getting new exceptions when trying to resolve. Kindly, help me out as I believe this is the point where the code is least affected by my additions. With this much of config and code, it is working for github and fb but not for google.
SocialApplication.java
#SpringBootApplication
#RestController
#EnableOAuth2Client
#EnableAuthorizationServer
#Order(6)
public class SocialApplication extends WebSecurityConfigurerAdapter {
#Autowired
OAuth2ClientContext oauth2ClientContext;
#RequestMapping({ "/user", "/me" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest()
.authenticated().and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout()
.logoutSuccessUrl("/").permitAll().and().csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
// #formatter:on
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/me").authorizeRequests().anyRequest().authenticated();
// #formatter:on
}
}
public static void main(String[] args) {
SpringApplication.run(SocialApplication.class, args);
}
#Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
#Bean
#ConfigurationProperties("github")
ClientResources github() {
return new ClientResources();
}
#Bean
#ConfigurationProperties("facebook")
ClientResources facebook() {
return new ClientResources();
}
**#Bean
#ConfigurationProperties("gmail")
ClientResources gmail(){return new ClientResources();}**
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(facebook(), "/login/facebook"));
filters.add(ssoFilter(github(), "/login/github"));
**filters.add(ssoFilter(gmail(), "/login/gmail"));**
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(
path);
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(oAuth2RestTemplate);
oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
return oAuth2ClientAuthenticationFilter;
}
}
class ClientResources {
private OAuth2ProtectedResourceDetails client = new AuthorizationCodeResourceDetails();
private ResourceServerProperties resource = new ResourceServerProperties();
public OAuth2ProtectedResourceDetails getClient() {
return client;
}
public ResourceServerProperties getResource() {
return resource;
}
}
index.html
<div>
With Facebook: click here
</div>
<div>
With Github: click here
</div>
**<div>
With Gmail: click here
</div>**
application.yml // skipped the contents for github and fb to save space
gmail:
client:
client_id: 7xxxxxxxx-1spjexxxxxxxc.apps.googleusercontent.com
scope: https://www.googleapis.com/auth/userinfo.profile
client_secret: Xxxxxxx-I*****zx
userAuthorizationUri: https://accounts.google.com/o/oauth2/auth
accessTokenUri: https://accounts.google.com/o/oauth2/token
auth_provider_x509_cert_url:https://www.googleapis.com/oauth2/v1/certs
LOG
org.springframework.security.authentication.BadCredentialsException:
Could not obtain user details from token at
org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:122)
~[spring-security-oauth2-2.0.10.RELEASE.jar:na] at
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE] at
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:112)
[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE] at
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE] at
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:112)
[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE] at
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
[spring-security-web-4.1.1.RELEASE.jar:4.1.1.RELEASE] at
org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:112)
[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE] at
org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:73)
[spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
**Caused by:
org.springframework.security.oauth2.common.exceptions.InvalidTokenException:
ya***********dCCnRbsve3
at
org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices.loadAuthentication(UserInfoTokenServices.java:91)
~[spring-boot-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE] at
org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter.attemptAuthentication(OAuth2ClientAuthenticationProcessingFilter.java:112)
~[spring-security-oauth2-2.0.10.RELEASE.jar:na] ... 66 common frames
omitted
And on Google API Console.
Redirect URL I have given as : localhost:8080/login/gmail
In your application.yml confirguration, I couldn't find the userinfo url defined?
I have the following google config working for me:
google:
client:
clientId: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
clientSecret: YYYYYYYYYYYYYYYYYY
accessTokenUri: https://accounts.google.com/o/oauth2/token
userAuthorizationUri: https://accounts.google.com/o/oauth2/auth
clientAuthenticationScheme: form
scope: profile email
resource:
userInfoUri: https://www.googleapis.com/userinfo/v2/me

Resources