customize state parameter with Oauth2client using spring security - spring

I want to customize state parameter with Oauth2client using spring security OIDC. I am using spring reactive. The issue is I am not able to add customize state in client registration. Below is my security configuration.
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers("/","/jwt").permitAll()
.anyExchange().authenticated().and()
.oauth2Client()
.build();
}
#Bean
public ReactiveClientRegistrationRepository reactiveClientRegistrationRepository(RegisteredClients clients) {
List<ClientRegistration> clientRegistrations = clients.getClients()
.entrySet().stream()
.map(clientRegistration -> {
String registrationId = clientRegistration.getKey();
RegisteredClients.OAuthClient client = clientRegistration.getValue();
return ClientRegistration.withRegistrationId(registrationId)
.clientId(client.getClientId())
.clientSecret(client.getClientSecret())
.redirectUriTemplate(client.getRedirectUri())
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.tokenUri(client.getTokenUri())
.authorizationUri(client.getAuthorizationUri())
.scope("openid")
.build();
})
.collect(toList());
return new InMemoryReactiveClientRegistrationRepository(clientRegistrations);
}

To customize the authorization request, you should wire an ServerAuthorizationRequestResolver:
#Bean
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
// ...
.oauth2Client((oauth2) -> oauth2
.authorizationEndpoint((authorization) -> authorization
.authorizationRequestResolver(authorizationRequestResolver)
)
)
.build();
}
#Bean
OAuth2ServerAuthorizationRequestResolver authorizationRequestResolver
(ReactiveClientRegistrationRepository registrations) {
DefaultServerOAuth2AuthorizationRequestResolver resolver =
new DefaultServerOAuth2AuthorizationRequestResolver(registrations);
resolver.setAuthorizationRequestCustomizer((request) -> request.state(...));
return resolver;
}
Spring Security has some related servlet documentation that may be useful as well.

Related

How to capture Exceptions from OAuth2 client(OIDC) while retrieving user info in spring boot?

