I'm about to start working on an ASP.NET (C#) website project which requires users to authenticate and I've run into a bit of a design issue. I am required to use a SQL Server database to store the web app's data (to include user's login data), but all of the information I've found regarding ASP.NET and authentication uses Windows Authentication.
Now of course I could just write the code to query the database and check the users input against the database to see if the username/password exists (the current plan), but then how do I set the state of the session to authenticated along with other data (such as a user ID) so that the site can give the user only their data?
First, read more on Forms Authentication. You couldn't have really missed that (could you?) but it's the other major authentication mechanism that doesn't involve Windows accounts, instead the session is maintained with the help of a cookie that stores the user name together with any other so called user data (could be user ID or whatever else).
Second, the Membership/Role Provider mechanism is available for like 10 years - and it gives you an abstraction you implement on your own. The abstraction is about storing users/passwords/roles. The Membership/Role Provider is nowadays slowly replaced with the Identity 2.0 framework and you are free to choose the olderone or try the newer.
These two together, Forms Authentication and Membership/Role Provider, make a foundation of what you need.
The basic flow is as follows:
users request various resources ("pages")
some resources are guarded from anonymous access and require authentication/authorization
the Forms Authentication module redirects requests to such resources to a login page (login view)
in the login page you use the Membership/Role Provider to verify user and issue a Forms cookie
you redirect back
The Forms authentication module now picks the cookie upon every request and recreates the identity so that the user is authenticated when your server code is about to run.
Related
I am trying to build a web project that will include user sign in. It will have an asp.net front-end, and an asp.net back-end. I am trying to figure out how this should work with user context and where user sign-in should happen. I believe controlling user sign in is a back-end responsibility, but it seems that many 3rd party validation methods would prefer it to be front-end. As I understand it seems that if I was using something like google or Microsoft validation. It would try to bring up a window, but that window wouldn't be seen by my user, because it was coming from the back-end that is not serving them, and is instead serving the front-end server.
Based on your comments I'll try to summarize a bit here. Do note, that this is not a coding question and should really have been asked on https://security.stackexchange.com/, but I'll give it a go.
A few keywords you should read up on:
Authentication: This is the process of verifying the identity of an entity (a person, device etc.)
Authorization: This is the process of granting access to a given resource based on some parameters - usually based on a verified identity
Identity provider: A system that manages and can verify the identity of an entity (in your example that would be Google or Microsoft)
Service provider: A system providing a service to authenticated entities (in this case your server application)
OAuth, which you use as an example, is not an authentication protocol but an authorization protocol, which makes it important for you to understand the difference. However, OpenID Connect is a protocol/layer built on top of OAuth 2.0 and...
It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server [read: "Identity provider" under the hood]. [source]
Copied from Wikipedia (point 8 removed to avoid confusion):
The communication flow in both processes is similar:
(Not pictured) The user requests a resource or site login from the application.
The site sees that the user is not authenticated. It formulates a request for the identity provider, encodes it, and sends it to the user as part of a redirect URL.
The user's browser requests the redirect URL for the identity provider, including the application's request
If necessary, the identity provider authenticates the user (perhaps by asking them for their username and password)
Once the identity provider is satisfied that the user is sufficiently authenticated, it processes the application's request, formulates a response, and sends that back to the user along with a redirect URL back to the application.
The user's browser requests the redirect URL that goes back to the application, including the identity provider's response
The application decodes the identity provider's response, and carries on accordingly.
This is the flow you're asking about. The only thing the client (front end) does is follow the URLs it's provided from your application in order to visit an authentication server. This server then provides the proven identity that your client then passes on to your server again.
So bottom line is, the client/front end does not perform the authentication, that's handled by the identity provider (a 3rd party backend).
We are currently starting to use MVC and are now looking at authentication. .net Authentication isn't necessarily our strongest point, so looking for some advise or pointers.
Our current set up:-
Basic Windows authentication
system uses the authenticated user to query a 3rd party system to get their current roles
these roles are then stored in session variables and used when ever authorisation is required
Any additional user details are called upon as and when needed from various tables
What we'd like to achieve :-
Basic Windows authentication (perhaps create a forms authentication cookie on the back of it)
System users the authenticated user to query 3rd party system to get their current role/s,
These roles are stored within the cookie, and can be accessed via User.Roles etc
Any additional user details (i.e. user favourite colour) will be called on authentication and store against the user profile. The additional user details will be stored in a single table as key value pairs.
Is this the correct way to go about this? we're struggling to find any samples etc to match the scenario we are after.
unfortunately, we need to use this 3rd party system to access the roles, this is achieved via a web service call.
Are there any new advances with MVC 4 which could greater handle authentication with additional user details?
any help, or advise would be greatly appreciated. :)
Sounds like a perfect candidate for federated authentication. You could even use WIF (Windows Identity Foundation) which is now part of the Base Class Library.
In general, federated authentication consist of following parts: delegating the authentication to an external identity provider, consuming identity provider's response, persisting the identity locally (in a cookie perhaps).
WIF has solutions for all these concerns, it is built around the WS-Federation protocol. The really, really great benefit of this is that you can switch between different identity providers easily. This is something that you could consider useless, until you see it in action and immediately you start to create complicated business scenarios in your head.
Using WIF requires some knowledge and specific questions can be answered easily. However, until you get at least some basic knowledge, this sounds like a mumbo-jumbo. You should definitely start by reading a free ebook, Claims-Based Identity and Access Control from here
http://msdn.microsoft.com/en-us/library/ff423674.aspx
Just download it and start reading. I promise you'll immediately find answers to many of your questions and page by page you'll feel this constant "wow, so that's how it should be done!".
Just to provide a specific answer to one of your questions: user data can be persisted in the authentication cookie. If you stick with WIF's model of Claims, expressing arbitrary data is natural: a claim is a pair (claim type, claim value). This requires however to switch to SessionAuthenticationModule as forms authentication module could possibly produce cookies that are too large:
http://www.wiktorzychla.com/2012/09/forms-authentication-revisited.html
(the session authentication module has a special "session" mode where the large part of the identity is stored locally at the server in the session container so that the cookie is really small)
And yes, the federated identity model works with MVC authorization tags. Claims of type role are interpreted as user roles. The remote identity provider can then even set user roles and you can guard your MVC controllers in the usual way.
If you are lucky your 3rd party component might bring a Claims provider with it so you could use Claims based authentication and let the Claims provider supply the additional user data in form of Claims that you can use in your application. For a tutorial see this link. If you cannot access a Claims provider, the known security building blocks still work for MVC. So for your additional roles, you could create a RoleProvider that requests the roles and configure it in your application. You can then secure your controllers or actions with the Authorize-attribute.
In order to optimize the request for roles so that you do not have to request it from the 3rd party system over and over again, there are some alternatives:
As you propose in your question, you can store them in the cookie. But be aware that cookies are stored on the client computer and could be tampered with. So if you have a Forms authentication cookie that you can use, you could store it in the UserData of this cookie. This cookie is already encrypted so that users cannot change it easily. As you want to use Windows authentication at least in the first step, you do not have a Forms authentication cookie that you could use. In the context of security, it is always advisable to set up upon a widely used and well tested framework, so I'd not recommend to create a cookie of your own and store the roles there (though it wouldn't be a too daunting task in this specific case to encrypt/sign the cookie data).
You could also store the roles in a Session variable. Downside is that the session times out after a while and you'd have to be prepared for this case. On the other hand, session memory is located on the server so that it is not that easy for users to tamper with (and if they could, you'd have lots of other problems).
Another component you could use is the Cache on the server; though you'd have to be careful not to mix data for various users as it is shared among users, it is also located on the server and provides a more fine grained control on when the data are invalidated. So you could configure a time frame after that any user would be authorized with a new role set in case it was changed.
Your RoleProvider would need to implement the caching technology (Cookie, Session or Cache).
As for your last point regarding the user profiles, I can imagine that the User Profiles of ASP.NET 2.0 still work. I don't have any experience with it, so I can't give you a recommendation on whether to use it or not. On the other hand, these data don't seem to be too security critical so you can also store them in a cookie or session memory once the user has been authenticated.
I am currently working on a project that has a requirement that is causing me some issues and I want to know the best way of handling it.
Essentially we would like internal users to be able to access the MVC application and be authenticated through AD, this we want to be pretty much like SSO, they sign on to their computer navigate to the site and they are in.
The second type of users are outside partners that do not exist in our AD and we want to manage through our SQL Server. For these users we want to display a login page and do forms authentication.
My thoughts at first were simple, let IIS try and authenticate with windows authentication and if it fails (401) redirect to a login page. I don't currently have an environment to test this in but from my understanding in IIS7 it is not that simple and requires a little bit of a "hack" to accomplish. I need to avoid anything like that I need a solution that works as the system was designed to work and not by tricking it.
I have looked into ADFS and WIF but ADFS only supports AD not SQL and from what I've seen there is no STS that supports SQL Server. I have contemplated hosting both an internal application that used windows authentication and external application that used forms authentication but I want to avoid this if possible.
Ideally the flow that we want is user navigates to the MVC application IIS tries to do windows authentication, if it fails (401) redirect them to the login page. From there the login page will authenticate the user credentials against the SQL Database. What is the best way of accomplishing this all within 1 MVC application?
Thank you!
I would just implement my own authentication on top of FormsAuthentication or OWIN if you are using ASP.NET MVC 5. It is really simple and you will have full control over where you go to authenticate users. Trust me it isn't as scary as it sounds. I've written a few posts about it that you might find interesting.
MVC 5
http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown-part-deux
MVC 4
http://tech.pro/tutorial/1216/implementing-custom-authentication-for-aspnet
I currently use the MVC 4 method to authenticate against an Active Directory domain with great success. The only thing I would recommend is you Cache your calls to Active Directory as it can be unreliable at times.
There is the STS that supports sql server, it is the IdentityServer.
https://github.com/thinktecture/Thinktecture.IdentityServer.v2
It even supports custom membership providers which give you quite a lot of different possibilities. I am not sure however if it supports automatic fallback to forms when integrated authentication fails. If not, there are two options: a custom sts or two explicit stses and an explicit choice for users. We have implemented the latter scenario once with ADFS - there were two adfses, one with Forms, the other one with integrated auth, first one federated with the other. This gives an explicit choice on the home realm discovery page - ".would you like to log in with username/password or try the integrated authentication"
You could create a project that uses "On-Premises Authentication" which uses ADFS to authenticate users. The on-premises authority URI will be:
https://yourADFSservername/federationmetadata/2007-06/federationmetadata.xml
After your project is loaded, you can to goto your ADFS settings and create a new "Relying Party Trust" and pass on HTTPS URL that your MVC app will be using. Setup to used LDAP attributes as claims and that will sort out AD authentication easily as it will navigate users to organisational sign-in page just like Office 365. Then if authentication fails for certain users, take the user to send the user to normal sign-in/signup page that exists independently of AD and connected to SQL server. You could skip windows authentication altogether by using on-premises authentication.
I'm developing a WCF service that will host business logic of the application. The application is mostly for intranet, but can be accessed from internet. We have an active directory domain up and running, so I plan to authenticate and authorize users according to their username and groups they are in. This service will be used mostly be an ASP.NET MVC site
So, first question is how to authenticate and authorize users based on their AD profile?
Secondly, I need to store additional info about each user. The problem is that I can't modify AD scheme. The number of added fields is about 10 or so.
Can I somehow use SQL server for profile storage? Of course I can, but how to tie this with AD auth?
You can use WIF for this.
You would configure your WCF service for WIF in the normal way and then use a custom ClaimsAuthenticationManager class deriving from the base ClaimsAuthenticationManager and overriding its Authenticate method. This is a normal extensibility point of WIF. WIF will
get hold of the security token from the incoming request and add claims for each of the relevant AD properties. In your override of the Authenticate method, you will add new claims to represent your extra properties.
The basic use of WIF for WCF services is described here:
http://msdn.microsoft.com/en-us/library/ee748476.aspx
To see how to use ClaimsAuthenticationManager, start here:
http://msdn.microsoft.com/en-us/library/ee748211.aspx
Well, I think you have a couple of choices here, but you will have to carefully consider the implementation.
The primary issue with using active directory authentication is that by default a user's credentials can only be passed successfully between two machines. In the case of a web application, this means that the user's credentials can travel between the end user's machine and the web server, but no further.
However, this behavior can be changed through the use of Kerberos authentication, which essentially allows an authentication ticket to be passed among all of the trusted machines in the chain (i.e. from the web server to the application server to the database, for example). Successfully configuring Kerberos can be extremely challenging, especially if you have had no prior experience with it.
I think your best bet is to configure your web site to accept only Windows Authentication. This means that IIS will perform the validation of the user against active directory. In your ASP.Net application you can pickup the domain name of the authorized user from Request.ServerVariables("logon_user").
At this point, you can log the user on with FormsAuthentication, for example, without requiring them to login again.
You could then either implement the SQL Server Membership Provider or create your own interface to your database for further user validation and extra information storage. We have used both mechanisms, but I prefer the self-built one due to the additional control it provides and, in this case, you won't need a lot of the functionality (password reset, recovery, etc) that the membership provider offers.
We're currently migrating a portion of intranet apps to MojoPortal(an open source cms app). MP uses FormsAuth by default and we've set it to authenticate against our current Active Directory store.
All that being said, we are looking to automatically log in users from the current system to the new system to create a seamless experience. New system(mojo) residing on a different server than the current system. Both live under the same "company.com" domain, with different subdomains.
Mojo, checks authentication via a FormsAuthentication cookie that is created when a user logs in through the mojo interface. We're looking to recreate this functionality remotely. I realize FormsAuth is based on MachineKey and lives inside a single IIS Web Instance, but am curious for any ideas the community may have.
The current "best" guesses we've come up with here are:
Create a WCF web service that lives in a virtual directory under the mojo site, accepts a username/password and creates the cookie. This is untested as we are unsure if this will actually affect the client.
Redirect the user to an intermediate page under mojo which accepts a username/password and creates the cookie, after which redirects the user again to the desired mojo page.
This does use MojoPortal as a provider, but the real issue is how to create a FormsAuthentication cookie remotely.
Additional background info:
Current system already authenticates against the same AD store, so there is no concern over creating cookies for users that are non-existent. Both servers lie in the same AD domain(they're physically next to each other). The current system's source code is available to us and able to be modified as well.
If I understand correctly you are trying to have a single sign-on between your legacy system and mojo? I've done something similar in the past. Our legacy system creates an authentication token and passes it to the second system. A web service call is then made back to the legacy system to validate the token (you'll want to add some rules around what makes a token authentic. For example: one time use, time outs, etc..). If the legacy system validates the token then the cookie is set.
FormsAuthentication.SetAuthCookie(, true)
from there redirect back to your mojo main page.