What is generally accepted as the best practice for an ASP.NET site to implement security authentication and authorization that is not based on Windows AD and stores account information in a database? Is it to use the built in Forms Authentication, a stock or custom rolled MembershipProvider, the Enterprise Library Security Block?
Are there any pros and cons between them, such as replacing Forms Authentication makes it harder or not possible to protect directories with files that need restricted that aren't ASP.NET files?
Ouch that's a huge topic, so instead I'll list some general points.
Forms authentication gives you an authentication cookie separate from a session cookie, which is protected against tampering and can be encrypted. Its provider model means this protection still exists even if you roll your own membership provider and these providers can be used to protect WCF web services, and to allow authentication and authorization with silverlight
Forms auth also creates an IIdentity/IPrincipal object on the executing thread which means you can use CAS PrincipalPermission demands to protect methods, classes and even assemblies which can be separated from your ASP.NET application, making authorization the cross cutting concern it should be.
Forms auth is also used by IIS7's file protection mechanisms, and so can be used with IIS7 to protect any type of file, not just those which are associated with the ASP.NET ISAPI DLL (you can, in IIS6 do a wild card mapping and put everything through the ASP.NET pipeline, but that has an impact on scalability)
Forms auth does not allow impersonation.
Rolling your own removes all of this. You can start to build it back in using HTTP Modules which would do your own cookie loading and validation, creating the principal on the thread and checking access to resources. You'd still need to write the database bits, controls if you need them, your own classes and plumb them in.
And you'd need to get it right.
There are a lot of pros for the standard way to do it, and it's been hammered and tested and used and abused by a lot of people, the biggest con for rolling your own is you're probably not as clever as you think you are - I know I wouldn't do it.
Using Forms Authentication (with either the stock MembershipProvider or a custom MembershipProvider) is typically considered the standard.
Related
https://identityserver4.readthedocs.io/en/release/intro/support.html
I currently issue tokens myself in my web api with JwtSecurityToken and I use standard ASP.NET Core middleware calling AddJwtBearer to verify the tokens. It works fine.
What advantage will give me using OpenID Connect (through IdentityServer4) over the approach described above? How to answer myself question "Do I need OpenID Connect?"
From my basic understanding about OpenID Connect, it is used to allow third parties to access your API. But I make API for myself and not for third parties and I don't know why should I favor IdentityServer/OpenIddict over my simple approach.
I read that if I want Single sign-on I should use this, but JWTs itself aren't bound to any specific domain and I can use single sign-on with just pure JWTs(they're self-contained)
I understand it implements some kind of standard for issuing tokens. (protocol). It might be good if I ever wish to expose some API to third parties. But for internal APIs? Is it worth using it?
This is my current auth flow (from https://jonhilton.net/2017/10/11/secure-your-asp.net-core-2.0-api-part-1---issuing-a-jwt/)
What I really want to implement to secure my Web API:
Login
Logout (invalidate token?)
No consent screen (want to have API only for myself), auth happens in the background in my native desktop, mobile, web app (no redirection)
Remember me feature (refresh tokens?)
Could someone clear out the fuzzy picture of OIDC/OAuth2 for me? i.e. give me some disadvantages going my own way (implementing my own flow) and advantages of using OIDC in place of my own flow.
What will it save me from doing later on (on the client-side for example), and what will not. And most particularly, is it good to start every project using standard flows like OIDC? Will it somehow benefit me in the future?
In any case you will implement OAuth2. Think of Oidc as an extension of OAuth2. The most important thing to keep in mind is seperation of concerns.
Forget Oidc, Identity Server 4 is all about authentication: "who is the user"? Consider Google login. When a user logs in for the first time, the application doesn't know the user, it only knows that Google does.
Authorization takes place on a different level and isn't really a concern of IdentityServer. For that you could take a look at PolicyServer.
So you'll need to keep the user database seperated from the application database. This doesn't mean you need another database, just don't mix contexts. If you have a relation from the "business context" to e.g. the user table in the "Identity context" then you are going to have a problem eventually.
In your setup your web api is both the resource and the identity provider. This means that every new web api you create has to be implemented as both resource and identity provider. For maintainability you could create a seperate web api that acts as an identity provider, while the web api is a resource only. You can implement something like that as long as all apps can read the token.
The same counts for the front. Why should the front have anything to do with the user? All it needs to do is pass the token in order to get the user authorized. In case of IdentityServer, the app contacts it to verify the user and receives a token. It knows nothing about credentials. This is more secure. The client app can be compromised. The credentials can be intercepted.
Having single apps with a specific concern makes things more maintainable. And it is quite easy to add a new resource without having to code when you use IdentityServer. Just add the configuration. It also allows you to add other flows in the future that are not needed at this time. And as a side note, the consent screen is optional.
The bonus is that you can implement SSO, where in your setup that could be harder, if not impossible.
So you don't have to use IdentityServer, nor Oidc. Your setup may be just fine. But if you build something, keep seperation of concerns in mind.
I'm working on a solution with others where we have built on a Visual Studio Web Project using MVC (5 I think) and WebApi2.0.
The nature of the solution is that it has 2 DALs, one of the DALs uses SQL to access another applications database, the other DAL uses entityframework codefirst to manage our applications database. There is also a service that is associated with the project so we have done our best to adapt the entire solution into a 3 tier pattern. This means there is a project that contains our BusinessLogic and both our service and our Controllers use it to access the DAL.
So all that out of the way...We are now adding in authentication on the web side. We were stuck for days until we really just embraced Microsoft's default project structure with the OWIN authentication. The downside is that we now have a separate User database that is essentially coupled with the Presentation/Web layer of the solution.
Is there any way to keep all the convenience of the default OWIN authentication in the MVC project AND abstract it out into the LogicLayer? I can't post what we've worked on, but needless to say it's failed every time because we are really struggling to identify what is being done for us behind the scenes (one example is the [assembly: OwinStartupAttribute(typeof(AlarmAggregator.Startup))] annotation). This annotation alone makes me think we will NOT be able to abstract it out.
I know I'm asking to have my cake and eat it too, but I was hoping someone had some insight if it was possible.
At the very least we were hoping there was a way that we could combine our internal database and our user database? I think this would have to happen at the context level? Would it be as simple as pointing our web.config at our internal context?
Since you have not mentioned what those 2 databases are, I assume they are not user databases and out of context. Focusing on the user identity storage, yes its going to be a separate entity unless you are using ADFS, LDAP or something. I would discourage you from building your own identity solution, rather look out for something more widely used and accepted because its a security topic.
Take a look at Thinktecture Identity Server. Its an OpenId Connect based open source solution built in .NET. It comes with its own database, supports same domain SSO, cookie based authentication and supports open id connect. It also supports federated authentication if you want to hookup a ADFS. Its also possible to do social sign in integration with it.
I have integrated .NET, Java and PHP solutions in production to the same instance and everything is fantastic and seamless.
You can host it as a separate service. You can register known clients (your apps and services), their incoming and redirect urls, including post logout Urls, so your application can seamlessly reach out and come back from identity server. The Identity Server comes with all the middleware you would need to protect your APIs and web applications. It also provides REST endpoints for getting and validating access tokens amongst others.
You can also set different scopes to specify the scopes against which a request can be processed.
Much of what I am talking about has directly to do with oAuth 2.0 specs so probably you can read a little about it here if you are not aware of it.
Using a typical oAuth Flow, (e.g implicit flow or authorization code flow), hooking up the right middleware in the Owin pipeline, and decorating your API resources with [Authorize] attribute, your Application will redirect to the identity server page where the user can login. Your APIs(the protected resource) can specify if they are expecting for a specific Scope, when a token is presented and allow to accept/deny your request based on that.
The client registration ensures that only known clients are accepted by identity server(as applications are generally internet facing) and you can either use the MembershipReboot component, also from Thinktecture(also opensource) as your identity store or write your own implementation of a "user service". There are way too many extension points available to play with and you can practically customize everything including the look and feel of the identity server pages to match the UI scheme of your client applications. There is IUserService(to plugin your own user store, ViewLoader to customize UI, CORS policy service to specify allowed origins per client, certificate based TokenSigningService to sign tokens(access/refresh tokens), ScopeStore, ClientStore, TokenHandleStore(to store scopes, client configurations, tokens), ClaimsFilters to filter what claims are included when a token is issued, which is helpful when you use external providers which might return more information that you need to store or provide)
I can go on for ever here but like I said its something available for use and I am using it for multiple applications in production, you can give that a try.
You can have it up and running in 30 mins on your local machine with both Identity Server and MembershipReboot databases setup. The support is very good from the authors and this is a very widely accepted solution for user authentication and authorization.
For example, securing a WebAPI is super simple:
decorate your APIs with [Authorize] and or [ScopeAuthorize] based on your need
This tells the API to go and check if you got something setup for Authorization in the owin pipeline.
In Owin startup just use:
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions()
{
Authority = "http://your-idserver-url"
});
Yes that is all the change you need in your WebAPI. There is a separate way to setup open id configuration for MVC based web applications but that is anyway available in the documentations with sample code.
The documentation is pretty easy to follow and the server is easy to setup. It takes away all the complexity from your App and services so you can focus on what you want your App to do rather than worrying about handling Authentication and Authorization in each of your Apps or services.
I want to authenticate a user using a third-party system when they hit a Controller or ApiController with the [Authorize] attribute, but I really don't want to have to create associated users and logins that OWIN requires in order to create the cookie that keeps the user session authorized, because our third-party system is already tracking that.
Normally, you'd map OWIN logins to external logins, but our system, as-is, is so tightly integrated with this third-party system that there are a bunch of reasons (that I won't go into) that we don't want to do that.
Is there a simple way to use ASP.NET MVC5 out of the box that allows you to authenticate to another system, and then mark the session as Authenticated without having to find/register them in OWIN?
Sorry if this isn't a lot to go on. I've not seen any way to go about this without perhaps implementing our own IAuthenticationManager, but I'm not even sure where I'd start to do that.
Thanks for any help you can offer.
I believe OAuth is the only ASP.NET SSO support you get out of the box. It would help if you elaborate on the nature of the third party authentication system, since you'll need to integrate with it in order to provide the SSO experience.
Here are a couple of blog posts explaining how to create custom OWIN authentication middleware, which seems to be what you'll need to do to set ASP.NET Identity based on some information from an external system (header, cookie, token, etc). I used the second approach to integrate with CA SiteMinder (commercial web authentication product).
Owin Auth 1
Owin Auth 2
I ended up solving this by creating my own implementation of IUserStore and its associated classes that wraps the third-party system.
I've been programming for a long time now, but I'm not the world's most experienced.Net developer. I recently picked up a project that is using Forms authentication for their website. I first looked at forms authentication in .Net 1.1 and at that time it had some limitations that made me decide not to use it as my primary form of authentication.
This project requires that users have roles (which I understand forms authentication supports) and group memberships. For example "User A" is an "Admin" for "Company A". Does forms authentication now support this sort of user structure?
I've also read that forms authentication sends passwords back as plain text. This client does not use SSL. Is this true?
The current code base uses forms authentication, but does not support groups (it does support roles). So, I need to either modify the forms authentication to support the required groups or rip out the forms authentication and use the Authentication framework I normally use. If forms authentication does support groups and is secure enough, then I should stick with that. If forms authentication has security issues or does not support groups then I need to remove that form of authentication.
I've searched the internet for a pros-and-cons sort of article, but no luck. What do you guys think?
To satisfy you requirements you will use Forms Authentication with Membership. If your application is using SQL Server database you can use SQLMembershipProvider as the membership provider to achieve this.
Examining ASP.NET 2.0's Membership, Roles, and Profile can be a good start reference.
About your concern about sending passwords as a plain text when the connection is not secured.
Actually the passwords that are sent are usually hashed (algorithm will depend on the Membership Provider chosen) and that is as there are eventually stored.
Of course if the connection is not secured that hashed password can be retrieved and used to hack the application but at least you eliminate the possibility that the plain user password is stolen and used e.g. to access another service (as you know many people use the same password across multiple services). So to be secure you really need to use https here.
As a note of warning, I am far from being an expert in that field, but quite recently I was faced with a similar problem that you are describing so I though that you may find some of this useful.
Forms authentication doesn't sends passwords back as plain text. As long as you make sure the login/pwd is protected when receiving it (i.e. using https ... ssl) there is no security risk in there.
If you really need to do authorization that way, you can rely on forms authentication for ... authentication, and do authorization with your own mechanism.
Forms Auth is an excellent choice for what you're after. It does support roles but it does not support groups. However, it does have built in support for active directory integration, which you can use to aleviate the group issue, if necessary. Personally, I would stick with what you have and learn more about it. If you want to use Forms mode of Forms Auth rather than AD auth mode, I would consider building on group support using the existing forms auth database.
I highly recommend viewing these videos from Microsoft about forms authentication. You'll find that it's pretty straight forward to use. Granted, it's not something you can throw together as it is a fairly robust and flexible framework. You'll want to read up on it and view these videos. However, when you become familiar with it, you'll find that it's secure, supported and very well accepted by the development community.
Yikes, I just reviewed your question again and you said they don't use SSL. How secure does this site need to be? To me, that would be my first order of business is to move to SSL!
Forms Authentication will not support groups natively. What we do is use it to "authenticate" a user (prove who they are) and then we use our own data stores to "authorize" a user (describe what they can do).
the db doesnt store the plain password text it uses md5 or some other means of hashing... i know that they are matching 2 hashed strings against each other to auth wheter they convert the string client side or server side im not sure..its probably browser... if you are thinking about using ssl i dont think you should be using ASP.net forms auth... its time for you to do your own forms based auth and dive in to some ad mining....
Thanks for all of the input. Although I think I'll continue to use my own authentication library in other projects, I think that the best thing to do for this client is to stick with the forms authentication they already have partially in place.
Although I develop with Visual Studio and the .Net platform, I don't always like to do things the "Microsoft" way. I find that many times the "Microsoft" way introduces a lot of overhead that can be avoided if you know what you're doing.
Thanks again for the input.
Passwords have to be passed clear text over the wire if you are not using SSL. Hence the need for SSL.
.Net Forms Authentication will properly hash and store the password to the db however this won't protect the credentials over the wire. But this holds true for all web frameworks.
As for the group piece of this you'll have to implement this in your app or find some libraries to help you.
I have a web application that once signed in, personalizes almost all pages.
I want to be able to have some very specific pages locked down with SSL that may have sensitive information. From what I have been able to find, once you sign in via an SSL sign in page (area of the web site), the session information which I use to store a lot of personalization and user credentials is not available to the non SSL portion of the web site since they are considered 2 seperate applications.
This MSDN document pretty much says what I am talking about: MSDN Doc
Note: If you use this type of site structure, your application must not rely on the user's identity on the non-SSL pages. In the preceding configuration, no forms authentication ticket is sent for requests for non-SSL pages. As a result, the user is considered anonymous. This has implications for related features, such as personalization, that require the user name.
I am also not using forms authentication. When a user signs in a session object is made storing their credentials including their IP. If this session object exists for a particular user with the same IP then they are considered 'signed in' and the personalization features are enabled.
So my question is, are there any work arounds to this so that say my sign in page and some other page are using SSL, the reset of the site is not, and all pages have access to the same session variables?
If not can anyone suggest any other methods of accomplishing the same type of personalization features?
Since there are no comments, I thought I'd offer an inelegent but practical solution.
Leave the RequireHTTPS off in your forms authentication configuration block.
Next, you create a custom class that implements IHttpModule. This interface has an Init method that takes a HTTPApplication instance as an argument. You can then attach to the "AuthenticateRequest" event on this instance.
From here, you can 302-redirect any requests that come in without SSL when they should do. You'd probably want to drive which pages require SSL from a custom configuration section in your web.config.
To use this class for your requests, you have to add a line to the HttpModules section of the web.config.
For a start, have a look at this code project article: http://www.codeproject.com/KB/web-security/WebPageSecurity_v2.aspx - this will enable you to "step on" and "step off" of https for certain pages.
With regard to your session issues, I think you're a bit stuck. The standard forms authentication mechanism stores a cookie to identify the authenticated session which is available over http or https. My advice would be to switch to using forms authentication, and use the ProviderUserKey guid as the key for accessing your per-session data.
Hope this helps.
We have decided to not go with SSL in those few pages that required them. We looked at other web applications that did similar things and they do not use SSL. We are not really protecting anything that would be all that useful for a malicious user to go through the trouble of stealing anyways.
One option I did consider before the decision was made to remove the SSL was to store a user's session on the application's web service interface. Every page call would access the web service to access the session information. This would be enforced on every page call to ensure the session stayed active. I didn't do too much investigation into using this solution before the SSL decision was made so there could be many draw backs to this solution, especially having to make extra calls to the web service with every server hit.