I'm testing out the recently released DocumentDb and can't find any documentation indicating best practice on how to perform user data segregation.
I imagine the rough design would be:
Authenticate the user and create new/obtain existing user id
On document insert inject the user id into the document
On read of document/collection of documents query where document user id = current user id
I'm creating an AngularJs application and currently use an Azure Sql Database combined with Azure Mobile Services.
Mobile services handles the user authentication and also the server side user data segregation by the use of data script javascript functions:
e.g.
function insert(item, user, request) {
item.userId = user.userId;
request.execute();
}
Any suggestions on what would be the technique for secure user data segregation from AngularJS using DocumentDB?
Your approach sounds reasonable to me - assuming the logic mentioned in your rough design takes place in your backend service.
Generally, I'd treat DocumentDB similarly as you would treat any other datastore. Your client (AngularJS) makes calls to your backend service, rather than making calls directly to your datastore. Your backend validates the client's request (i.e. assert that the user is authenticated and may touch a particular piece of data) before delegating any work to your datastore.
If direct database access from the client is desired - you can check out DocumentDB's users and permissions. For implementing multi-tenancy for your application, you can create users in DocumentDB which corresponds to your actual users or the tenants of your application. You can then create permissions for a given user which correspond to the access control over various collections, documents, attachments etc. On your client, you can connect to the database using the User's resource key rather than your DocumetnDB's administrator keys.
Check out this blog post on DocumentDB users / permissions: http://blogs.msdn.com/b/cloud_solution_architect/archive/2014/12/09/permissions-in-azure-documentdb.aspx
Related
I have 3 microservices that hold particular user information including their sign-in credentials (email + password). If the services are A, B, and C then the user "John" will have his info stored separately in all three of these services' database.
Now, the user info in service A is updated at an earlier point of time, and at that moment it is not predictable whether services B or C will definitely be activated to be used by that particular user. So, there is no point in creating an entry in B and C for "John". But, as "John" activates B or C at a later point of time, the system can only have access to the hashed password.
It is to be noted that the service C requires the password to be stored in encrypted form so that it can be decrypted later. So, merely storing the hashed value in all 3 services is not feasible, neither do we want all 3 of them to have encrypted password.
What is a feasible solution to sync the password between the services by maintaining the requirements?
Your approach implies a lot of problems in addition to the one you already described yourself. I recommend to look into Federated Identity (using OAuth2 and OpenID Connect) which fits for Microservices architectures.
Basically, this means that authentication and credentials handling is performed by a separate highly available and scalable service (usually referred to as identity provider or authorization server) that only does that - handling user credentials, identity and access control - and does it well.
It handles login and issues access tokens which are then sent to your Microservices along with the requests. As each Microservice will trust this identity provider it will be able to verify that the token is valid and was issued by this identity provider (this happens by validating the token with a public key). And the token contains information like user id and information about what actions are allowed with this token.
The identity provider can be a cloud service like Okta, Auth0, Azure AD B2C, etc. (see https://openid.net/developers/certified/#OPServices) or host an identity provider on your own, if you are not able to access cloud services, by using ready-to-use libraries available for your technology stack (https://openid.net/developers/certified/#OPLibs).
So there is no need to store user credentials in each Microservice and sync this information between them. I would consider such an approach as an anti-pattern.
The federated authentication approach also allows to solve other problems such as single-sign-on.
If you are new to that topic it can be a little overwhelming at first but it's something you can't get around if you really want to have all the advantages a Microservices architecture can provide.
This article might help you get started:
https://nordicapis.com/how-to-control-user-identity-within-microservices/
So from what I have read on IdentityServer I should be storing details about the user such as first name and last name inside claims. How would a web application then be able to access the claim information? Since the User Info endpoint requires a valid access token representing the user, I suppose I would need to make an API that could access that returned the profile information of other users? Is this the right way to do it? (use case, web page needs to display contact details that are stored in claims of another user)
Also what would be the way for multiple language profile information be stored and retrieved in the claims? For example a user can have a name/title in multiple languages. I'm thinking of making [LanguageCode]_[ClaimType] (fr_first_name) naming convention and either adding all languages to just the profile IdentityResource or creating separate resources per language.
Your best bet is to set up a project using the IdentityServer4 QuickstartUI example and review that code to better understand how it all works. As of version 4, Identity Server is only focused on the sign-in / sign-out process and the various flows around authentication. They also provide a basic EF-driven persistence model, and they also support the ASP.NET Core Identity persistence model (also EF-driven), but both of those are not meant to be production-ready code.
Basically, persistence of user details is considered your responsibility. That being said, the cookies used for ASP.NET Core authentication greatly restricts how much data you can/should store as claims. The best model is to keep "real" identity provider (IDP) claims as claims, don't add new claims to that list, copy what you need into some other separate user-data table you manage completely, and use the unique claims identifier (almost always "subject id") as the key to your user data. This also makes it easier to migrate a user to another IDP (for example, you'll know user details for "Bob" but he can re-associate his user data away from his Facebook OIDC auth to his Google auth).
Basic persistence isn't too difficult (it's only 12 or 13 SQL statements) but it's a lot more than will fit in a Stackoverflow answer. I blogged about a non-EF approach here -- also not production-ready code (for example, it has ad-hoc SQL to keep things simple), but it should get you started.
I'm using Identity Server 4, Asp Identity, EF Core and one database.
I have 3 projects at the moment
IdentityServer - Contains all data contexts and all migrations with my app tables
Api - no context, no migrations however I need to access database somehow from here
Clinet - javascript
The question:
How do I access data context from IdentityServer project and still have all settings (db connection, etc) in one place. I understand I can reference IdentityServer from API and use data context but it seems not right to me. What is the preferred way to do this ?
Since you are interested in this option, I've decided to move my comments to this answer.
First of all, IdentityServer is not the place for your app tables. These are seperate contexts and separate migrations. The preferred way is to maintain the separation of concerns.
As I explained in my answer here, you don't need a relation between the login user and your business context. Instead create a user in the business context. The login user has a different purpose than the business user.
I don't have code for you, but you can take one of the sample apps from IdentityServer. Adjust the API to use your business context. In that context add a user table (which links to the sub claim) and the fields you need for the business context. BTW it doesn't matter if the tables are in the same database, just don't mix the contexts.
In IdentityServer: if the user may register for one website then you can extend the registration form with a drop-down of available websites. Or a list if the user can register for multiple websites.
Now it depends on the chosen strategy. You can wait to register the user in the API, but I think it is far more easy to register the user straight away. There are other options, but here's one where it is part of the IdentityServer configuration (without adding business logic to IdentityServer):
Extend IdentityServer to call the API after registering the user. For this I would add a table in the IdentityServer context with URLs to register per website. When the login user is created, call the configured API(s) to register the business user.
In the API you need to add the method that IdentityServer can call to create the user, linked to the sub claim and including the required user information. This way you can suffice with the sub claim to identify the login user and link this to the business user.
You can use a similar strategy for client apps. Extend IdentityServer with an API method to allow client apps to register users.
If you want to withdraw access, you can delete the login user without having to delete the business user. Which you don't want if you don't want to destroy historical information. You can also use claims to specify if the user has access to the website without having to delete the login user.
What is the best design approach in term of security, performance and maintenance for REST API that has many subscribers (companies)?
What is the best approach to use?:
Build a general API and sub APIs for each subscriber (company), when request come we check the request and forward it to the sub API using (API Key) then retrieve data to general API then to client.
Should we make single API and many databases for storing each subscribe(company) data (because each company has huge records that why we suggested to separated databases to improve performance)? when request come we verify it and change database Connection String based on client request.
Should we make one API and one big database that handle all subscribes data?
Do you suggest any new approach to solve this problem? We used Web API and MS SQL Server and Azure Cloud.
In the past I've had one API, the API is secured using OAuth/JWT in the token we have a company id. When a request comes in we read the company id from the JWT and perform a lookup in a master database, this database holds global information such a connection strings for each company. We then create a unit of work that has the company's conneciton string associated with it and any database lookups use that.
This mean that you can start with one master and one node database, when the node database starts getting overloaded you can bring up another one and either add new companies to that or move existing companies to take pressure off. Essentially you're just scaling out when the need arises.
We had no performance issues with this setup.
Depends on the transaction volume and nature of data, you can go for a single database or separate database for each company.
Option 2 would be the best , if you have complex data model
I don't see any advantage of going for option 1, because , anyway general API will call for each request.
You can use the ClientID verification while issuing access tokes.
What I understood from your question is, you want an rest API for multiple consumers(companies). Logically the employees from that company will consume your API, employees may be admin, HR etc. So what I suggested for such scenario you must go with single Rest API for providing the services to your consumers and for security you have to use OpenId on the top of OAuth 2. This resolves the authentication and authorization for you.
Our current process is BizTalk expose a web service for vendor to call in, where the request header contains pre-assigned user name and password. Upon receiving service call, BizTalk validates the credential against the database, extract and attach some metadata from db record to the inbound message (e.g. city, vendor level etc)
Question,
can we replace this process with Azure Active Directory? Heard it does provide a restful API, but get confused everytime reading the documentation when talk about JWT token... Does it have a straight forward restful endpoint to call to validate and extract user information?
can we customize the metadata within the AAD user?
Thanks for the help!!
1 - sure you can. There is no endpoint to perform validation, but it's easy to validate incoming tokens - we offer components that automate it. See https://github.com/AzureADSamples/NativeClient-DotNet for an example. The same location on guthub has lots of other samples demonstrating different scenarios.
2 - I am not certain I understand what you mean with metadata here. If you are referring to the info you can specify about the user: you can customize the user scheme. See https://msdn.microsoft.com/en-us/library/azure/dn720459.aspx