I am developing a Web API 2.1 service that needs to authenticate the connecting clients (HTML5/JS clients that I will create and control). Unfortunately, the user information (username, password hashes, roles and much, much more info) is stored in an existing (SQL Server) database to which I only have read access. The Users database table was created 5-6 years ago without any reference to security frameworks, so it's a completely custom format. I'm not allowed to make any changes to either the data or the database structure.
Inspired by this article, I rolled my own token-based method of authenticating users, but I'm lacking the completeness and (re)assurance of using an established security framework.
Is there a way to integrate an existing framework, e.g. OAuth2, within my current project given the constraints I mentioned above? I don't know if it makes any difference, but I'm self-hosting using OWIN.
This is a good answer to a similar question.
It basically says:
Make a custom user class which implements IUser
Define a custom user store which implements public class UserStoreService
: IUserStore<CustomUser>, IUserPasswordStore<CustomUser>
wire everything up
Since the answer is pretty extensive I just provided the basic steps...
details are here: How to customize authentication to my own set of tables in asp.net web api 2?
This is also a very valuable content which also applies to web api:
Customizing ASP.NET Authentication with Identity by JumpStart
https://channel9.msdn.com/Series/Customizing-ASPNET-Authentication-with-Identity
HTH
Someone else, having the competence, can explain the options. But if authentication as service is an option, then check out Auth0 # https://auth0.com
I have tested the service (as Azure plugin) using both HTML/JS- and native Windows Phone applications, against simple Sql Server table and AD. Works liek charm, near zero headache.
I stumbled upon a my solution while trying to implement json token authentication within web api. It is important to note that my solution handles authentication by sending a json token through the Authentication header of the Http request (not via cookies) and not using Microsoft.Identity framework.
Anyway, I basically implemented in a cookbook fashion the solution helpfully described here by Taiseer Joudeh: http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
The key thing to notice is the following bit of code:
//Dummy check here, you need to do your DB checks against memebrship system http://bit.ly/SPAAuthCode
if (context.UserName != context.Password)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
//return;
return Task.FromResult<object>(null);
}
Naturally you would replace this bit of code above with your own method for checking your (presumably pre-existing) user database(s). Once I implemented this I realized that you don't need to use new code first identity framework that Visual Studio installs for you.
To make this work I did the following:
1) Created an an empty project and selected Change Authentication/Individual User Accounts. This installs most of the required references and files you need out of the box to use token authentication by way of cookies as well as the code-first identity framework files.
2) Edited these files following Taiseer Joudeh's lead. This requires
some new objects such as CustomOAuthProvider.cs among others. And you need to implement your own user/password check by customizing this code block:
if (context.UserName != context.Password)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
//return;
return Task.FromResult<object>(null);
}
Link to Taiseer Joudeh's instructions: http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
3) Pruned my project of extraneous files (AccountBindingModels.cs, AccountViewModels.cs, IdentityModels.cs, ApplicationOAuthProvider.cs, identityConfig.cs, AccountBindingModels.cs, AccountViewModels.cs). Basically, No more microsoft identity references.
I am sure the microsoft.identity thing is excellent, but I was annoyed with the code-first implementation of databases when I was already using some legacy databases of a different structure etc. Hope this helps. I am quite satisfied with the result (after a few days of messing around to get it to work).
I did not want to use any existing classes and finally come out some thing very simple like
var userName = context.UserName;
var password = context.Password;
var userService = new UserService(); // our created one
var user = userService.ValidateUser(userName, password);
if (user != null){
.......
}
See the full details here OAuth Web API token base authentication with custom database
For Role base authentication with custom database
Hope it will help
This might be a completely insane and invalid approach for you but I faced a similar challenge: New web app (MVVM + WebAPI), legacy system used to issue and validate tokens. Inspired by http://tech.pro/tutorial/1216/implementing-custom-authentication-for-aspnet, and because my application would primarily be used by its accompanied GUI (the MVVM webapp), I decided to use a "cookie based" token produced by FormsAuthentication. The FormsAutnentication cookie/ticket is secured by .net internal magic security (which I assume id completely safe and unbreakable).
In my case the cookie simply holds the ticket issued by the legacy system, (but you could store more details there as well, eg by JSONSerializing a custom type). During authorization, my system validates the token against the legacy system. I guess you could use something similar together with a custom AuthorizationFilter.
Related
I'm sure the answer to this must be obvious, as it's an obvious thing want to do, but I can't seem to find any guidance.
I have an ASP.NET Core minimal API, and want to add authentication. I already have Identity set up in a different project, and want to use the same database (ie the same users) for the API.
I saw this blog post, which looked promising until I realised that the code there checks the user name and password as plain text (using admin as both in the sample)...
if (credentials[0] == "admin" && credentials[1] == "admin")
The problem with this is that (thankfully), Identity does not store the passwords in plain text, they are hashed, so I can't do a simple comparison.
I tried hashing the incoming password, as shown in this answer, but that didn't work as the hash came out different every time I called _userManager.PasswordHasher.HashPassword.
I tried using the ASP.NET Core's SignInManager.CanSignInAsync method to check if I could sign in with the credentials, but that required me to add the following to Program...
builder.Services.AddIdentity<User, IdentityRole>(options => {
// options removed for clarity
})
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<AppDbContext>();
However, as soon as I did this, any request to the API attempted to redirect to a log-in page, which is obviously not going to work when the API is being called from code.
All I could find on Microsoft's site was this article, but that assumes you are using Azure. At the moment, I'm still developing this on my local machine, and I don't know yet whether the project owners want to deploy to Azure or their own hosted server, so the code there doesn't help me.
Anyone able to explain to me how I do what seems like such an obvious and simple task? Please let me know if there is any more info I need to provide. Thanks
Have you seen Bipin Joshi's series of articles on this subject? My guess is that you are past the first few, but you might find these useful...
Implement JWT Authentication In ASP.NET Core Minimal APIs
Integrate ASP.NET Core Identity With JWT And Minimal APIs
The one change I made when using that approach was that the getToken API call just takes two string parameters for the user name and password, instead of a User object. Given that it's only two parameters, I find this makes life easier when working with disparate projects, as you don't need the class definition. Up to you though.
In order to call the API, you'll need to call getToken first, passing in the user name and password. Once you have your token, you can then set the authentication on your HtpClient as follows...
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
Having trouble finding a good lead on this. I have a aspnetcore app with identityserver4 configured to use asp identity with a sql database.
There is a business requirement that all non AD users are stored in this asp identity database.
All AD users are defined on Azure. I can authenticate them with LDAP and receive their data.
The issue comes after authentication. Whenever asp identity tries to call:
var user = await UserManager.FindByNameAsync(userName);
With an AD user, it fails because the user does not exist. This is because it is using EF to query the asp identity database, where those users are not defined.
private DbSet<TUser> UsersSet { get { return Context.Set<TUser>(); } }
I can not store any of the AD information in the asp identity database (business requirement). I am trying to find a way to get the user store to look both at the asp identity tables, as well as Azure (via LDAP).
My current method for getting the AD users when doing initial auth is here:
await GetADUser(queryParams),
It uses LDAP to authenticate and grab the user object.
One additional requirement is that I can not use an external login screen, the login must all be done from the same company facing login UI. AKA no external providers.
As per #mxmissile, abstracting the UserManager out was the correct call. Then you can also abstract out other managers as needed for special functionality. This is in fact the only class in the inheritance layer for this part of the code that is virtual.
There are built in functions that let you register your custom managers:
services.AddIdentity<IdentityUser, IdentityRole>()
.AddUserManager<ApplicationUserManager<IdentityUser>>()
.AddSignInManager<ApplicationSignInManager<IdentityUser>>()
Hopefully this is a little help to any others that have a similar question. I ended up just overriding a couple of the functions from the base user manager and just calling the base method for anything that did not need my new logic. By default it looks like ASP Identity does not try to look up users by email - just fyi.
I have a project that is not released yet I will not be soon but I moved it from mvc3 to mvc4 a few days ago and while reading I saw this new security provider SimpleMembership.
The way I implement security now is by using MembershipProvider and FormsAuthentication:
I have implemented ICustomPrincipal
I have implemented CustomPrincipalSerializeModel
I have implemented IPrincipal
To register user I use:
MembershipCreateStatus status;
Guid g = Guid.NewGuid();
Membership.CreateUser(model.User.Email.Trim(), model.Password.Trim(), model.User.Email.Trim(), null, null, true, g, out status);
if (status == MembershipCreateStatus.Success)
...
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
tUser.Email,
DateTime.Now,
DateTime.Now.AddDays(60),
true,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
...
But as I saw SimpleMembership looks much cleaner and I want to move project to it
but I have some questions about it:
1) I use stored procedures for all database actions I don't use EF at all. If I use SimpleMembership is it possible to use it without EF?
2) Do I need to build custom SimpleMembership for real world application?
3) I saw that it seeds database Create tables. I have my tables Users, Profiles, Roles and UsersInRoles can I apply it to my custom schema?
4) If I want to call WebSecurity.CreateAccount(...) and I want to call some my custom method from domain project that is responsible to call stored procedure that create user do I have to make it custom and if I have to do that is there some resource that explain how to make it custom for users and roles?
To understand SimpleMembership and how it has evolved from, and depends on, the previous Membership implementation, I recommmend reading the original reference "Using SimpleMembership With ASP.NET WebPages (Matthew Osborn)", and my more detailed answer to "What is MVC4 security all about?" to understand it better. To summarise those references:
SimpleMembership
is a term that covers both the SimpleMembershipProvider and the SimpleRoleProvider
is a storage and functionality provider that is used with Forms Authentication
works within ASP.NET Forms and ASP.NET MVC websites, and can also be used within ASP.NET Web API and SignalR, to provide a unified authentication and authorisation model
SimpleMembershipProvider
adds new features to the original MembershipProvider through the ExtendedMembershipProvider abstract base class, such as integration with OAuth providers out of the box
creates 4 default tables which you don't/shouldn't interact with (webpages_Membership, webpages_OAuthMembership, webpages_Roles, webpages_UsersInRoles) and one (UserProfile) which is yours to structure as you wish
works with the WebSecurity helper class to add new functionality
Moves from the "user profile" stored in a single xml field in the original Membership, to a more manageable property-per-column in the new UserProfile table (which is fully customisable using EF)
To answer your specific questions:
1) I use stored procedures for all database actions I don't use EF at all. If I use SimpleMembership is it possible to use it without EF?
You would not generally interact directly with the tables prefixed with webpages_ as there are API level functions in Membership, WebSecurity etc. to do all the business functions you require. However there is nothing to stop you interacting with UserProfile through stored procedures, and if you didn't want to take advantage of the APIs, you could even interact with the webpages_ tables through sprocs as well (but you would just be duplicating all the benefits of SimpleMembership if you did).
2) Do I need to build custom SimpleMembership for real world application?
That very much depends on what you want to do, but as yet I have not had to do this for any real world applications. I have built on and added to the existing APIs, but not replaced them.
3) I saw that it seeds database Create tables. I have my tables Users, Profiles, Roles and UsersInRoles can I apply it to my custom schema?
If you were migrating to SimpleMembership you would have to port the data in these to the tables webpages_Membership, webpages_OAuthMembership, webpages_Roles, webpages_UsersInRoles and UserProfile. However, note that UserProfile can be called anything you want, you don't have to call it UserProfile.
4) If I want to call WebSecurity.CreateAccount(...) and I want to call some my custom method from domain project that is responsible to call stored procedure that create user do I have to make it custom and if I have to do that is there some resource that explain how to make it custom for users and roles?
Its a little hard to understand your requirement, however WebSecurity.CreateAccount does the following:
Creates a record in webpages_Membership and
optionally adds properties to UserProfile if you use WebSecurity.CreateUserAndAccount
If you wanted to do other actions across your database you would then need to call that after your call to WebSecurity.CreateAccount. You can make this transactional by using TransactionScope
If however you wanted to wrap this all in a single call to WebSecurity.CreateAccount and make it call your own domain methods and stored procedures you will have to create your own provider by inheriting from SimpleMembershipProvider (or from ExtendedMembershipProvider). When WebSecurity.CreateAccount then calls ExtendedMembershipProvider.CreateAccount it will defer to your custom logic
Summary
So would I migrate? The benefits of SimpleMembership are meant to be:
UserProfile: property-per-column storage of user data that plays well with EF or any other db development method
Integration with OAuth, allowing you to use Google, Facebook etc. authentication with very little effort
High level business function APIs in the form of WebSecurity, and continued support of existing features with Membership
Continued support for Roles that works with the Authorize attribute
Integration with EF so that you can use UserProfile along with your own tables
Integration with standard Forms Authentication for ASP.NET Forms and MVC, and also with SignalR and Web API.
If those help you out, then migrate, otherwise spend your dev time on new features for your application.
If you do decide to migrate, then "Migrating Legacy Apps to the New SimpleMembership Provider (Paul Brown)" is useful, which is summarised as:
Modify UserProfile to have a field per property for your old user profile properties that were stored in xml
Migrate your data from the aspnet_ tables to the webpages_ tables
The first time each user logs in again, update their stored password to use the new hash model instead of the old Membership one (see the footnote to my answer here for how to do this)
#Andy Brown makes a lot of good points. I would note to anyone who lands on this that Simplemembership is basically dead and was short lived with ASP.Net Identity coming out shortly after it and is what is used in all new projects. Such a short lived membership product.
I am trying to learn about how to do Roles in ACS. I have a Windows Store App (not a website :-), and I need Administrator and a Member roles - but finding even very basic documentation or tutorials for something like this is proving very difficult for me.
All I have found are a bunch of references to ASP.NET or Azure Websites stuff - which I can't use, since a Store app is not a Website - and doesn't use ASP.NET.
I have Azure Mobile Services for my Windows Store app. Is there any information that you know of that could be of help?
I'm surprised that Roles don't seem to be covered in the samples/reference/tutorials section anywhere on the Azure website (unless I've missed it - several times).
Take, for example, this scenario. Here, in the Script tab of the Management Portal, I insert some text into the table associated with the currently logged in user (via the insert function):
var SendGrid = require('sendgrid').SendGrid;
function insert(item, user, request) {
item.userId = user.userId;
request.execute(
{
success: function() {
request.respond();
// Send email in the background.
sendEmail(item);
}
}
);
}
The above code inserts some text into the table and then sends an email to that user. But, how could I adapt this code, so that it would (pseudo code):
if item.text == "administrator"
then insert userid into admin column
else
then insert userid into member column
Any help at all will be highly appreciated.
It is not really an answer, but it is also too long for a comment, and I think it is really important.
First of all, when using authentication from the Windows Azure Mobile Services, you are not using Windows Azure Access Control Service. So, there is no Active Directory, there are no (additional) claims when one uses Mobile Services. This must be very clear, because I see continuous misunderstanding and confusion. #Joey still asks for, and refers ACS as federation provider for his application, which is not the case if he relies on the Mobile Services authentication mechanism.
So, the roles assignment must totally be handled by your application logic with additional table as Jim describes.
However roles assignment in general is interesting topic, and really is not part of any tutorial or documentation. And it is not part of such, because Role Assignment is part of business logic of the application itself, not part of the Authentication service. There is very similar question here, which however again does not answer in detail how to assign roles. The foundation and main issue to solve is: How to assign administrator role. Everything else, can be solved by adding appropriate UI for the application administrators. Still, this question is not subject to a short SO answer.
For a given application I have a .aspx login form backed by a C# code behind file.
In the code behind I am using the following "home grown" method:
private bool AuthenticateUser(String username, String password)
{
bool validated = false;
try
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, "domnet.domad.com", "dc=domnet,dc=domad,dc=com");
IdentityType ADElement;
UserPrincipal up;
//Try first with no #DOM.COM - this should work for SamAccountName values:
username = username.ToUpper().Replace("#DOM.COM", "");
ADElement = IdentityType.SamAccountName;
up = UserPrincipal.FindByIdentity(pc, ADElement, username);
validated = pc.ValidateCredentials(username, password, ContextOptions.Negotiate);
//If SamAccountName fails try UserPrincipalName with #DOM.COM
if (!validated)
{
username = username + "#DOM.COM";
ADElement = IdentityType.UserPrincipalName;
up = UserPrincipal.FindByIdentity(pc, ADElement, username);
validated = pc.ValidateCredentials(username, password, ContextOptions.Negotiate);
}
//Put username into session
if (validated)
{
Session["Username"] = username.Replace("#DOM.COM", "");
}
}
catch (Exception) //login failure...
{
validated = false;
}
return validated;
}
This works fine for the application but I have other applications that need authentication too.
I really don't want to copy / paste the login files into ever application.
So my most basic question is what are my options to centralize the authentication code between applications?
In the future I will also be looking to:
Verify not only username/password but also AD group membership.
Once user is authenticated no more log in screens between apps. (SSO)
It seems to me I am not the first person to run into this problem.
I would prefer to use an out of the box solution vs. developing my own if possible.
You could:
Enable Windows authentication in IIS and set your Web.Config to use Window authentication http://weblogs.asp.net/scottgu/archive/2006/07/12/Recipe_3A00_-Enabling-Windows-Authentication-within-an-Intranet-ASP.NET-Web-application.aspx
Setup an ADFS claims authentication server and have all your applications use claims based authentication http://blogs.msdn.com/b/alextch/archive/2011/06/27/building-a-test-claims-aware-asp-net-application-and-integrating-it-with-adfs-2-0-security-token-service-sts.aspx
Have one application that all others redirect to for authentication and set an encrypted cookie that the other applications can read to verify authentication Encrypt cookies in ASP.NET
One approach would be to create a Core project (.dll/library) that contains the common parts that you wish to share between your applications, and then to reference that project in your applications.
Ie: Say that you have 2 applications: A and B you would create three projects A, B and Core. In project A and B simply add a project reference to the Core library. Now you can access any method in core from both A and B.
This approach works well with SVN and similar version control systems and you will find it is a very flexible way of working. The hard part is to identify what is really common code and and to make as general as possible.
#Baxter Not sure if my answer comes a bit late as this question was posted a few days ago, but am looking into the same problem of implementing centralized session and authentication management in my MVC 3 application, and I believe the following link would be of great interest to you:
http://www.codeproject.com/Articles/246631/ASP-NET-MVC3-Form-Authentication
The author of the article corresponding to the link above, factors out the authentication functionality into a separate DLL and uses dependency injection to use application context to utilize the external 'security' DLL. I am planning to use this approach to centralize the security mechanism and reuse it in 3 different MVC 3 web applications, so it is still research in progress, and will update this answer accordingly with what i find :)
You can refactor this method out into a separate project (meaning a different dll) and reference that project from any web application where you want to use this code.
An alternative if you are using Windows Authentication is to grab their SID, query AD for a piece of information that is shared between AD and the application's user table (we use the email address) and check to see if the user table has an entry with that email address.
This way, by logging onto their workstation, they are essentially pre-logged into any application using this authentication method. You just have to make sure that when you create a new user account (at the application level) you capture the info that you want to check for authentication (this is why we use the email address - everyone knows their company email).
This works really well with the Core library method suggested by Avada Kedavra. This method also allows you to have each application maintain its own user base (although it will also work well with a central user database).