So I've been banging my head against the wall for the past couple days trying to understand how WCF's security architecture worked. I have a goal in mind and I'm not sure that I'm going in the right direction.
The System
We use a combination of Active Directory and databases to manage our authentication and authorization. Client applications typically use their Windows credentials to authenticate and the applications checks against database tables to see if those users are allowed to authenticate and then if they are authorized to use the resources they are requesting. The current setup has each client directly communicating with the database to do these checks.
The Goal
We want to use a Security Token Service to authenticate the client and provide "high level" authorizations for top level resources. The services that provide data or perform actions would operate if the supplied SecurityToken was valid. Additionally, the token, if it did not contain a particular right, would query the token service to see if the user did have rights that were not loaded when the token was initially created. (We have over 300 rights in our database, and that could lead to rather hefty tokens for users with many rights)
What I Don't Understand
1) I understand the token creation process, but I'm a little lost on how the client gets, stores and sends the token to the services it intends to use. Does each "worker" service require a unique token (i.e. call to CalculatorService requires one version of the token and the SaveResultService require a new token to be generated?) Can I manually request, save and send tokens?
2) On the "worker" service side, what is the process by which the token is verified? Does my "worker" service have to contact the Token Service for verification of the token? Or does it just read the token and assume, if it is properly signed, that the token is genuine and operate from that perspective?
3) Is it possible to encrypt my tokens manually and store them on the client side for use while they are valid (thus avoiding authentication attempts on every service call) and so that a web client can save the token between page loads and reuse it on successive calls?
Thanks for helping with my lack of understanding
You should go through the samples for Windows Identity foundation - It providers the classes and implementations required to wrap claims that you can use or query for auth and authz.
http://msdn.microsoft.com/en-us/library/ee517291.aspx
What you are looking for is a durable token cache. - Tokens have lifetimes and usually require renewal and WIF does the renewal under the hood for most scenarios.
You can manually request and attach tokens and pool the proxies using WIF.
Related
I am developing a new distributed application. I already have some operational microservice and it works fine. I am now implementing authentication/authorization and I have serious doubts.
enter image description here
1.- First I authenticate with the JWT microservice and obtain a token. This token contains the claims that indicate which properties that user has access to.
2.- This token has an expiration of 3 days. So when I make a request to a microservice I attach the token.
3.- However, when the request reaches any microservice controllers, how do I confirm that the token is valid and the user has permisions for this controller function? or if the claims have changed since the token was generated ?
Is it necessary to make another request to the JWT microservice to validate it?
Is there a more efficient way to validate each user's permissions in microservice controllers. I would like to not have to send another request to the JWT microservice again.
I have read that an API Gateway is sometimes implemented as an access point. If so, could the user access permissions be validated in the API Gateway? What technology is the most optimal (Camel, Spring Cloud)? To this, I add that we are deploying these microservices in Google Cloud Kubernetes (GKE).
enter image description here
If someone who has experience in microservices can enlighten me.
Thank you
There are two major approaches to token validation: local and rpc call.
Local is way more popular. This is the approach AWS, GCloud and Azure take. The token itself has all required information - who is the user, what are permissions. And the token is signed.
When this type of token is received on a service (or api gateway), the service can validate the token locally - by checking signature and expiration. Base on validated content of a token, the service decides what to do.
It is worth mentioning, that this approach does not allow token to be revoked. There are few workaround, but most solutions just rely on shorter lived token and issue a refresh token. (please, let me know if this is topic to talk more).
Having local validation also opens an interesting approach to limiting scope - when a system issues an access token, the token can have limited access - subset of whatever a user can do. This is nice feature to limit risks.
The other method is to call some internal service for token validation. This seems like easier to understand approach, but it scales purely.
One more thing to note: where token should be checked - on api gateway or on a service itself. Traditionally, access used to be checked on boundaries - api gateway in your case. These days, companies move to Zero Trust Architecture - which means access is verified on every service - there is no implicit trust.
Just found out that the basic workflow for token-based authentication is as follows:
User requests access by providing username and password
The application validates the credentials and returns a token to the client
The token is then stored on the client and sent with every request henceforth
The server then validates the token and returns private data as a response
Now, I understand the flow more or less, however, I'm having issues with the terms application, client and server. I understand the term server to mean where the API is stored... which is also part of the application. But the application could also be anything from a web app to a mobile app on various platforms... a client in other words.
So isn't it true that the application includes both the server and the client. So what does it mean by each term exactly, in the above context?
On second thoughts... I guess the original token is being generated on the server side, and this is then being returned to the client. Is this true?
Those terms terms are pretty overloaded in software development, so it's always difficult to nail down the exact meaning without focusing in a very specific context. Bear in mind that even authentication can be seen as a very broad context.
I would rephrase your proposed workflow to the following:
User requests access by providing a set of user credentials (we don't have to use passwords all the time, see passwordless authentication out of curiosity).
The authorization server validates the user identity and, if valid, issues an access token.
The client application from which the user started the process receives and stores the issued access token.
The client application calls into a resource server using the access token in order to obtain user associated resources.
Damn, now we have even more terms, but let's try to fix that by providing some definitions.
First, the ones more generic:
Client: An application that obtains information from a server for local use.
Credentials: Usernames, passwords, email addresses—any of a variety of means for communicating parties to generate or obtain security tokens.
(source: Auth0 Identity Glossary)
Then definitions within the context of OAuth 2.0 and/or OpenID Connect:
Authorization server: The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.
Resource server: The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.
Client: An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).
(source: RFC 6749)
It's not even useful trying to define application, but what we should conclude from the other definitions is the following:
As you said, a client can range from web, to mobile to event server-side applications.
The role of the authorization server and resource server can be played by the same component, for example, a Web API that has an endpoint protected by HTTP basic authentication that can be used to exchange a pair of username/password credentials with an access token and then all the remaining API endpoints are protected in such way that only allow access if you provide that access token.
Finally, one final note to clarify your last question, yes, the creation of the access tokens need to happen on the server side because the creation of the token will be accompanied by some kind of mechanism that will ensure that the token cannot be tampered with and was in fact created by a very well-know entity. For the case of JWT's this mechanism consists of signing the token which is accomplished by having the server know a secret that no one else knows.
I'm having a hard time choosing a decent/secure authentication strategy for a microservice architecture. The only SO post I found on the topic is this one: Single Sign-On in Microservice Architecture
My idea here is to have in each service (eg. authentication, messaging, notification, profile etc.) a unique reference to each user (quite logically then his user_id) and the possibility to get the current user's id if logged in.
From my researches, I see there are two possible strategies:
1. Shared architecture
In this strategy, the authentication app is one service among other. But each service must be able to make the conversion session_id => user_id so it must be dead simple. That's why I thought of Redis, that would store the key:value session_id:user_id.
2. Firewall architecture
In this strategy, session storage doesn't really matter, as it is only handled by the authenticating app. Then the user_id can be forwarded to other services. I thought of Rails + Devise (+ Redis or mem-cached, or cookie storage, etc.) but there are tons of possibilities. The only thing that matter is that Service X will never need to authenticate the user.
How do those two solutions compare in terms of:
security
robustness
scalability
ease of use
Or maybe you would suggest another solution I haven't mentioned in here?
I like the solution #1 better but haven't found much default implementation that would secure me in the fact that I'm going in the right direction.
Based on what I understand, a good way to resolve it is by using the OAuth 2 protocol (you can find a little more information about it on http://oauth.net/2/)
When your user logs into your application they will get a token and with this token they will be able to send to other services to identify them in the request.
Example of Chained Microservice Design
Resources:
http://presos.dsyer.com/decks/microservice-security.html
https://github.com/intridea/oauth2
https://spring.io/guides/tutorials/spring-security-and-angular-js/
Short answer : Use Oauth2.0 kind token based authentication, which can be used in any type of applications like a webapp or mobile app. The sequence of steps involved for a web application would be then to
authenticate against ID provider
keep the access token in cookie
access the pages in webapp
call the services
Diagram below depicts the components which would be needed. Such an architecture separating the web and data apis will give a good scalability, resilience and stability
You can avoid storing session info in the backend by using JWT tokens.
Here's how it could look like using OAuth 2.0 & OpenID Connect. I'm also adding username & password login to the answer as I assume most people add it as a login option too.
Here are the suggested components of the solution:
Account-service: a microservice responsible for user creation & authentication. can have endpoints for Google, Facebook and/or regular username & password authentication endpoints - login, register.
On register - meaning via register endpoint or first google/fb login, we can store info about the user in the DB.
After the user successfully logs in using either of the options, on the server side we create a JWT token with relevant user data, like userID. To avoid tampering, we sign it using a token secret we define(that's a string).
This token should be returned as httpOnly cookie alongside the login response. It is recommended that it's https only too for security. This token would be the ID token, with regards to the OpenID connect specification.
Client side web application: receives the signed JWT as httpOnly cookie, which means this data is not accessible to javascript code, and is recommended from a security standpoint. When sending subsequent requests to the server or to other microservices, we attach the cookie to the request(in axios it would mean to use withCredentials: true).
Microservices that need to authenticate the user by the token:
These services verify the signature of the JWT token, and read it using the same secret provided to sign the token. then they can access the data stored on the token, like the userID, and fetch the DB for additional info about the user, or do whichever other logic. Note - this is not intended for use as authorization, but for authentication. for that, we have refresh token & access token, which are out of scope of the question.
I have recently created a detailed guide specifically about this subject, in case it helps someone: https://www.aspecto.io/blog/microservices-authentication-strategies-theory-to-practice/
One more architecture perspective is to use nuget-package (library) which actually do authentication/token validaton. Nuget-package will be consumed by each microservice.
One more benefit is that there is no code duplication.
you can use idenitty server 4 for authentication and authorisation purpose
you must use Firewall Architecture hence you have more control over secutiry , robustness ,scalability and ease of use
I'm working on federating an application with various areas and extremely fine-grained permissions. Each of the various areas has a federated WCF endpoint to communicate back to the server. Because of the fine grained permissions, a single token containing all of the permissions can be as large as 1MB, maybe more.
Requirements dictate that the user's username and password credentials must not be held within our code base after the initial log in process. The permissions cannot be combined to create a smaller set. We are using the Thinktecture.IdentityServer for our STS implementation.
My proposed solution is to break each endpoint into its own realm in the STS, and the STS will return a token with the permission claims specified for the realm. To accomplish this I would like to have an Auth realm which is authenticated by username/password and returns a token containing a user, tenant, and subgroup IDs which could then be used as credentials for authenticating to other realms.
Setting up the STS to issue tokens specific to realms has already been implemented. The only requirement remaining is that the username/password is not kept around within our code base.
Is it possible to configure the STS to allow authentication by providing a previously issued token from a specific realm? Is there a better solution which I have not come upon?
Yes, you can authenticate to STS A using a token issued by STS B. STS A has to be configured to trust STS B as a known identity provider.
With thinktecture STS I think you can do this by configuring a new WSStar identity provider. If one realm STS adds the other realm STS as an identity provider, it should begin accepting tokens issued from that realm+certificate.
For WCF, a reasonably painless way to set up issued token channels is with the WIF CreateChannelWithIssuedToken extension method:
http://msdn.microsoft.com/en-us/library/ee517268.aspx
1MB is a very big token indeed. There may be other good reasons to split into multiple STSes in separate realms, but you might alternatively help to solve the problem by dynamically deriving permissions through a policy or permissions stores on the relying party side where your token gets consumed rather than pre-calculating all the granular permissions from the STS side. But I say this without knowing your specific application so feel free to tell me to go away :)
What you really want is re-newing an expired token. We don't support that. And also don't have plans to do that.
You could set the expiration time to a value that works for you - and then force re-login after that.
1 MB tokens are not a good idea - you either need to roundtrip that, or create session affinity. Tokens are meant to describe user identity, not to dump every possible value into them.
Why doesn't the RP load the authZ rules from the IdP via a service call?
Suppose I have a front-end application that wants to fetch some data from a back-end service. (I do.) The service will need to verify that the end-user is authenticated, that it is authorized to use the service and possibly filter the returned data based on the user's privileges. In my case, both the front-end app and the back-end service relies on Azure ACS for authentication.
Ideally the front-end would like to act on the behalf of the authenticated user, which sounds like a good fit for using an ActAs token (as specified in WS-Trust). However, it turns out that ACS does not currently support ActAs.
A workaround could be to use the actual bearer token (the bootstrap token in the front-end app) to authenticate to the back-end service. It's not hard to do, but would it be a bad idea for some reason?
From your front-end app, you could certainly pass along the identity data of the end user by either sending the token as is or sending the attributes from it. Both have issues. For the former, if it's also encrypted, the front- and back-ends will have to share the private key needed to decrypt it; they will also have to share audience restrictions, etc. in order for the back-end to consider the token valid for it. In other words, the front- and back-ends will be ONE relying party, not two. Might not be a problem, but be aware. In the latter case, you end up sending user data in a proprietay way which could increase integration and maintenance costs over time. In both cases, you can authenticate the front-end app to the back-end using some other type of credential, e.g., a certificate used at the transport level and, thus, forming a trusted subsystem between them.
One thing that I would suggest you consider instead is OAuth 2. From this blog post, it seems to me that ACS supports it (though I don't have any first hand experience w/ it). The truely wonderful thing about OAuth 2 is that it bakes delegation in, and is NO WHERE near as complex as ActAs in WS-Trust. The net result is the same, i.e., the back-end service will have info about the calling service and the end user, but the amount of effort to get it setup in incomparable. The tokens will still be bearer tokens, but you can mitigate that to a degree by using SSL. Beyond SSL, you can put some additional measures in place, but the best, IMO, would be if Microsoft did something in ACS like Google has done w/ their Access Tokens for service accounts which uses asymmetric keys that are chained up to a PKI. (BTW, for all I know, Microsoft may have already done something like that; if so, you're set.)
Anyway, HTH!