Should I use claims to reflect an authorized user with no special roles, and if so, how? - asp.net

I'm currently using ADFS and claims-based identity in ASP.NET web applications to convey informations such as a user's name or identifier.
In addition, inside applications a ClaimsTransformer adds a couple more claims that are relevant to that app. Such claims include applicative roles (Admin, Validator, etc.), whereby the user can't see some pages unless they have the right role.
However, just because you have no role doesn't mean you can't access the application at all. Vanilla users that aren't part of a specific group are sometimes also able to see some pages. Besides, we have a few web applications where roles aren't used -- it's just a matter of whether you can get in or not. We call this "access", which is different from "role" or "permission".
Access rights to applications are stored in a separate database. You can have access to an application if an admin manually granted it to you or if you satisfy a set of rules calculated by another system.
How would you materialize access in terms of claims? A claim type like HasAccess with a true/false value sounds weird and vague.
Is claims-based identity the right place to look at? The idea is to insert that information precisely enough in the authorization chain that every auth cookie doesn't have to carry a list of all accessible applications for the user, but early enough in the process that an accessibility check doesn't have to be done at each http request.

Related

Identify User with OpenID Connect with multiple Providers

I'm writing a web application with spring boot and want that the user is able to tell me what his identity provider is. In a same way as I can do it on Stackoverflow.
How can I identify a user in a unique way? I already read that I should use the sub/Subject for distinguishing users. Is this unique when using multiple providers?
My fear is that a user provides a malicious identity provider which then tells my app he is a different user.
How can I identify a user in a unique way? I already read that I should use the sub/Subject for distinguishing users. Is this unique when using multiple providers?
You'd store the combination of (iss, sub) as an identifier that is globally unique. As Kavindu mentioned already, the sub claim by itself is only locally unique.
My fear is that a user provides a malicious identity provider which then tells my app he is a different user.
There are two ways of using "multiple providers" with your app, via:
a set of trusted IdP's
any IdP
If someone's real identity is important to you, then you can choose the providers you trust to provide someone's identity details. People then can only sign in via one of the providers in your list.
But if it doesn't matter that much (normal username/password registrations also don't provide any guarantees), then you could also choose to let people login with a provider of their choosing. The correct provider may then be discovered from the user's "handle" via OIDC Discovery.
Q : How can I identify a user in a unique way? Is this unique when using multiple providers?
According to OpenID Conenct specification, "sub" claim is locally unique. Following is the extraction from specification which highlight this (reference),
Subject Identifier. A locally unique and never reassigned identifier within the Issuer for the End-User
So when you are dealing with a single identity provider, "sub" claim is unique. But that does not hold for multiple providers.
Q : My fear is that a user provides a malicious identity provider which then tells my app he is a different user.
I doubt about this scenario. Does your application allow end users to register different identity providers as they want ?
In OpenID Connect, there's a application registration step. Your application need a client identifier. Also registration process involve redirect URL registration. All these are done in registration step. Without these, OpenID Connect will not function.
Adding to that, different providers behave differently. For example, though "sub" is the standard claim to communicate end user identity, a provider may use a custom claim to define a specific user identity. This is allowed by OpenID Connect specification. So your application must only support known, well established identity providers which you know at the application design time.

Are ASP.Net Identity Claims useful when NOT using OAuth/external authentication providers?

Everything I've read about claims-based authentication is essentially about "outsourcing" your authentication process to a trusted 3rd party.
See:
Explain "claims-based authentication" to a 5-year-old
Why Claim based authentication instead of role based authentication
Obviously this lends itself well to using something like Facebook or Google to authenticate. But what if there is no 3rd party? What if you just need users to authenticate against an internal database? For example, in a corporate setting. Is there any reason to use claims over plain old roles? If so, some concrete examples would be helpful.
What I know about claims so far:
I understand that claims are key/value pairs rather than booleans like roles.
I understand that claims can store roles.
And if I understand correctly, claims get stored in an authentication cookie (maybe this is key - fewer database calls vs. roles?).
There are numerous reasons, including these you mentioned.
Another reason is that forms authentication module is incapable of handling too large cookies. Just add few hundred roles and exceed the maximum allowed cookie size (4kb) and you are out of luck. The session authentication module that handles claim cookies automatically splits too large tokens into multiple cookies. And if you don't want to have multiple cookies, just a simple switch to "session mode" automatically stores the large token in the session container and the cookie only contains a small bit of information to reflect that.
Yet another argument for the claim-driven cookie is that you can handle any custom data, including tenant name (in a multitenant application), name of home organisation, age, whatever you can need somewhere later. Forms cookie has the custom data section but it is just a string so that you need a custom serializer to have structured data here.
All this is done by the session authentication module and, frankly, it outperforms the forms module easily then. Switching your forms authentication to the new module is also easy, I've blogged on that some time ago (other people blog about it also):
http://www.wiktorzychla.com/2012/09/forms-authentication-revisited.html

Multiple site domains and virtual directory single login

