I'm working on multiple projects for single entity, they want the user to have to register just once for all their products (something like Google where you have one Google account for products like Gmail, Drive, YouTube, ... etc.).
My choice for the technology is Identityserver4 with ASP.Net Identity as user credentials store. For this problem I decided to use separate database for Identityserver and separate database for ASP.Net Identity(User profile, claims, credentials, ... etc.) because, and based on my very humble experience, identity-server is concerned about authentication & authorization but not the mean of storing user data and how to register new users or keeping and maintaining the user data, please correct me if I have a misunderstanding here. I'm not very experienced with Identityserver so I think I'm doing huge risk by going with this design. For example, I have audit columns (CreatedBy, UpdatedBy, DeletedBy) in multiple tables in all of these products besides ownerId in most of the tables in these databases.
So my question is:
How should I reference the user (via CreatedBy, UpdatedBy, DeletedBy, OwnerId columns) in the central database in these products databases and should I ever do that (separating the user-store database)?
And in regards to the user-profile information (user-claims):
Those products share many of the information between users like (First name, middle name, last name, address, phone numbers, etc...) and they have other optional info (university, high school) and other that required by some, optional by some, and totally irrelevant by others.
Should I store all these claims in one central table (user-claims
table in the identity database) and then generate customized profile
via the ProfileService based on the the client (the user
authenticating to) and the accessToken (what the user allow this
client to see from it's profile data)?
I hope this question is not an off-topic here in SO and not too-broad.
It was a good decision to build your application with IdentityServer 4 and Identity framework. Because the combination of both has very powerful features (Authentication, Authorization, User management).
As you decided, implement this as one application in your echo system. So now this System works individually for User management, Authentication and Authorization. As an example create users, user groups, user claims, 2FA.... all should be handle in this Application.
Now you can Think above identity server as the third party application (think it as google). So when Login through google it gives us a token that token contains many details depending on what we requested (User ID, Email, Frist name.....).
Okay, now let's think about your second application in the echo system. it doesn't know anything about the users inside the identity server. It only knows the details coming inside the token.
Depending on that token details maintain a separate user table in your second application. you can use Email or userId to keep the mapping of the Identity server user and new Application user.
For all requirements in the second application use this table to refer the user.
Related
The requirements
we have 3 modules ui, api, IdentityServer (IS) (client, resource, IS in terms of IdentityServer)
all the modules should be separated from each other (separate dbs for IS and api)
api is stateless (all the needed auth info got from tokens)
the api will have resources like \projects, \users, etc.
another entry point may be added in the future like another-ui which will communicate with the IS and api and will have its own claims
The problems
The main problem is that the resources of api like \projects\12345, \users\, \projects\123456\users, etc. may also be needed as claims in IS. For example, api module reads the access token of authorized user and see the claim projects that equals ["222", "12345"], so the resource \projects\12345 or \projects\123456\users are allowed for that user.
Users are identities in IS and resources in api at the same time. Projects are claims in IS and resources in api at the same time.
I thought of book-keeping these entities that are represented in both modules through the ids (guids). But ids won`t solve all the problems.
Some of them are:
creation of a new project with its id should grant that user the rights to use it in the future, so we need save the claim for that user in some way. The modules are separated, so should we call the IS api to create that claim for that user and then proceed with project creation. How the communication between the two (IS and api) should be organized? Do we need to register the api as another client in IS?
How should updates of users in IS like changing the email, phone (the values one may log in with) will update the api. I thought of showing warnings that the auth email (got from token) does not match the info email.
Could you, please, explain how modern systems coupe with the per resource access?
Thank you for your time.
First you need to make sure what a claim is.
Claim is not a permission or a role, it's what the user is. Based on what the user is, then you can assume the permissions.
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/claims?view=aspnetcore-3.0
A claim is a name value pair that represents what the subject is, not what the subject can do.
So starting from that, you can get the claims and do the following.
Let's say that a user is the owner of a project. When the new project is created, the project api can update the identity server and add a claim to the user saying he is the owner.
In your apis the owner of a project has a set of permissions and based in those, access to specific resources
In the DDD Domain driven design world, a little bit of data duplication does not matter. So duplicating the possible claims that your application needs in terms of roles (again, not ids but a mapping of one or more claims to specific roles) is not a bad practice.
When you update some kind of claim from your api, you should do so in a transactional way. Think first if you need the email to be saved in both. You will get the user data from the claims anyway on every request. Is it even something you need as a claim? If not have it in your api only.
Communication between apis is organized in many ways. If you need transactions or eventual consistency is something you should also consider. Communicating with events or queues is the microservices way to go, with patterns like the SAGA being the coordinator.
We have a multi-tenant ASP.NET application. So far tenants have been isolated from each other, however now we have Agencies that manage multiple tenants and want to be able to manage all their tenants with a single user account. I'm trying to figure out the best way to accomplish that, hopefully without much change to the existing technologies that we are using.
Relevant technical details:
AspNetSqlMembershipProvider for both membership and roles
C# 4.0 (soon to be 4.5)
Forms Authentication
Both aspx and MVC (v3) pages
Assume 100 or more tenants, so any solution needs to support that
I believe the requirements are very similar to the security model for SQL Server. We have one set of logins which represent all the users that can login to the system. Users should be able to be given roles to one or more databases (tenants). Example: User Bob has admin role in company A, but only user role in company B. We also have a "sysadmin" role for my company's employees which allow us access to any tenant as well as specialized administrative privileges such as create/delete tenants, etc.
I've done a lot of research into various libraries, frameworks, etc, and I haven't found any convincing evidence that some other library or framework will be better than what we currently have. So I'm currently thinking of just figuring out how to make Sql Membership provider do what I want, unless someone can point me in a better direction. I'm also not sure I know the best terms to search for in this.
I've got 2 options I'm considering:
Add only a handful of roles to the membership provider and handle all the questions of "does the current user have this role in this tenant" outside of membership provider. Membership provider would be used to handle basic access to the system.
Add tenant specific roles to membership provider. We would have (# of roles) x (# of tenants) total roles in the system. Each new tenant would add another set of roles to the system, e.g. "Tenant A:Admin", "Tenant A:User", etc. Would need some additional tables to manage the relations as well as probably some custom code to ensure that access is requesting the correct tenant-specific role from the membership provider.
Are either of these options good? Or should I be looking elsewhere for support for this?
I don't think you are going to be able to shoehorn multitenancy into any out of the box role provider, so you might as well keep using SqlMembershipProvider (and SqlRoleProvider). Even the newest Microsoft.AspNet.Identity still assumes a vanilla many-to-many between users and roles. What you really need is to add a 3rd column to the primary key of that many-to-many table, which will id your tenant, i.e.:
user: 6
role: 4
tenant: 17
user: 6
role: 9
tenant: 18 (and so on)
...with this, you are able to have users with different privileges for different tenancies, all using the same set of role names.
If you went with option #2, then your [Authorize] attributes would explode. Imagine this:
[Authorize(Roles = "TenantA:Admin", "TenantB:Admin", ...)]
public ActionResult Post(int id, SomeViewModel model) {}
... all of those attributes would have to be written at compile time unless you went with a custom AuthorizeAttribute, which you could do. But even then you are left creating a new set of roles each time you add a tenant to the system, which should not be necessary.
I work on a big multi-tenancy application. We came to the conclusion that it was easier to maintain separate databases per tenant, and have the web application automatically switch database contexts, rather than try and use an over-complicated database schema to model different tenants.
The benefits
Tenant data is compartmentalized by default into different databases
Tenant data can be exported as a database dump for client MI
Database design is vastly simplified
The drawbacks
You have to manage multiple databases - operations challenge
You have to develop database switching code
Implementation using multiple databases
We used a configuration database that has client settings based on an account code. That account code can come from a login screen or you can map subdomain to client code.
When the app starts you load all tenants into cache (containing connection strings)
On every request you have to determine the client and then switch the db context
I have also developed a multi-tenant application that uses a single database. You quite quickly have problems making sure that you don't cross tenant data. Every query needs to include a tenant id filter. The database queries are therefore always slower as a result, although you can index everything you can to try and improve the situation.
With regards to the Membership question, you can install the membership schema into each tenant database.
What doesn't work
The ideal alternative would be to dynamically switch the ApplicationName, but although it seems to work, ApplicationName is not thread safe, therefore this would not be reliable:
Because a single default membership provider instance is used for all
of the requests served by an HttpApplication object, you can have
multiple requests executing concurrently and attempting to set the
ApplicationName property value. The ApplicationName property is not
thread safe for multiple writes, and changing the ApplicationName
property value can result in unexpected behavior for multiple users of
an application. We recommend that you avoid writing code that allows
users to set the ApplicationName property, unless you must. An example
of an application where setting the ApplicationName property may be
required is an administrative application that manages membership data
for multiple applications. Such an application should be a single-user
application and not a Web application.
Alternative: MembershipReboot
Multi-tenancy is hard in .Net. An open source alternative to using the built in Membership is to use MembershipReboot, written by Brock Allen. It has some excellent features including multi-tenant support out-of-the-box:
single- or multi-tenant account management
flexible account storage design (relational/SQL or object/NoSql), samples using both EF and RavenDB
claims-aware user identities
support for account registration, email verification, password reset, etc.
account lockout for multiple failed login attempts (password guessing)
extensible templating for email notifications
customizable username, password and email validation
notification system for account activity and updates (e.g. for auditing)
account linking with external identity providers (enterprise or social)
supports certificate based authentication
proper password storage (via PBKDF2)
configurable iterations
defaults to OWASP recommendations for iterations (e.g. 64K in year 2012)
two factor authentication support via mobile phone SMS messages or client certificates
The most common use case will be to integrate this into an ASP.NET or
ASP.NET MVC application, though the library can also be used over a
network as a service.
Alternative: ServiceStack REST
Another alternative if you are building modern web applications that heavily use JavaScript MVC frameworks such as AngularJS, EmberJS or BackboneJS is to use ServiceStack REST services. ServiceStack has a long list of Authentication features, and from my experience of SS, I find it has an extremely well thought out API model.
I have an ASP.NET solution that acts as the primary customer portal for my customers. On this website the users can log-in access their important financial information and more. The website uses a custom authentication scheme that checks the user's username (their email) and their password (salt-hashed) against a Users table in a local database.
I am building a new MVC.NET solution that is more of a web-app tool to be used by these same customers for ordering. I want to re-use the sign-on mechanism of the ASP.NET portal to authenticate users. The goal is to save the user from remembering two log-ins or even having to supply the same log-in twice.
What are my options for allowing users who sign on to the ASP.NET solution to then be auto authenticated to the MVC.NET solution? I've listed some ideas below but are these "bad" or is there a more elegant solution? I'd love your input.
Common Cookie I could create a common cookie that the ASP.NET site creates and the MVC.NET site looks for. But is that secure enough?
Token in Query String I could create a token id on the ASP.NET site that is stored in the local database and is then passed in the query string of the link to the MVC.NET site which takes the token id and validates it against the same database.
Hybrid A bit of both?
Other? Got a better idea?
I've recently done something quite similar (the major difference being that it was internal to the company rather than for external customers) using OpenId.
The implementation of OpenId for .NET is called DotNetOpenAuth which should be suitable for your purposes.
It did take me a while to implement; but it works very well, is very flexible, and extremely secure.
More information about openid (from Wikipedia):
OpenID is an open standard that allows users to be authenticated by certain co-operating sites (known as Relying Parties or RP) using a third party service, eliminating the need for webmasters to provide their own ad hoc systems and allowing users to consolidate their digital identities.
Users may create accounts with their preferred OpenID identity providers, and then use those accounts as the basis for signing on to any website which accepts OpenID authentication. The OpenID standard provides a framework for the communication that must take place between the identity provider and the OpenID acceptor (the "relying party").2 An extension to the standard (the OpenID Attribute Exchange) facilitates the transfer of user attributes, such as name and gender, from the OpenID identity provider to the relying party (each relying party may request a different set of attributes, depending on its requirements).
The OpenID protocol does not rely on a central authority to authenticate a user's identity. Moreover, neither services nor the OpenID standard may mandate a specific means by which to authenticate users, allowing for approaches ranging from the common (such as passwords) to the novel (such as smart cards or biometrics).
Oh, and if you'd like further encouragement, Stack Exchange uses it!
#Jmrnet: in response to your last comment:
Perhaps I was unclear. OpenId in and of itself is simply for validating credentials from one location to another (more or less). It's entirely possible to implement as an SSO model where users do nothing different whatsoever - they don't have to choose a provider, or register, or anything like that. For example, in my setup, the user enters a username and password in a web portal, and then clicks a button to launch another site being automatically logged in by OpenId. Nothing different for the user at all! OpenId can be used with any initial authentication model you can think of (note the bolded section in the snippet from wikipedia).
Take a look at SAML:
http://en.wikipedia.org/wiki/Security_Assertion_Markup_Language
It works using XML and supports encryption.
I am currently implementing two SSO solutions for the same project.
In one, we are interfacing with an external partner and are using SAML.
In the other, we are allowing logged in users access to our Sharepoint and using the "Token in Query String" approach, since we trust Sharepoint to access our membership tables. This approach is much easier than dealing with SAML tokens.
There are many methods you can use, Mansfied described OpenID and RandomUs1r described SAML. Also, you can store relevant information in localStorage or in the session. I believe you should store relevant information with session.
It is not safe to put this in the query string, because if I register and log in, I will see something like UserID=1234 in the URL. If I change that to UserID=1235 and the ID is existent, then I can do some things in the name of the other user. This is called identity theft, which should be prevented by any means possible. So you should never have this kind of info in your URLs. Also, if you store the id of the user, you should obfuscate it somehow. For instance if you store the value in local storage and instead of 1234 you store encrypt(1234, salt), then the consistency of user action will be maintained.
I have a very basic question and want to know how other experts do this
I have an application with some 100s of users. I have been using SQL LOGINS to authenticate these users. These users have password policy enforced. and I face difficulty when any user's password is expired i.e. i have to reset it from SSMS myself. It sometimes becomes a difficult job along with other tasks that i do.
I was told by some experts that it is a good practice to create my own user table and have all the user details in that table. I have created a user table with following columns.
User Id
User Name
Password
PasswordCreationDate
PasswordExpiryDate
PasswordActive
One simple question. How do my users connect to the database . Offcourse i would need a connection string from the application. That connection string would require a user name and a password isn't it? and I can not get the information from the user table until and unless i am connected to the database.
Another problem, how do i keep track of last 5 password. The policy says that the user can not use any of the last 5 already used passwords.
All this can be avoid if I can get a solution of notifying my users that their Password is due to expire in 'n' days and they must change it before it expires.
What do the other developers do when authenticating their users. Please Guide Me
If you keep your user's login credentials in the database, then for access to sql server itself you may only need one login for the entire app. This login would have full access to your database, because it would be up to your application to enforce access rights.
If you go this route, you need to be aware of two things:
There is still a security concern for larger applications that need to give ad hoc reporting capabilities to users through tools such as Reporting Services, Crystal Reports, Infomaker, etc. In this case, users can use these reporting tools to gain read access to areas of the database they should not be able to see.
If you store your own credential information for your users, you need to make sure you do it properly. That means no plain text passwords. You need a cryptographically secure password hash (not md5!) and a per-user salt. If that's greek to you, best to leave this alone.
Another option open to you is to use Active Directory/Windows Authentication for your database. The trick here is that you still have to set up access rights for all your users. However, you can use Active Directory groups for this to reduce the number of logins you need to create, and it will at least prevent you from needing to reset Sql Server logins by hand, because users will log in with their Active Directory account.
A pretty common scenario amongst web applications is to use one username/password (so only one sql login, typically some kind of dedicated login with minimal rights for the application). This way, connection pooling can be used. This is of course a backend account, configured in the web.config and not visible to the end-users.
The users are maintained as a type of data within the application. Asp.net comes with a solution that is called Membership. User authentication is done against the Membership provider and several classes give you programmataic support for authentication, roles, etc. You can use AD as a provider for example, or forms authentication. Or you can write your own.
Since you are now using a dedicated sql login for each user, you need to be aware that this approach moves data access security to the application level. So this might not always suit your needs.
Ideally you'd use existing Active Directory infrastructure to handle your authentication/authorisation of individual users, and you could then have end-users' credentials passed via the web server to your SQL server (You'd probably need to look into handling the Kerberos "double-hop issue" to effect this).
But failing this, it's easy to set up so that the application it self has a SQL login to access the database in order to retrieve user level authentication information. One-way hashes on user passwords would ensure that even if the app's password is read from connection string, user passwords can't be obtained.
Or somewhere in between those two solutions, where the application has a service account within AD, which has access to the SQL database, in order to retrieve the user account info from within the DB.
Either way, if AD is available you can secure further with Kerberos Service Point Names to ensure database access from only your expected end-point (ie the ASP.NET server).
As we knew in Web got a lot of tutorial for Azure ACS, but most of it stop at inset simple ACS into website or application. Now, i wondering is that possible to identify and link up all the famous user oauth provider, and add them a new user in database then assign role to them ? After the process, they just simply click any provider then will bring them back to the same account ? Do you having such tutorial can share? Here is the process flow i want to make:
Window live + google + Yahoo + Facebook, one person may having all four account, but then i need their info also, then i create my cuatom data entering page and the problem is how can i link up ? How can withdraw the unique id to identify ? So i can recognize it..and assign role to it..
Question 1: how to link up ?
Question 2: how to identify in system?
Question 3: how to give role ? Not giving from azure admin page but through the code
Thx
There is one thing you should be aware of, when working with ACS (and with Claims in general) - you shall get to know the Claims.
Now, to the ACS specific question. Windows Azure Access Control service is not the magic wand that will do what you desire automatically. ACS is the easiest way to get working with Claims, and to work with only one set of specific claims, and don't bother with all different implementations of different protocols. In fact, what you work with, when creating browser based application, is WS-Federation protocol (and SAML token by default, but you can also use SWT token), and not OAuth protocol. The user uniqueness you get, when someone logs-in with your site, when using ACS is the strict combination of following two factors:
User identity
ACS namespace
The uniqueness you get is NameIdentifier claim (represented by: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier).
The first catch is that, say I am "john.doe#gmail.com" identified to your site through http://yourcompany.accesscontrol.windows.net you will get nameidentifier "X". When, I, the same "john.doe#gmail.com" identify myself to your site, through http://yourcompany-live.accesscontrol.windows.net/, you get nameidentifier "Y"! And this is true for all identity providers, which you link via your Access Control Service.
The second catch is: Live ID identity provider, when configured via ACS, will only give you a NameIdentifier claim. And nothing more.
Now to the questions:
Question 1: how to link up ?
The only feasible way to link up identities, is to built your own linking logic in your application. What I would do, is to stop using all the auto generated code and passive redirection to ACS, but to handle some of the Passive Federation manually. This would mean - I will watch out whether the user is logged-in or no. If not logged in, I will redirect the user to my own custom login page, where I will get from ACS the configured login options. When the user is logged-in, I will create an entry in my own user data base for that user. I will have fields (or linked table) for all possible identity providers that I would like to link up to a single user. Understand, I will store all the NameIdentifiers the user may have. Now, how will I link a user account. There may be different approaches. First, you must indentify the user to allow him/her to link an account. Then create let's say a "linkage ticket" with some unique ID (not GUID, to be easily remembered by the user). Show this ID to the user, and offer him an option to login with another provider (retrieve the list of privers from ACS). When user comes with another provider - show the field when one could enter the ticket. Check the ticket, and if it is valid - link to the existing account.
Question 2: how to identify in system?
As mentioned in answe one - you will need to have your own custom user database, where you will have one account per user, but that account will hold all the NameIdentifier claims, issued by the different authorities. Thus you will be able to uniquely identify the users with linked accoutns.
Question 3: how to give role ? Not giving from azure admin page but
through the code
In your architecture it will be very hard to maintain the roles in the ACS, because of the complexity you enter when requiring to link multiple accounts. I suggest that you keep user-role assignment withing the application database. The part that you have local user accounts, you will assign role(s) to each account.
Note, when I say local user account, I don't mean to support local login credentials, but just user profiles!