Spring OAuth2.0 - Dynamically register OAuth2.0 client - spring

I am working on setting up an OAuth2.0 authorization server using Spring security. I want to know if there is a way to dynamically register an OAuth2.0 client after the OAuth2.0 authorization server is up and running?
Basically, I know that I can register a client while configuring the OAuth2.0 server by extending the AuthorizationServerConfigurerAdapter and overriding the configure method to add the client details in memory. However, this way the client is pre-registered and I would like to know how to dynamically add the client details.
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients.inMemory()
.withClient(CLIENT_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes("authorization_code", "implicit")
.redirectUris("http://junk/")
.scopes("cn")
.accessTokenValiditySeconds(600);
// #formatter:on
}

You should be able to just use the JdbcClientDetails (there are even convenience methods similar to the in memory ones):
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource)
.passwordEncoder(passwordEncoder)
.withClient("my-trusted-client")
... etc.
(Code taken from here: https://github.com/spring-projects/spring-security-oauth/blob/master/tests/annotation/jdbc/src/main/java/demo/Application.java#L102.) Then you have a database with data you can change at runtime as much as you want.

Related

Can Spring OAuth2 ClientDetailsServiceConfigurer authenticates with database?

I am new to Spring Boot OAuth2 framework.
I have the following working when authenticating incoming requests to ask for token.
The "withClient" and "secret" are both hard-coded and I want that to query against database
like MySQL. I like different clients to have different login/secret pairs.
Is this possible? Can someone provide example? thanks
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientA")
.secret("secret")
.accessTokenValiditySeconds(2000) // expire time for access token
.refreshTokenValiditySeconds(-1) // expire time for refresh token
.scopes("read", "write") // scope related to resource server
.authorizedGrantTypes("password");
}

Avoid oauth authentication for specific endpoints: Spring boot oAuth2

I am quite new to Spring boot OAuth. My application is using OAuth2 integrated with Azure AD. I want to have a URL which will not redirect to Azure AD for authentication. It was quite straight forward with Spring Security, we could configure something like this:
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/someURL");
}
Is there an alternative available for OAuth?
Yes can allow access to everyone by using this
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatchers("/someURL").permitAll();
}
for details check.
You can avoid specific end point authentication like below
#Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/url/**").permitAll()
.anyRequest().authenticated();
}

Spring Security with OAuth2 and anonymous access

I have my Spring REST API secured with Spring Security and OAuth2, I can successfully retrieve a token and access my APIs. My App defines the OAuth2 client itsself.
Now I want users to have anonymous access on some resources. The use case is really simple: I want my app to be usable without login - but if they are logged in, I want to have access to that principal.
Here is my WebSecurityConfigurerAdapter so far:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api1").anonymous().and()
.authorizeRequests().antMatchers("/ap2**").permitAll();
}
As soon as I add a second antMatcher/anonymous, it fails to work though, and it doesn't really express my intent either - e.g. I wan't to have anonymous access on api1 GETs, but authenticated on POSTs (easy to do with #PreAuthorize).
How can I make the OAuth2 authentication optional?
I dropped my #EnableWebSecurity and used a ResourceServerConfigurerAdapter like so:
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/api/api1", "/api/api2").permitAll()
.and().authorizeRequests()
.anyRequest().authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("my-resource-id");
}
}
/api/api1 may now be called with or without authentication.

Connecting Spring Security OAuth2 with SAML SSO