I am using ODIC authentication in my spring boot project , After successful authentication I am getting error as invalid_user_info_response , I do not see any exceptions or errors in the tomcat or log file. I would like to know how to capture the any kind of exceptions occured while retrieving user information from the ODIC provider. Below is security filter code.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.ALWAYS).maximumSessions(2)
)
.authorizeRequests((authz) -> authz
.antMatchers("/auth/redirect").permitAll().anyRequest().authenticated()
)
.csrf(c -> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
.logout()
.logoutSuccessHandler(logoutSuccessHandler).invalidateHttpSession(true).and().oauth2Login()
.redirectionEndpoint().baseUri("/auth/redirect").and().userInfoEndpoint()
.oidcUserService(this.oidcUserService());
return http.build();
}
#Bean
public WebClient rest(ClientRegistrationRepository clients, OAuth2AuthorizedClientRepository authz) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 = new ServletOAuth2AuthorizedClientExchangeFilterFunction(
clients, authz);
oauth2.setDefaultOAuth2AuthorizedClient(true);
oauth2.setDefaultClientRegistrationId("clientname");
return WebClient.builder().filter(oauth2).build();
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}```

Spring Security Customizing Authorization Endpoint URL

I am implementing a Spring MVC REST web service and attempting to security it with Spring Security Oauth2.
My authorization URL is at the following address (note that there is no registration id):
http://localhost:8080/myoauthserver/oauthservlet
So, in my Spring Security Config, I have this:
#Bean
#Profile("dev")
public ClientRegistration devClientRegistration() {
// set up variables to pass to ClientRegistration
ClientRegistration result = ClientRegistration
.withRegistrationId("") // this obviously doesn't work
.clientId(clientId)
.clientSecret(clientSecret)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationUri(authorizationUri)
.tokenUri(clientSecret)
.userInfoUri(userInfoUri)
.userNameAttributeName(userNameAttribute)
.redirectUri(redirectUrl)
.providerConfigurationMetadata(providerDetails)
.build();
return result;
}
#Bean
public ClientRegistrationRepository clientRegistrationRepository() {
ClientRegistrationRepository repository = new InMemoryClientRegistrationRepository(devClientRegistration());
return repository;
}
#Bean
#Profile("dev")
public SecurityFilterChain securityWebFilterChain(HttpSecurity http) throws Exception {
// this prevents throwing an exception in the oauth2 lambda function
Map<String, String> loginProps = ...
http
.authorizeRequests()
// what we want is for a few urls to be accessible to all, but most to require
// oauth authentication/authorization
.antMatchers("/login/**","/error/**", "/oauth2/**").anonymous()
.anyRequest().authenticated()
.and()
.oauth2Login(oauth2 -> {
oauth2
.clientRegistrationRepository(clientRegistrationRepository(loginPropsCopy))
.authorizationEndpoint()
.baseUri("http://localhost:8080/myoauthserver/oauthservlet");
}
);
return http.build();
}
How do I customize the entire authorization endpoint to not try to tack the registration id onto it?

Spring security very simple basic authentication

I've tried to implement a very simple BASIC authentication with Spring Boot, without the deprecated WebSecurityConfigurerAdapter.
#Configuration
public class SecurityConfig {
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers("/a", "/b", "/c", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html");
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic();
return http.build();
}
#Bean
public InMemoryUserDetailsManager userDetailsService() {
UserDetails user = User.builder()
.username("user")
.password("{bcrypt}$2y$10$rUzpfbTx9lcIs6N4Elcg2e2DGM4wMwkx0ixom7qLW5kYnztRgT.a2")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
The ignored endpoints work (with a warning: You are asking Spring Security to ignore Ant [pattern='/swagger-ui.html']. This is not recommended -- please use permitAll via HttpSecurity#authorizeHttpRequests instead.). For the other, I get an HTTP 403.
What have I done wrong?
If you are doing POST request, it can be the CSRF protection. Add logging.level.org.springframework.security=TRACE in your application.properties file and see the console output after the request is made to see what is happening.
If it is CSRF protection, I recommend you leave it enabled unless you have a requirement that tells you to disable it. You can have more details about Cross Site Request Forgery here.
Also, if you want to use the {bcrypt} prefix in your password, use the PasswordEncoderFactories.createDelegatingPasswordEncoder. If you want to use only the BCryptPasswordEncoder then you have to remove the {bcrypt} prefix

How to validate OAuth token in Spring Cloud Gateway

I have a Spring Cloud gateway application which currently supports "HTTP basic auth". I'm planning to use OAuth 2.0 with Keycloak as the provider. I have started by adding required packages (listed below).
implementation "org.springframework.boot:spring-boot-starter-security"
implementation "org.springframework.boot:spring-boot-starter-oauth2-client"
I'm new to this and want to support the following things.
Register clients dynamically to Keycloak
Validate the current request token with Keycloak to allow/ deny the request
My SecurityConfig.java is as given below.
#Configuration
#EnableWebFluxSecurity
public class SecurityConfig {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http.csrf().disable()
.formLogin().disable()
.logout().disable()
.authorizeExchange(exchanges -> exchanges.anyExchange().permitAll())
.oauth2Client();
return http.build();
}
#Bean
public WebClientHttpRoutingFilter webClientHttpRoutingFilter(
#Qualifier("webClient") WebClient webClient,
ObjectProvider<List<HttpHeadersFilter>> headerFilters) {
return new WebClientHttpRoutingFilter(webClient, headerFilters);
}
#Bean
public WebClient webClient(
#Qualifier("reactiveOAuth2AuthorizedClientManager")
ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(reactiveOAuth2AuthorizedClientManager);
oauth.setDefaultOAuth2AuthorizedClient(true);
oauth.setDefaultClientRegistrationId("keycloak");
return WebClient.builder()
.filter(oauth)
.build();
}
#Bean
public ReactiveOAuth2AuthorizedClientManager reactiveOAuth2AuthorizedClientManager(
ReactiveClientRegistrationRepository clientRegistrationRepository,
ServerOAuth2AuthorizedClientRepository authorizedClientRepository) {
ReactiveOAuth2AuthorizedClientProvider authorizedClientProvider =
ReactiveOAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultReactiveOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultReactiveOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
}

Credentials propagation from Spring Cloud Gateway to underlying service

I use Spring Cloud Gateway as UI gateway. Security config:
#Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) {
return http.httpBasic().and()
.formLogin().loginPage("/login")
.and()
.authorizeExchange().anyExchange().permitAll()
.and()
.build();
}
How I can propagate current user credentials (username and roles) to underlying services? Do I need add some custom filters to routes config:
#Bean
RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("some-ui", r -> r.path("/some-ui-context-path/**")
.uri("lb://some-ui"))
.build();
}
? Is there a standard component for this purpose?
I created filter for adding username and user roles to headers of downstream services request (code on Kotlin):
#Component
class AddCredentialsGlobalFilter : GlobalFilter {
private val usernameHeader = "logged-in-user"
private val rolesHeader = "logged-in-user-roles"
override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain) = exchange.getPrincipal<Principal>()
.flatMap { p ->
val request = exchange.request.mutate()
.header(usernameHeader, p.name)
.header(rolesHeader, (p as Authentication).authorities?.joinToString(";") ?: "")
.build()
chain.filter(exchange.mutate().request(request).build())
}
}

Resources