How should a message queue consumer impersonate a user in Identity Server 3 in a microservices environment? - windows-services

We have a microservices environment using Identity Server 3. Identity is provided to http microservices via bearer tokens in the authorisation http header, where the token is a JWT. That JWT usually represents a logged in end user, but it can also sometimes represent a system user that has authenticated via client credentials flow.
Messages are published on a queue (RabbitMQ) by these microservices, to be processed asynchronously. Currently, we have a windows service which consumes those messages. It authenticates as a system user with client credentials, and sends that JWT in the auth header to other http microservices.
We would like to maintain the identity of the user that publishes the messages throughout the flow, including within the machine-to-machine (m2m) communication when a message is consumed from the queue and when that consumer calls other microservices. Ie, when Service A (which was provided with a JWT) publishes a message to the queue, then the windows service should be able to impersonate the user represented in Service A's JWT, and should be able to provide a JWT representing that same user when calling Service B.
Service A (running as alice) --> RMQ
RMQ <-- Win Service (running as alice) --> Service B (running as alice)
Only clients with the correct claim should be able to impersonate a user in this way.
Which flow should I use in order to return the JWT to the Windows Service and how should this be achieved in Identity Server 3? I've managed to generate the JWT using Resource Owner flow, passing in a dummy username and password (overriding AuthenticateLocalAsync), although I've not yet attempted to check that the Win Service's client has a valid claim to impersonate. Or should this be a custom flow, implementing ICustomGrantValidator? Perhaps client credentials flow can be used?
Note that the original JWT can be provided with the message, or just the user id itself. The original JWT may have expired, which is why the windows service has to re-authenticate in some way.

My understanding is you want to propagate authenticated identities through a distributed architecture that includes async messaging via RabbitMQ message broker.
When you send/publish messages to RabbitMQ you might consider including the JWT in the message headers i.e. similar to how JWTs are included in HTTP headers for calls to protected HTTP routes. Alternatively if you're feeling a bit lazy, you could just have the JWT directly on the message payload. Your async (Windows service) consumer could validate the JWT on it's way through or it might just pass it through on the subsequent HTTP requests to protected routes of 'other http microservices'.
I'm not sure if you're question about 'which flow should I use' is relevant as presumably the user is already authenticated (via one of the OIDC/authN flows e.g. authentication code grant, implicit, ROPC...) and you're just looking to propagate the JWT through the distributed architecture for authZ purposes...
In terms of sending custom message headers, I have done this with RabbitMQ and MassTransit, but it was for (OpenTracing) trace Id propagation between asynchronous message broker operations. Repo is on GitHub here - might give you some ideas about how to achieve this...
[edit] following clarification below:
Below are some options I can think of - each one comes with some security implications:
Give the async (windows service) consumer the JWT signing key. If
you go down this path it probably makes more sense to use symmetric
signing of JWTs - any service with the symmetric key would be able
to re-create JWTs. You could probably still achieve the same result
with asymmetric signing by sharing the private key, but (IMO) the
private key should be only be known to the authorization server (when using asymmetric signing).
When the user authenticates, request a refresh token by adding
offline_access to the list of scopes specified on the /token
endpoint. You could then pass the refresh token through to the async
(windows service) consumer, which would be able to use the refresh
token to obtain a new access token if the previous one has expired (or just get a new one each time).
There's probably some security considerations that you'd need to
think about before going down this path.
Increase the timeout
duration of the access tokens so that there's enough time for the
async (windows service) consumer to handle the requests. Not sure if
this is viable for your scenario, but would be the easiest option.

Related

Can Oauth be used securely from the client side for a back-end service?