We’re having a microservices architecture based on spring boot where we have multiple microservices talking to each other and also a Javascript UI that connects to the different microservices.
Since this is an internal application and we have the requirement to connect them to our SAML2 endpoint to provide SSO, I’m getting a bit of a headache to connect all of this together. Ideally the microservices use oAuth2 between themselves (JWT) and the UI, but User Authentication is done through SAML2
The following I want to achieve with this:
UI Clients talk to the microservices by using JWT
Microservices use JWT as well to talk to each other. When a user initiates a request to a microservice and that microservice needs more data from another one, it uses the users JWT token (this should be fairly easy to do).
Having one central authentication microservice which is responsible for generating new tokens and authenticate the user against the SAML endpoint.
Storing some SAML details (e.g. Roles) in the authentication microservice
So I have tried many different things. What I can say is the following:
Using OAuth between microservices and JWT works fine and is not really an issue (e.g. this link is a nice tutorial to set this up http://www.swisspush.org/security/2016/10/17/oauth2-in-depth-introduction-for-enterprises )
Using SAML with spring-security-saml-dsl is also straight forward and works pretty well
I have implemented JWT in combination of spring-security-saml-dsl and that works also well (similar to this: https://www.sylvainlemoine.com/2016/06/06/spring-saml2.0-websso-and-jwt-for-mobile-api/ except that I use spring-security-saml-dsl) which I don’t like because it uses to much custom code with all the filters, etc. but would be a way to go.
I guess where I struggle with is the connection points of oauth2 Resource Server and the SAML services.
Regarding SAML I have the following that works fine:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${security.saml2.metadata-url}")
String metadataUrl;
#Value("${server.ssl.key-alias}")
String keyAlias;
#Value("${server.ssl.key-store-password}")
String password;
#Value("${server.port}")
String port;
#Value("${server.ssl.key-store}")
String keyStoreFilePath;
#Autowired
SAMLUserDetailsService samlUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/oauth/**").authenticated()
.and().exceptionHandling()
.and()
.authorizeRequests()
.antMatchers("/saml*").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml()).userDetailsService(samlUserDetailsService)
.serviceProvider()
.keyStore()
.storeFilePath("saml/keystore.jks")
.password(this.password)
.keyname(this.keyAlias)
.keyPassword(this.password)
.and()
.protocol("https")
.hostname(String.format("%s:%s", "localhost", this.port))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath(this.metadataUrl);
}
}
and that works fine. so when I hit a protected endpoint I will get redirected and can login through saml. I get the userdetails then in the samlUserDetailsService.
Regarding oauth I have something like this:
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.tokenEnhancer(accessTokenConverter())
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("ABC"); //needs to be changed using certificates
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("refresh_token", "authorization_code")
.autoApprove(true)
.scopes("webapp")
.accessTokenValiditySeconds(60)
.refreshTokenValiditySeconds(3600);
}
}
This part also works fine with other micorservices where I have #EnableResourceServer
As far as I understand the OAuth part, the ClientDetailsServiceConfigurer just configures the client applications (in my case the other microservices) and I should use client_credentials kind of grant for this (but aren't sure). But how I would wire in the SAML part is not clear to me...
As an alternative I'm thinking about splitting this up. Creating a microservice that is an OAuth Authorization Service and another one that does the SAML bit. In this scenario, the SAML Microservice would connect to SAML and provide an endpoint like /me if the user is authenticated. The OAuth Authorization Service would then use the SAML Microservice to check if a user is Authenticated there and provide a token if that is the case. I would also do the same regarding refresh tokens.
As far as I understand this, I would implement this kind of logic in the
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {} method.
If there's a better approach, let me know!

Securing a REST application in SpringBoot and accessing it from a Rest Client

I am pretty new to Springboot. I have developed a rest server but I was wondering how to perform Basic authentication from a client and how to configure the spring boot server to authenticate request. The tutorials I saw online didn't include a restful client. Would be great if you can show some code including both the client request and server authentication process with springboot rest.
On the client side since you are using Jersey Client you need to do something like the following:
Client c = Client.create();
c.addFilter(new HTTPBasicAuthFilter(user, password));
One the server side you need to enable Spring Security and set Basic Authentication for it which would look something like the following (this is the simplest possible case).
#Configuration
#EnableWebSecurity
public class RootConfig extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("tester").password("passwd").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}

Resources