How to architecture Microservice & OpenID connect? - microservices

We have three microservices: microA, microB & microC.
microA & microB are powering product 1.
microA & microC are powering product 2.
Obviously, we would need a security layer, in our case implementing an "OpenID Connect" provider fits well with the business needs. We add to the stack the OpenID provider.
The user/rights management is quite easy & natural: we associate the OpenId identifier of the user on each microservices to a subset of rights:
For example on the service microA, we store that the user OpenID XXX can do this and that. it's isolated on the microservice level. Respect the boundaries of our context. Fine.
When the user login with OpenID on product1, we grant an access token to the user + an Id token.
The situation becomes more complex when product1 expose an API that third-party use.
Now, let say that my user comes to the third-party webapp and is prompted to login & allow the third-party to get some rights on product1 API.
If I understand correctly OpenID connect, it's all about authentication over OAuth2, but how do we handle classic OAuth2 scope management then?
The best scenario I have found is:
make the whole OpenID connect to have the authentication info
and then make another full OAuth2 process to another Authorization server to ask the user to grant some scopes to the third party?
which means that on the third-party:
the user will be prompted to login on the OpenID Provider
then redirected and prompted to accept the scope requested
Is that correct? If yes, OAuth2 server flow is like 4 HTTP requests to the end user, so performing it twice is like executing eight requests to get the Authentication + Authorization flow done. Seems too massive.

I've already had this problem. What I would do in your case is:
Use this new OpenId microservice to authenticate the user and create the access-token. This access token can be a string with the permissions, user_id and the timestamp signed or you can store this info on a database.
Then, for every call (to product1 or product2):
I would force the client to send the access-token on the headers.
Then, when a microservice receives a call (lets say product1), I would send a signed request to the OpenId Microservice to ask if the user is allowed to perform that action.
That way, just the OpenId microservice knows how authentication works. So if in a couple of weeks you want to change how authentication works, you just have to change it on the OpenId microservice.
I dont really understand whats the problem with third-parties. They will get the token and they will be able to perform calls passingit on the Access-token header.

Related

Server-2-server authorizaton in microservice architecture

It's clear for me about users authorization in microservice architecture (API Gateway for handling auth, SSO, authorization microservice and so on).
Now i'm thinking about authorization request between microservices.
And there is one question - which options i have in case when i have not got a user?
For example - analytics service, which requests data from billing and builds complex reports. There is no user, but do i need authorize request from analytics service to billing?
I know that there can be endless tokens, but i think its not good idea.
What another options for authorization request between services?
In OAuth2 specification there is such thing called machine-to-machine token. Which is different than password credentials flow which is refering to your user authorization.
To create a machine-to-machine token you should implement a flow called client credentials flow. In this flow basically all services have a specific client id and client secret and with those you are making a call to your central oauth-server to get a token. As it is also required to configure client details in the central service you will have the authorization in between client calls in terms of which client could call which others. There is also configurations for the time to live for each token.
If you already have the OAuth2 setup on your side it might be easy to introduce this new flow. But if you don't to implement such a thing on your side with your own setup could be tricky. Please check https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2#grant-type-client-credentials

What's the difference between these Google Login methods?