I am creating a project which has a login portal with multiple applications and websites. I want to allow the user to login and then click any application and have access to it. Some considerations are: each application is defined in a user profile, ie which users can see what. also each application privileges are different for each user. so user a may be an administrator of application a but just a normal users in application b.
What i know.
I can have one auth cookie created in the main portal which with setting the machine key and same authcookie name, each application can use it. I have done a test with this and it seems to work.
My problem
As each site/ virtual directory has different privileges per user and per application when the user access a site i need to get his privileges from the databases but I cant then overwrite the auth cookie userdata with the new details because he may have multiple tabs etc open at a time on different sites. So how can i have an extra cookie store per user and per application for holding application specific details. I know I could go to the database each time but that's allot of overhead for each post back.
Maybe another option is to use the main authcooke for checking the user is logged in then have a new auth cookie per aplication and user, but how can i have 2 authcookies, that may get confusing and the second needs to timeout when the main one does et c i think
Any help suggestions would be gratefully appreciated
THanks
------------------- EDIT -----------------------------
we have one user table for all all sites not 1 per each site. then we map the user to an application and then the user application and role. so when you get to an application it has to check if the user has access and what there role is. all other user details are already in the auth cookie when loggedinto the main site. We do it this way because we have to manage users in one application not each application. Hope this helps understand my requirements.
What you are describing is a 'classic' SSO (single sign-on) example. There are lots of ways people have tried this and they are well documented on Google.
One way to do this is to have your SSO server (e.g. the first place you land and log in) to issue a security 'token' (e.g. a Guid) and then either store this in a cookie or append to URLs. Each subsequent call to an application can look-up the token in a database, verify it's validity and carry on (or boot the user out if invalid).
Using a database also allows you to set a timeout for all applications for which the token is valid.
This can then be extended to allow the database to store which apps each user can access etc. I've described this in very broad terms but it may be a good starting point.
Hope this helps
BTW: querying the database on each request isn't too much of an overhead. I have applications that do just that and are still performant when loaded with 300+ users.

Creating a Forms Authentication cookie for a search engine crawler

Big picture: I have been asked to create a search engine for our company's intranet. Such a search engine will crawl pages supplied to it by XML files for each independent application on the intranet. Problem is, the entire intranet is using Forms Authentication, and so the crawler will have to have access to each application without actually having user credentials (e.g. username and password).
Each application within the intranet has its access controlled by a permission manager, which is essentially a wrapper on the default Role Manager ASP.NET comes with. Each application can define its own roles and assign people who have those roles.
Please note that there are potentially hundreds of applications.
The crawler has access to the permission manager's database, so it knows what all the roles are. Therefore my idea was to have the crawler create a cookie that identifies it as having all roles for each application.
The problem I'm running into is this: how do I create a forms authentication cookie which already has the roles assigned in it without creating a corresponding user (IPrincipal).
It is entirely possible that I've failed to completely understand how Forms Authentication works, and if so, please tell me what I can do differently.
This is probably not what you want to hear, but...
I would just have the crawler authenticate like anyone else.
Given that this is a crawler you control, why fight Forms Authentication? Seems logical to create a user with all required roles in each application (hopefully you have a central administration point for the hundreds of apps, else I would not want to be an administrator there ;-)
If you do anything that allows "just the crawler" special access (bypass user-based authentication based on... what? The crawler's user agent? A specific origin IP?), you create a security hole that a hacker can leverage to gain access to all of the intranet applications that have otherwise been diligently secured with user IDs, passwords and roles (in fact, the security hole is particularly wide because you propose granting access to EVERY role in the system).
It sounds like what you want is an appropriately encrypted System.Web.Security.FormsAuthenticationTicket (which then gets attached to HTTP requests as a cookie).
The encryption logic is located in System.Web.Security.FormsAuthentication.Encrypt(), which I think uses the MachineKey as the encryption key. Also have a look at the GetAuthCookie() logic (using Reflector).
You might have to write your own version of the encryption method, but what you want to do should be possible, provided you have a copy of the remote site's encryption keys. You don't need the user's passwords -- only the user name is encoded into the Ticket.
It seems to me that the problem is not yet well defined, (at least to me!).
Why do you need to crawl the pages and index them if there are fine grained permissions on them?! How do you show search results without violating the permissions? Why not index the back end by passing the pages altogether (I mean index the database records not the pages)....

Approve multiple applications with single sql membership provider

I have an asp.net application that uses the SQL membership provider. I know how to get multiple applications using the same membership provider so a user can go to multiple sites and login using the same credentials. However the requirement on my current project is that each user is given access only to certain applications. For example, the user is given credentials to access Site 1, then at some point in the future, the user needs access to Site 2 and a manager/admin has to allow the user to access Site 2. Or when the manager creates the user's account initially, he/she approves access to the 3 sites (or whatever) the user needs to access.
So my question is what is the best way to use 1 membership provider for many applications, but only allows users to access applications they're approved for (so a manager can manage access to applications, but give users 1 username and password)? I've thought about using roles, but I already use roles in the application for allowing access to certain features in the application. It seems like that would get messy.
I've read about 50 similar questions on SO but none of them addressed the application approval requirement. Thanks in advance.
The easiest straight forward method here is to use roles.
If you add more roles (one for each app) for this purpose it is no big deal. You have a basic role for each app that must be available and check this on Application_AuthenticateRequest or Application_AuthorizeRequest . There are other ways to do it, but this is the least impact, easiest to code (nothing required but a role check), and easy to follow.

Resources