I have a web app (C# / Javascript) where I want to call a back-end service that I own. I want to secure that service so only my app(s) can call it. Seems like if I use Oauth on the client side, the secret is exposed? All the docs I read about Oauth give solutions when the user of the app owns the resource, not when the app itself owns it. I was looking at how google apis work, and the JavaScript libraries seem to expose the key on the client side, no?
Yes you can accomplish this with OAuth, but how you go about it depends on the details of how the data accessed via your back-end service is organized. If the data is actually user-specific, then your user really is the resource owner. In this case you would use the typical authorization code grant. With this grant type you register a client with the OAuth auth server and receive a client_id and client_secret. The client_id is, indeed, exposed in the browser, but the client_secret sits in your web app server and is never exposed. It is only sent on back-channel (non-browser) requests to your auth server. The main thing here is that only your own client web app would be registered and receive the client_id/client_secret. You simply need to not provide any public registration endpoints so no other clients can register. With this grant type, in order for your web app to gain authorization to access the user's data on the back-end service, the user would need to approve the authorization in the browser as part of the process.
On the other hand if the data you're accessing on your back-end service is not user-specific, then you can use the OAuth Client Credentials grant. With this grant type you register the client as before and receive a client_id and client_secret. The secret is stored securely on your web app server and only passed in back-channel requests. You would avoid allowing any other clients to register. Your web app can then gain authorization to your back-end service without even needing any user authorization in the browser.
I'm afraid there is no way to restrict your API to be called just by the code of your applications. Browser applications with public codes cannot hold any secret (such as certificate), that would identify them, because anyone can extract it from the code. Desktop and mobile applications compiled to bytecode are not so easy to read, but with some effort, attacker could find the secret data. That's also the reason why these applications (so called public clients) don't hold client_secret if they act as OAuth2 clients. They use a one-time secret instead - PKCE.
What you can do, is to check the audience (what client ID the token was issued for) of an access token sent from a frontend application to your backend. You can get this info either from the token introspection endpoint (aud attribute) or from JWT attributes if the token is of JWT type.

OAuth 2.0 Flows for Microservice Architectures

I'm trying to understand how to best apply the OAuth 2.0 grant types to a microservice architecture I am working on. Here's the situatation...
I have a Single-Page Application/Mobile App acting as a client running in a web browser (browser acting as the user agent) or mobile phone. I use the Implicit Grant defined in RFC 6749, section 4.1 to authenticate a user and acquire an access token that the app uses to access some externally exposed API.
The architecture I am dealing with is a collection of microservices that call on one another. For example, consider an externally exposed API serviceA and internal APIs serviceB and serviceC. Let's say serviceA depends on serviceB which subsequently depends on serviceC (A --> B --> C).
My question is, what is the typical authorization flow for this situation? Is it standard to use Implicit Grant for the SPA to acquire an access token and then use the Client Credentials Grant defined in RFC 6749, section 4.4 to acquire an access token for the machine to machine interaction between serviceB and serviceC?
For your single page application, use the Implicit grant, which is designed for browser applications - they cannot hold any secrets and with the Implicit grant, the tokens stay in the browser (because it's in the hash part of the redirect URL).
The mobile app, take a look at the OAuth 2.0 for Native Apps, it recommends the use of the Auth code grant. It also describes implementation details for common platforms and security considerations.
There is a new grant described in the OAuth 2.0 Token Exchange RFC that would suit your needs for chained calls between services:
... An OAuth resource server, for example, might assume
the role of the client during token exchange in order to trade an
access token, which it received in a protected resource request, for
a new token that is appropriate to include in a call to a backend
service. The new token might be an access token that is more
narrowly scoped for the downstream service or it could be an entirely
different kind of token.
But I don't know whether Auth0 supports it. If it doesn't, I would probably pass the original access token from serviceA to serviceB and serviceC. The internal services could be secured at the network level too (e.g. they could called just from other services).
If serviceB and serviceC are internal and will never be called from an external client then the Client Credentials Grant would be a good candidate. As the client is also a resource server too.
You could also look at passing the same bearer token between services, providing the SPA (which requests the token initially) obtains consent for all scopes which may be used by the other services and the "audience" of the token must allow for all the possible resource servers (services).
I don't think either are best practice and there are tradeoffs with both ways.
I would honestly recommend for each backend service to implement the Authorization Grant. That is have an endpoint exposing the redirect to your provider. Then for each frontend app go to that endpoint to trigger the OAuth flow. After the flow has been completed handle the Authorization part in the callback url and return a token which will be stored on the frontend somewhere.
Hope this helps.

Keycloak - OpenId Connect Access types

I'd like to authenticate a legacy java (6) application against a node-js one currently secured using keycloak OIDC bearer only (both apps belonging to same realm).
I've been told to use keycloak-authz-client library resolving a keycloak OIDC JSON as below
{
"realm": "xxx",
"realm-public-key": "fnzejhbfbhafbazhfzafazbfgeuizrgyez...",
"bearer-only": true,
"auth-server-url": "http://xxx:80/auth",
"ssl-required": "external",
"resource": "resourceName"
}
However, the keycloak java client required java 8 and my current runtime is a jre6. Recompiling the lib including transitive dependencies does not looks like a good idea and I end up so using keycloak oauth2 REST endpoint.
As far as I know oauth2 I would go with a client_credentials flows exchanging a client secret against an access_token once at application initialization and refreshing / renewing when expired.
Coming to keycloak documentation :
Access Type
This defines the type of the OIDC client.
confidential
Confidential access type is for server-side clients that need to perform a browser login and require a client secret when they turn an
access code into an access token, (see Access Token Request in the
OAuth 2.0 spec for more details). This type should be used for
server-side applications. public
Public access type is for client-side clients that need to perform a browser login. With a client-side application there is no way to
keep a secret safe. Instead it is very important to restrict access by
configuring correct redirect URIs for the client. bearer-only
Bearer-only access type means that the application only allows bearer token requests. If this is turned on, this application cannot
participate in browser logins.
It seems that confidential access type is the one suitable for my needs (should be used for server-side applications) however I don't get how it is related to browser login (which is my mind is related to authenticating using third parties identity providers as facebook and co).
The confidential client settings also require a valid redirect uri the browser will redirect to after successful login or lagout. As the client I want to authenticate is an application I don't see the point.
Generally speaking I don't get the whole access type things. Is it related only to the client or to the resource owner also (Is my node.js application stuck to bearer-only as existing clients use this access type ? will it accept the bearer authentication using the access_token obtained with client_credentials flow ? I suppose it will).
Can someone clarify keycloak OIDC access type and where I went wrong if I did ?
What is the proper way to delegate access for my legacy application to some resources (not limited to a specific user ones) of another application using keycloak ?
You are mixing up the OAuth 2.0 concepts of Client Types and Grants. Those are different, albeit interconnected, concepts. The former refers to the application architecture, whereas the latter to the appropriate grant to handle a particular Authorization/Authentication use-case.
One chooses and combines those options; first one choses the client type (e.g., public, confidential), and then the grant (e.g., Authorization code flow). Both client types share some of the same grants, with the caviar that the confidential client will require also a client secret to be provided during the execution of the Authentication/Authorization grant.
From the Oauth 2.0 specification:
OAuth defines two client types, based on their ability to
authenticate securely with the authorization server (i.e., ability to
maintain the confidentiality of their client credentials):
confidential
Clients capable of maintaining the confidentiality of their
credentials (e.g., client implemented on a secure server with
restricted access to the client credentials), or capable of secure
client authentication using other means.
public
Clients incapable of maintaining the confidentiality of their
credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web
browser-based application), and incapable of secure client
authentication via any other means.
As one can read the client type refers to the type of the application architecture. Why do you need those types? The answer is to add an extra layer of security.
Let us look at the example of the Authorization Code Grant. Typically the flow is as follows:
The user goes to an application;
The user gets redirect to the Keycloak login page;
The user authenticates itself;
Keycloak check the username and password, and if correct, sends back to the application an authorization code;
The application receives that code and calls Keycloak in order to exchange the code for tokens.
One of the "security issue" with that flow is that the exchange of code for token happens on the frontend channel which due to the nature of browsers it is susceptible to a hacker intercepting that code and exchange it for the tokens before the real application does it. There are ways of mitigating this but it is out of the scope of this question.
Now, If your application is a single-page application, then it cannot safely store a secret, therefore we have to use a public client type. However, if the application has a backend where the client secret can be safely stored, then we could use a confidential client.
So for the same flow (i.e., Authorization Code Grant), one can make it more secure by using a confidential client. This is because the application will now have to send to Keycloak a client secret as well, and this happens on the backend channel, which it is more secure than the frontend channel.
What is the proper way to delegate access for my legacy application to
some resources (not limited to a specific user ones) of another
application using keycloak ?
The proper grant is to use the so called Client Credential Grant:
4.4. Client Credentials Grant
The client can request an access token using only its client
credentials (or other supported means of authentication) when the
client is requesting access to the protected resources under its
control, or those of another resource owner that have been previously
arranged with the authorization server (the method of which is beyond
the scope of this specification).
Since this grant uses the client credentials (e.g., client secret) you can only use it if you have selected confidential as the client type.

Client authentication on Public Client

Studying OAuth2.0 I finally found these 2 refs:
RFC6749 section 2.3,
RFC6749 section 10.1
Correct me if I'm wrong:
It's possible to use unregistered clients, but you have to manage them yourself with security risks.
How should I manage them?
Some more specific questions:
A Native Application (a Public Client indeed) is not able, by definition, to safely store its credentials (client_id + secret). Is it an unregistered client? If I can't verifiy/authenticate it using a secret, what else should I do?
client registration ≠ endpoint registration: the first is about registering Client Credentials (client_id + secret); the second about registering Client Redirection Endpoints. Is the Redirection Endpoint registration sufficient to grant the authenticity of the Client?
Does Client Credential Grant use the same credentials (client_id + secret) for client registration?
I think you could answer me by explaining what does this paragraph (RFC6749 section 10.1) mean.
Please give me some references and practical examples on how to implement the interaction between the authorization server and the resource server.
Thanks
tl;dr:
Native clients cannot be authenticated with client_id and client_secret. If you need to authenticate the client, you'll have to implement an authentication scheme that doesn't entrust the shared secret to the client (or involve the end-user in the client authentication discussion). Depending on your application's security model, you might not need to authenticate the client.
The redirection endpoint is not generally sufficient to authenticate the client (though exceptions exist).
The "client credential" grant type may use any client authentication mechanism supported by the authorization server, including the credentials given out at client registration.
The gist, as I read it, is that you can trust a confidential client's client_id (read: "username") and client_secret (read: "password") to authenticate them with your service. There is no[1] chance that a third-party application will ever represent itself with that client's credentials, because they are reasonably assumed to be stored safely away from prying eyes.
A public client, however, can make no such guarantee – whether a browser-based application or a native desktop application, the client's id and secret are distributed to the world at large. It's quite reasonable to assume that such applications will end up in the hands of skilled developers and hackers who can dig into the client and extract the id and secret. For this reason, Section 10.1 explicitly states that:
The authorization server MUST NOT issue client passwords or other
client credentials to native application or user-agent-based
application clients for the purpose of client authentication.
Okay. So public clients cannot be authenticated by password. However…
The authorization server MAY issue a client password or other
credentials for a specific installation of a native application
client on a specific device.
This exception works because it ties the authentication of the client to a specific device, meaning that even if someone walked away with the client's secret, they couldn't reuse it. Implicit in this exception, however, is that the "specific installation … on a specific device" must be uniquely identifiable, difficult to spoof, and integral to the authentication process for that client.
Not every native application can meet those criteria, and a browser-based application certainly cannot, since there's nothing uniquely identifiable or difficult to spoof in the environment in which it runs. This leads to a couple of options – you can treat the client as unauthenticated, or you can come up with a more appropriate authentication mechanism.
The key to the authentication dance is a shared secret – something that's known only to the authorization server and the authenticating client. For public clients, nothing in the client itself is secret. Thankfully, there are options, and I'm not just talking about RFID key fobs and biometrics (though those would be completely acceptable).
As a thought experiment, let's consider a browser-based client. We can reasonably assume a few things about it: it's running in a browser, it's served from a particular domain, and that domain is controlled by the client's authors. The authentication server should already have a Client Redirection URI, so we've got something there, but as the spec calls out:
A valid redirection URI is not sufficient to verify the client's
identity when asking for resource owner authorization but can be
used to prevent delivering credentials to a counterfeit client
after obtaining resource owner authorization.
So the redirection URI is something we should check, but isn't something we can trust, in large part because the domain could be spoofed. But the server itself can't be, so we could try to ask the domain something that only the client's domain's server would know. The simplest way to do this would be for the authentication server to require a second ("private") URI, on the same domain as the client, where the client's secret will be hosted. When the client application makes an authorization request, the server then "checks in" against that second URI relative to the client's reported hostname, and looks for the shared secret (which should only ever be disclosed to the authorization server's IP address) to authenticate the client.
Of course, this is not a perfect solution. It doesn't work for every application, it's easy to get wrong, and it's potentially a lot of work to implement. Many potential authentication mechanisms (both highly specific and highly general) exist, and any one which does not entrust the client application with private data would be suitable for this problem space.
The other option we have is to implement no further authentication, and treat the client as unauthenticated. This is notably not the same thing as an unregistered client, but the difference is subtle. An unregistered client is a client whose identity is unknown. An unauthenticated client is a client whose identity is known, but untrusted. The security implication for both types of clients is the same: neither should be entrusted with private data. Whether the authorization server chooses to treat these two cases the same, however, seems to be left up to the implementer. It may make sense, for example, for an API to refuse all connections from an unregistered client, and to serve public read-only content to any registered client (even without verifying the client's identity).
Pragmatism, however, may yet win out – an unauthenticated client is fundamentally no different than the SSL "errors" you'll occasionally see when your browser cannot verify the authenticity of the site's SSL certificate. Browsers will immediately refuse to proceed any further and report exactly why, but users are allowed to accept the risk themselves by vouching for the identity of the server. A similar workflow may make sense for many OAuth2 applications.
Why is it important to verify the client's identity, anyway? Without doing so, the chain of trust is broken. Your application's users trust your application. The authorization workflow establishes that your users also trust the client, so your application should trust the client. Without validating client identity, another client can come along and assume the role of the trusted client, with all of the security rights thereof. Everything about client authentication serves to prevent that breach of trust.
Hope this helped!
[1]: Server compromises, where the source code of your application falls into malicious hands, are an exception to this, and there are other safeguards built-in for that case. Having said that, the spec also specifically calls out that a simple username/password combination isn't the safest option:
The authorization server is encouraged to consider stronger
authentication means than a client password.

Why must we "change temporary credentials for token credentials" in OAuth?

Can't the server just "upgrade" the temporary credentials to token credentials and retain the same key and secret?
The client can then start doing authenticated calls right away after the recieving the callback from the server stating that the temporary credentials has been "upgraded".
Of cause if the temporary credentials have not be upgrade (i.e. client doesn't wait for callback) the authenticated call fails.
So the question is why make an extra call to the server after the callback to "exchange" temporary credentials for token credentials?
You could implement OAuth in that way, but as I understand it, separating Request Tokens from Access Tokens does provide an extra layer of security.
From the Beginner's Guide:
OAuth includes two kind of Tokens:
Request Token and Access Token. Each
Token has a very specific role in the
OAuth delegation workflow. While
mostly an artifact of how the OAuth
specification evolved, the two-Token
design offers some usability and
security features which made it
worthwhile to stay in the
specification. OAuth operates on two
channels: a front-channel which is
used to engage the User and request
authorization, and a back-channel used
by the Consumer to directly interact
with the Service Provider. By limiting
the Access Token to the back-channel,
the Token itself remains concealed
from the User. This allows the Access
Token to carry special meanings and to
have a larger size than the
front-channel Request Token which is
exposed to the User when requesting
authorization, and in some cases needs
to be manually entered (mobile device
or set-top box).
So, as I understand it, by limiting the Access Token to a channel directly between the consumer (your service) and the provider (the service you're gaining access to), you can obtain a secure Access Token (that is, one the attacker doesn't have) even if the user's machine or the user's network connection to your service is compromised. If the Request Token were simply upgraded, then anyone sniffing the user's network connection could easily obtain the Request/Access Token, which we'd prefer to keep secret since it can be used (with your consumer token, of course), potentially for a very long time, to access the user's data. A server-to-server connection is often more secure.
Also, as is pointed out above, this lets you have a much longer key in cases where the Request Token actually has to be typed out by the user (and so is probably very short).

Resources