Can Spring OAuth2 ClientDetailsServiceConfigurer authenticates with database? - spring-boot

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");
}

Related

Spring Security OAuth2 clientId and clientSecret

I am evaluating the Spring Security OAuth2 implementation. I am confused by clientId and clientSecret.
I follow https://spring.io/guides/tutorials/spring-security-and-angular-js/ to build auth server.
I can get generate code by
http://localhost:9999/uaa/oauth/authorize?response_type=code&client_id=acme&redirect_uri=http://example.com
I also can obtain the accesstoken by
curl acme:acmesecret#localhost:9999/uaa/oauth/token \
-d grant_type=authorization_code -d client_id=acme \
-d redirect_uri=http://example.com -d code=jYWioI
{"access_token":"2219199c-966e-4466-8b7e-12bb9038c9bb","token_type":"bearer","refresh_token":"d193caf4-5643-4988-9a4a-1c03c9d657aa","expires_in":43199,"scope":"openid"}
When getting access token, the clientId and clientSecret is required.
But if I have multiple clients, should I start multiple auth server? It cannot work in this way.
How do I build OAuth2 server without clientId and clientSecret?
The code is here: https://github.com/yigubigu/spring-security-auth
You can setup may clients
Ex In Memory :-
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token",
"password").scopes("openid")
.and()
.withClient("xx")
.secret("xx")
.authorizedGrantTypes("xxx");
}
Or you can add Database record for client
REF - Spring oauth2 DB Schema
In order to achieve dynamic client registration, you need to store the credentials in database, instead of hardcoded configuration.
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource())
// ...
}
Please refer to this tutorial for more info.

Spring OAuth2(JWT tokens) multi-tenancy based on clientId

In my Spring Boot application I have a single back-end application that exposes REST API.
I'm going to consume this API from different client applications(for example written in AngularJS).
Based on different OAuth2 clientId I'd like to allow or restrict user access to different functionalities or data how it was described in my previous question Spring OAuth 2 + Spring Data Neo4j multi-tenancy
For example I have 3 different web domains:
example1.com
example2.com
example3.com
and for domain example1.com I'd like to allow user login only with clientapp1
My current login url:
http://localhost:8080/oauth/authorize?response_type=token&client_id=clientapp1&redirect_uri=http%3A%2F%2Flocalhost%3A8080
In my Spring OAuth2 server(with JWT tokens) I have configured multiple clients - clientapp1, clientapp2, clientapp3
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("clientapp1")
.authorizedGrantTypes("password","refresh_token")
.authorities("ROLE_CLIENT")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("123456")
.and()
.withClient("clientapp2")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.autoApprove(true)
.and()
.withClient("clientapp3")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60);
// #formatter:on
}
}
The issue is that right now any user in the system can login into the applications with any clientId and thus can use for example domain3.com with clientapp1
I need the following behavior:
REST API calls from domain1.com must be only allowed with OAuth2 JWT token only with clientapp1 inside, for domain2.com only with clientapp2 and so on.
How to configure my application in order to be able only login user with a correct clientId for appropriate domain ?
Is it safe to store and directly use clientId value on client side(in user browser) ?
Also, if my approach is wrong - please suggest how to correctly implement multi-tenancy with OAuth2.

Why ClientDetailsServiceConfigurer is issuing tokens to users with ROLE_ADMIN when is it configured only for ROLE_USER?

I am using spring boot application with Oauth2 Security
I have configured ClientDetailsServiceConfigurer to use client01 client to issue tokens to only users who have ROLE_USER like this:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client01")
.scopes("read", "write")
.authorities("ROLE_USER")
.authorizedGrantTypes("password", "refresh_token")
.secret("password")
.accessTokenValiditySeconds(1800);
}
curl -X POST -vu client01:password 'http://localhost:8080/api/oauth/token?username=admin01&password=test&grant_type=password'
Why with this client I can also issue tokens to users with ROLE_ADMIN?
If I have wrong implementation, what would be the right one?
My goal is to create two clients:
- one client should allow to authenticate users with ROLE_ADMIN only;
- another client should allow to authenticate users with ROLE_USER only;

Spring OAuth2.0 - Dynamically register OAuth2.0 client

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.

Authentication Server for App Gateway and Web App sharing the user base with Spring Boot

I'm writing an App Gateway (REST-API) and a Web Application using Spring Boot. I've got a user database containing users and password hashes. Both applications will use the same user database, hence I want to have it in an isolated service. I've looked over https://spring.io/guides/tutorials/spring-security-and-angular-js/ which raised the idea to use an Auth Server via OAuth.
I'm quite unsure about the Request Flow for my use case. I think it will go App -> App Gateway (e.g. Login), which then does a request to /uaa/oauth/token with grant type password(since i got the user credentials). This request must contain client_id and client_secret and should return a token.
Is this concept correct for my usecase?
If so: How do I have to configure the Auth Server to use the Database instead of Basic Auth? All examples I found have a certain user / pw combination in application.properties
What would be the most idiomatic way to delegate Auth via username + pw to the Auth Server?
Edit: I found this to be very helpful: https://github.com/dsyer/sparklr-boot
Now I can do:
curl -H "Accept: application/json" my-trusted-client#localhost:8080/oauth/token -d grant_type=password -d username=user -d password=password
How do I wire some user backend into it? As far as I understand the following uses the default Spring Basic Auth settings.
application.yml:
security:
user:
password: password
Code:
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients.inMemory().withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code",
"refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust").resourceIds("sparklr")
.accessTokenValiditySeconds(60).and()
.withClient("my-client-with-registered-redirect")
.authorizedGrantTypes("authorization_code").authorities("ROLE_CLIENT")
.scopes("read", "trust").resourceIds("sparklr")
.redirectUris("http://anywhere?key=value").and()
.withClient("my-client-with-secret")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT").scopes("read").resourceIds("sparklr")
.secret("secret");
// #formatter:on
}
}

Resources