My requirement:
Using google login as the only login method for my website, creating users by google user id, creating authentication sessions after a valid google login.
I saw there was 2 ways to do this:
The standard google docs
(step 1) get id token at frontend https://developers.google.com/identity/sign-in/web/sign-in
(step 2) verify token id at backend https://developers.google.com/identity/sign-in/web/backend-auth
Using spring security OAuth functions
https://dzone.com/articles/getting-started-with-google-sign-in-in-spring-boot
So the problem is,
I just finished implementing measure 1 and found that after the login popup closes the state at frontend is changed. No typical OAuth2 elements like redirect_uri, code and access_token invovled in the process. So is this OAuth at all or is google just packed everything for me so I'm not seeing them?
Is measure 2 better? Because you don't have to deal with, let's say, the leak of id_token and client_id ?
The personas involved are different:
Front end: web OAuth2 flow with user involved. You request an authorization code with a redirect_uri for redirecting the user after the authentication. And then you validate this authorization code against the IDP server (you need a client ID and a client secret).
Back end: implicit OAuth2 flow with secret key file for the authentication, for app authentication. This flow is only to deploy on backend server, you absolutely don't have to share your secret key file in your website front end
EDIT
With your update, I'm not sure to understand. The 3 are equivalent
Pure OAuth flow
Google packaging (the function onSuccess() is called when the authentication is successful in the popup, as you can see in this example
Spring boot packaging.
At the end, the same information are provided and required, the "leak" are the same in all cases. It's simply a packaging preference and habit.
EDIT 2
For getting the access_token or the refresh token, you can simply do this as described here
accessToken = googleUser.reloadAuthResponse().access_token
Then, you can pass it to your backend if you want to perform operations on behalf of the user.

What the configuration of spring-security-oauth2 authorizedGrantTypes means in practice?

For example on the default jhipster UAA configuration we have:
clients.inMemory()
.withClient("web_app")
.scopes("openid")
.autoApprove(true)
.authorizedGrantTypes("implicit","refresh_token", "password",
"authorization_code")
.and()
.withClient(jHipsterProperties.getSecurity()
.getClientAuthorization().getClientId())
.secret(jHipsterProperties.getSecurity()
.getClientAuthorization().getClientSecret())
.scopes("web-app")
.autoApprove(true)
.authorizedGrantTypes("client_credentials");
So what does "authorizedGrantTypes" really means in practice? The first client "web_app" will have different types including refresh and so the second will be able to generate a token as client_credentials. What is the difference?
Another question, what is the purpose of the second client authentication which uses "client_credentials" ? Since this is disconnected from the real users stored. microservice to microservice communication? Looks bad if the configuration is deployed on spring cloud (client and secret hard coded configuration) to allow any external authentication via the gateway. How to prevent this?
OAuth 2.0 grant types are the different "ways" your client applications can obtain tokens.
There are a bunch of articles explaining it better, but here is a summary :
authorization_code is the "classic" OAuth 2.0 flow, where the user is asked for its consent through redirections. The client application is strongly authenticated because it has to send all its credentials (client_id+ client_secret + redirect_uri) before it can get a token.
implicit is almost the same as authorization_code, but for public clients (web apps or installed/mobile applications). The flow is almost the same from the user standpoint, but with weaker client authentication. The redirect_uri is the only security, as the client receives the access token through redirection + request parameters.
password is straight forward : the client application collects the user credentials, and sends both the user credentials (username+password) and its own credentials (client_id+client_secret) in exchange for a token. This flow mixes authorization with authentication, and should only be used when there is no other choice (i.e. your own installed/mobile application, where you don't want users to switch back and forth between native app and browser). You should never allow a third party to use this flow.
With all these flows, the user is asked for its permission, one way or another. The token given to the client allows it only to access that single user's data.
The client_credentials grant is different, as it does not involve a user. It is a drop in replacement for HTTP Basic.
Instead of sending a username (client_id) + password (client_secret) for every request, your client sends its credentials in exchange for a token.
It is used in server-to-server communications, where you want to know "which application is calling" by giving it distinct credentials, but you don't tie its authorization with a specific user.
Some examples :
a command line application (batch) or worker process consuming secured services. This kind of application probably processes a bunch of user data at once, and it cannot request each user's consent. The service called has to know "who" is calling in order to allow the client application to access anything.
a third party / external client of your API wants to know informations that are not linked to user data (for example : usage stats, quotas, billing...)
a third party / external client with special privileges who can access all your users' data
Note : In service to service communication, you should relay the token received from the outside instead of having each intermediate application request its own token.

SSO with Laravel Passport

I'm thinking to develop a full-fledged Identity System in Laravel 5 with Passport.
Following is my requirement:
I should have main identity management app like identity.mysite.com where all of my users are stored.
I have 2 other applications APP1, APP2.
When user request restricted resource on APP1, (s)he should get authenticated by identity.mysite.com
Once authenticated, let user access resources on APP1
Meantime, if user decided to access restricted resources on APP2, (s)he should not be asked to put credentials again.
Things I've tried:
simpleSAMLphp - SAML is an option which does these things for me. But it is not as mature as OneLogin and I'm not thinking to go in SaaS model at this stage unless it is necessity.
Laravel Passport - oAuth 2.0 seems tempting. I can even use, Passport Grant Tokens but I'm unsure on how reliable it is over SAML. Also, Laravel Passport is being widely used to authenticate API. Is it going to be useful while authenticating traditional session based apps? I haven't seen any example where the proper SSO is implemented with more than one application and laravel passport.
I know OAuth 2.0 is not an authentication protocol. Rather it uses something called Authorization but we probably can make it work to support Authentication protocol as mentioned here. Is it something, that Laravel passport supports?
This is what I call a resource oriented approach where all the clients(app1, app2...) want to know weather requesting user is authorized to access the resource or not...
Here we need to shift all the authenticating logic to oauth and make all our requesting apps dependent on OAuth. This way if user request app to access resources then if:
Token is present then app will request oauth server to validate given token and if found true then app will provide access to user.
If token is not present then you can solve it by asking for credential and app will transfer user data to oAuth server and validate it respond with the token.
As per my experience I use to implement this approach and I think Laravel Passport is an abstraction layer over top of your authenticating system. You can mold it however you need. There are few more enhancement and advancement can be done but this would work as a basic layer over top of your SSO.
You can achieve this with passport however you are right about the examples as there are not many or lacking on some steps.
You could to create a new middleware in App1 and App2 side that communicates with identity.mysite.com and gets the user data (token, scopes, etc, id) then it will verify if the token is valid.
On the passport server side you need an endpoint to return whether the token is valid or not and any additional info.
To avoid making too many requests to your passport server i would recommend to create a service that get the TTL of the access token and set it as the time on cache on App1 or App2 for the user data.

spring boot oauth2.0 and spring security: How to grant permission(authorities) to user login via facebook or slack

I have an auth server built using spring boot oauth2.0 and follows david_syer model.
My auth server does following -
Let user login via third party oauth provider like google or let user create his account on our server using username and password and generate token.
So, when user uses external oauth like google to login then I simply store the token and pass the same(google) token to my UI app for accessing resource api servers. I have an authentication filter that verifies token and allow api access.
When user uses username and password to get token we store user and his permissions and generate a token for him. Now UI uses our auth servers generated token to access resource api servers.
Now my question is
Is this the correct way of using token from external api and using the same to access our resource api server?
And how do I add authorities to user who are signing up using 3rd party oauth provider since I don't add user entry and authorities for them?
So, spring security which loads user and user authorities (loadUserByUsername() from UserDetailsService) will not have any thing if user came from eternal provider.
I have a suggestion for step 2:
After the user uses the google authentication, and gets redirected back to your application page, do the claims transformation on your server and generate your own token issued by the identity server that you have.
The reason is you will be able to provide specific claims and the claims names does not necessarily required to match up.
That way you keep verifying your own token all the time on the client app. So lets say the user uses Facebook instead of Google and even in that scenario as you will assign your own token, you need not to verify the token coming from different third party Identity servers.
That way, your identity server trusts Facebook, Google provided token and your application will trust only your identity server so your app doesn't need to know about what IDP is issuing the token.
And with the approach I suggested above, you will be able to even modify the claims for the user on your own and don't have to depend upon the third party identity server to provide claims.

Resources