I am using Visual Studio 2015 Enterprise and ASP.NET vNext Beta8 to issue and consume JWT tokens as described here.
In our implementation we're storing some client details in Redis at token issuing time and we would like the flush this information when the user logs out.
My question is what is the best practices for logging out with OIDC?
While I could roll my own contoller for this purpose I couldn't help but notice Open ID Connect (OIDC) seems somewhat primed to handle this case. For example OIDC has an OnLogoutEndpoint handler and LogoutEndpointPath settings. But when I call the OIDC logout URI that handler appears to accept any random x-www-form-urlencoded form I throw at it and doesn't in any particular way seem to be demanding the presence of a token.
Any advice on proper OIDC logout practices would be very much appreciated.
In AspNet.Security.OpenIdConnect.Server, the logic used for the logout endpoint is left as an exercise.
In this sample, it is implemented using an MVC 6 controller, where you're - of course - free to add custom logic to remove cached details from your Redis server.
[HttpPost("~/connect/logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout() {
// When invoked, the logout endpoint might receive an unauthenticated request if the server cookie has expired.
// When the client application sends an id_token_hint parameter, the corresponding identity can be retrieved using AuthenticateAsync.
var identity = await HttpContext.Authentication.AuthenticateAsync(OpenIdConnectServerDefaults.AuthenticationScheme);
// Remove the cached details here. If you need to determine
// who's the authenticated user, you can use the identity variable.
// Remove the authentication cookie and return the user to the client application.
return SignOut("ServerCookie", OpenIdConnectServerDefaults.AuthenticationScheme);
}
You can also do something similar directly from the LogoutEndpoint event. Don't forget to call context.HandleResponse() to make sure the request is not intercepted by another middleware.
We currently have an internal API that uses Windows Authentication. I've been charged with looking into making this API public, and one of the requirements is that it should be possible to login without a domain user. Domain users should still be able to login, and should be considered super admins (access everything).
It is also clear that before long, we will need role or claim based authorization. As a prototype, I have implemented a system using ASP.NET Identity. Using JWT tokens and Claims based authorization.
But how do I ensure that users authenticated with Windows Authentication can skip the token step and simply use the API directly?
Found a solution where I add custom AuthorizationFilterAttributes to my endpoints. In the attribute, I check for the Principal type:
public override Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
{
if (actionContext.RequestContext.Principal is WindowsPrincipal)
{
return Task.FromResult<object>(null);
}
//Custom logic here
[...]
}
Inside some web api controllers, I would like to access the User as indicated in this answer: https://stackoverflow.com/a/12705062/538962
sample code from answer...
[Authorize]
public List<Product> GetProductsFromId()
{
string username = User.Identity.Name;
return _productService.GetProductsFromUsername(username);
}
The asp_net membership tables in my scenario are on a different database server than then the database server the application runs on. The database for the application has its own Users table with an IDENTITY column as the Primary Key on the Users table, and then other tables that include a CreatedByUserID and UpdatedByUserID columns are integers based off the IDENTITY column in the users table.
The issue is that if CRUD type operations depend on the user being updated in tables as an INTEGER, just accessing the username alone is not sufficient; we still have to get to that username's corresponding UserID.
This could be done with another join to the Users table, but this seems a bit kludgy. What would be the best way to go about handling this issue?
From the perspective of ASP.NET Web API, using membership provider and the out-of-box FormsAuthentication is already kludgy, so why not the join? :) Anyways, assuming your web API is consumed by only the web clients and FA is cool, you can use the UserData of the FA ticket to put in the user ID. That way, you don't need to get the ID by hitting your DB every time. But you will need to create the ticket yourself and not let the default out-of-box implementation do that for you. Then, in the PostAuthenticateRequest event, you can read the user ID from the ticket and set it in the identity. Of course, you need to create your own custom identity for this with an ID property or if you are on .NET 4.5, you can use FormsIdentity itself but you can use the NameIdentifier claim to store the ID, perhaps. Check this out - ASP.NET MVC - Set custom IIdentity or IPrincipal.
I am developing an ASP.NET website. I am planning to use Forms authentication in order to guarantee authentication/authorization, but I am facing two problems regarding the authorization:
I know how to set in the web config that the authenticated users are allowed to visit a webpage (say myPage.aspx). But I do not know how to define that UserA is able to access myPage to retrieve his information, not UserB's information.
I was thinking about generating a token when the user authenticates, so I am able to check to whom this token belongs to and verify if this information is available to him.
What do you think about this approach? Does the Form Authentication generates a token like that? (I couldn't find any mention about it in my research). If not, could I adapt the Form authentication mechanisms in order to generate or would I need to write everything on my own?
I would like to access webservices, and these should only return information if the user is logged. For this reason, I would like to use the same token explained above. What do you think about it? Is it a good approach?
I am asking this because I have no experience on designing authentication/authorization mechanisms, any help/hint would be appreciated.
Regarding question one, after forms authentication occurs in an ASP.Net web forms app, the user's identity is exposed as a FormsIdentity object in the Page.User.Identity property. This object has a Name property which contains the username that a user use to log into your site. You can use this value to restrict what a user can access. For example, let's say you have a table in your database with user information containing the following fields:
userId int
userName varchar(25)
...more fields containing user information...
You can restrict a user to only access information from the row in this table in which the userName equals the Page.User.Identity.Name property, either directly if you are using direct ADO.Net or via your query to your ORM-mapped (i.e. nHibernate or EF) domain object.
Regarding question two, the FormsIdentity object exposed by Page.User.Identity has a boolean "IsAuthenticated" property. You can use this to restrict access to your web service as follows:
if(Page.User.Identity.IsAuthenticated)
{
//Call your web service in a secure manner
}
I'm creating my first ASP.NET MVC site and have been trying to follow domain driven development. My site is a project collaboration site where users can be assigned to one or more projects on the site. Tasks are then added to projects, and users with in a project can be assigned to tasks. So a "User" is a fundamental concept of my domain model.
My plan is to have a "User" model object which contains all the information about a user and can be accessed through an IUserRepository. Each user can be identified by a UserId. Although I'm not sure at this point if I want the UserId to be a string or integer.
How should my domain objects User and IUserRepository relate to the more administrative functions of my site like authorizing users and allowing them to login? How would I integrate my domain model with other aspects of ASP.NET such as HttpContext.User, HttpContext.Profile, a custom MemberShipProvider, a custom ProfileProvider, or custom AuthorizeAttribute?
Should I create a custom MembershipProvider and or ProfileProvider which wraps my IUserRepository? Although, I can also foresee why I may want to separate the User information in my domain model from the authorization of a user on my site. For example in the future I may want to switch to windows authentication from forms authentication.
Would it be better to not try and reinvent the wheel and stick with the standard SqlMembershipProvider built into ASP.NET? Each user's profile information would be stored in the domain model (User/IUserRepository), but this would not include their password. I would then use the standard ASP.NET membership stuff to handle creating and authorizing users? So there would need to be some code somewhere that would know to create a profile for a new users in the IUserRepository when their account is created or the first time they login.
Yes - very good question. Like #Andrew Cooper, our team also went through all this.
We went with the following approaches (right or wrong):
Custom Membership Provider
Neither I or the other developer are fans of the built in ASP.NET Membership provider. It's way too bloated for what our site is about (simple, UGC-driven social website). We created a very simple one that does what our application needs, and nothing more. Whereas the built-in membership provider does everything you might need, but most likely won't.
Custom Forms Authentication Ticket/Authentication
Everything in our application uses interface-driven dependency injection (StructureMap). This includes Forms Authentication. We created a very thin interface:
public interface IAuthenticationService
{
void SignIn(User user, HttpResponseBase httpResponseBase);
void SignOut();
}
This simple interface allows easy mocking/testing. With the implementation, we create a custom forms authentication ticket containing: things like the UserId and the Roles, which are required on every HTTP request, do not frequently change and therefore should not be fetched on every request.
We then use an action filter to decrypt the forms authentication ticket (including the roles) and stick it in the HttpContext.Current.User.Identity (for which our Principal object is also interface-based).
Use of [Authorize] and [AdminOnly]
We can still make use of the authorization attributes in MVC. And we also created one for each role. [AdminOnly] simply checks the role for the current user, and throws a 401 (forbidden).
Simple, single table for User, simple POCO
All user information is stored in a single table (with the exception of "optional" user info, such as profile interests). This is mapped to a simple POCO (Entity Framework), which also has domain-logic built into the object.
User Repository/Service
Simple User Repository that is domain-specific. Things like changing password, updating profile, retrieving users, etc. The repository calls into domain logic on the User object i mentioned above. The service is a thin wrapper on top of the repository, which seperates single repository methods (e.g Find) into more specialized ones (FindById, FindByNickname).
Domain seperated from security
Our "domain" the User and his/her's association information. This includes name, profile, facebook/social integration, etc.
Things like "Login", "Logout" are dealing with authentication and things like "User.IsInRole" deals with authorization and therefore do not belong in the domain.
So our controllers work with both the IAuthenticationService and the IUserService.
Creating a profile is a perfect example of domain logic, that is mixed with authentication logic also.
Here's what our's looks like:
[HttpPost]
[ActionName("Signup")]
public ActionResult Signup(SignupViewModel model)
{
if (ModelState.IsValid)
{
try
{
// Map to Domain Model.
var user = Mapper.Map<SignupViewModel, Core.Entities.Users.User>(model);
// Create salt and hash password.
user.Password = _authenticationService.SaltAndHashPassword();
// Signup User.
_userService.Save(user);
// Save Changes.
_unitOfWork.Commit();
// Forms Authenticate this user.
_authenticationService.SignIn(user, Response);
// Redirect to homepage.
return RedirectToAction("Index", "Home", new { area = "" });
}
catch (Exception exception)
{
ModelState.AddModelError("SignupError", "Sorry, an error occured during Signup. Please try again later.");
_loggingService.Error(exception);
}
}
return View(model);
}
Summary
The above has worked well for us. I love having a simple User table, and not that bloated madness that is the ASP.NET Membership provider. It's simple and represents our domain, not ASP.NET's representation of it.
That being said, as i said we have a simple website. If you're working on a banking website then i would be careful about re-inventing the wheel.
My advice to use is create your domain/model first, before you even think about authentication. (of course, this is what DDD is all about).
Then work out your security requirements and choose an authentication provider (off the shelf, or custom) appropriately.
Do not let ASP.NET dictate how your domain should be designed. This is the trap most people fall into (including me, on a previous project).
Good luck!
Let me break down your collection of questions a bit:
Although I'm not sure at this point if I want the UserId to be a string or integer.
It doesn't have to be an integer per say, but definitely use some kind of bit based value here (e.g. int, long or guid). An index operating over a fixed size value is much faster than an index over a string, and in your life time, you will never run out of identifiers for your users.
How should my domain objects User and IUserRepository relate to the more administrative functions of my site like authorizing users and allowing them to login?
Decide if you want to use the built in asp.net membership or not. I recommend not for the reason that it's mostly just bloat and you have to implement most of the features of it yourself anyway, like email verification, which you'd think from looking at the tables generated it would be built in... The template project for ASP.NET MVC 1 and 2 both include a simple membership repository, just rewrite the functions that actually validate the user and you'll be well on your way.
How would I integrate my domain model with other aspects of ASP.NET such as HttpContext.User, HttpContext.Profile, a custom MemberShipProvider, a custom ProfileProvider, or custom AuthorizeAttribute?
Each one of these is worthy of it's own SO question, and each has been asked here before. That being said, HttpContext.User is only useful if you are using the built in FormsAuthentication functionality and I recommend using it in the beginning until you encounter a situation where it is does not do what you want. I like storing the user key in the name when signing in with FormsAuthentication and loading a request bound current user object at the beginning of every request if HttpContext.User.IsAuthenticated is true.
As for the profile, I avoid stateful requests with a passion, and have never used it before, so someone else will have to help you with that one.
All you need to use the built in [Authorize] attribute is to tell FormsAuthentication the user is valdiated. If you want to use the roles feature of the authorize attribute, write your own RoleProvider and it will work like magic. You can find plenty of examples for that on Stack Overflow. HACK: You only have to implement RoleProvider.GetAllRoles(), RoleProvider.GetRolesForUser(string username), and RoleProvider.IsUserInRole(string username, string roleName) in order to have it work. You do not have to implement the entire interface unless you wish to use all of the functionality of the asp.net membership system.
Would it be better to not try and reinvent the wheel and stick with the standard SqlMembershipProvider built into ASP.NET?
The pragmatic answer for every derivation of this question is to not reinvent the wheel until the wheel doesn't do what you need it to do, how you need it to do it.
if (built in stuff works fine) {
use the built in stuff;
} else {
write your own;
}
if (easier to write your own then figure out how to use another tool) {
write your own;
} else {
use another tool;
}
if (need feature not in the system) {
if (time to extend existing api < time to do it yourself) {
extend api;
} else {
do it yourself;
}
}
I know my answer comes a little bit late, but for future references to other colleagues having the same question.
Here is an example of Custom Authentication and Authorization using Roles as well.
http://www.codeproject.com/Articles/408306/Understanding-and-Implementing-ASP-NET-Custom-Form. It's a very good article, very fresh and recent.
In my opinion, you should have this implementation as part of the infrastructure (Just create a new project Security or whatever you want to call it) and implement this example above there. Then call this mechanism from your Application Layer. Remember that the Application layer controls and orchestrate the whole operation in your application. Domain layer should be concern exclusively about business operations, not about access or data persistence, etc.. It's ignorant on how you authenticate people in your system.
Think of a brick and mortar company. The fingerprint access system implemented has nothing to do with this company's operations, but still, it's part of the infrastructure (building). As a matter of fact, it controls who have access to the company, so they can do their respective duties. You don't have two employees, one to scan his fingerprint so the other can walk in and do its job. You have only an Employee with an index finger. For "access" all you need is his finger... So, your repository, if you are going to use the same UserRepository for authentication, should contain a method for authentication. If you decided to use an AccessService instead (this is an application service, not a domain one), you need to include UserRepository so you access that user data, get his finger information (username and password) and compares it with whatever is coming from the form (finger scan). Did I explain myself right?
Most of DDD's situations apply to real life's situations... when it comes to architecture of the software.