I have a service call DataManager that needs a reference to the current IPrincipal user. However, I don't want to use a global reference like System.Threading.Thread.CurrentPrincipal or HttpContext.Current.User because I want to be able to unit test it and specify any user for any given test. But I also don't want to construct a new DataManager for each thread in a multi-threaded environment (like WebApi or Web Services).
Is it bad practice or will it break anything if I inject (via constructor) an IPrincipal implementation that internally uses HttpContext.Current.User or HttpContext.Current.User? Otherwise how should I handle this?
The solution I am thinking of looks like this:
public class DataManager {
public DataManager(IPrincipal currentUser){
this.currentUser = currentUser;
}
private IPrincipal currentUser;
...
public void DoWork(){
var currentUserName = currentUser.Identity.Name;
// Do work here
}
}
And then, when using this in ASP.NET, pass in an IPrincipal implementation that references the HTTP context's current user:
public class CurrentUser : IPrincipal {
public IIdentity Identity {
get {
return HttpContext.Current.User.Identity;
}
}
public bool IsInRole(string role) {
return HttpContext.Current.User.IsInRole(role);
}
}
Related
I want to use AutoFac to inject the current principal in the objects that need it. Suppose I have an object (AuthorizationValidator) that is performing security checks. It looks something like this:
public AuthorizationValidator : IAuthorizationValidator
{
public AuthorizationValidator(IDataAccess dataAccess, IPrincipal principal)
{
// Save injected objects
...
}
public bool CheckPermission(Guid objectId, Action action)
{
// Check if we are authorized at all
if (this.principal == null)
return false;
// Check the permission in the database
...
}
}
For my web application the AuthorizationValidator is registered and I use the following registration to inject the principal:
builder.Register<IPrincipal>((c, p) => HttpContext.Current?.User);
Other type of applications use the thread's principal or something similar. All object that require the principal get the proper principal injected.
If a call is made without authorization, then AutoFac raises an exception telling me that it cannot provide the IPrincipal object, because the factory returned null. In this case, an empty principal is fine and shouldn't raise an exception.
In the Autofac documentation they recommend to use the Null Object pattern for such scenarios. You could create a NullPrincipal class that inherits from the IPrincipal interface with a private constructor that only exposes a readonly static field which provides the default instance. Then you can return this instance instead of null:
builder.Register<IPrincipal>((c, p) => HttpContext.Current?.User ?? NullPrincipal.Default);
Of course you would have to update all places in your code where you are checking if the principal is null and check if it is equal to the NullPrincipal.Default instead.
To solve this problem, I have created the IPrincipalFactory interface that can obtain the current principal without going through AutoFac:
public AuthorizationValidator : IAuthorizationValidator
{
public AuthorizationValidator(IDataAccess dataAccess, IPrincipalFactory principalFactory)
{
// Save injected objects
_dataAccess = dataAccess;
_principal = principalFactory.GetCurrentPrincipal();
}
public bool CheckPermission(Guid objectId, Action action)
{
// Same as previous example
...
}
}
public interface IPrincipalFactory
{
IPrincipal GetCurrentPrincipal();
}
For the ASP.NET application I would register the following object as IPrincipalFactory:
public class IAspNetPrincipalFactory : IPrincipalFactory
{
public IPrincipal GetCurrentPrincipal() => HttpContext.Current?.User;
}
Although this works, I am not completely happy with this solution.
I have a Singleton model class in my MVC application to determine if the user logging in has authorization/admin (based on memberships to certain AD groups). This model class needs to be a Singleton so that the user's access rights can be established once at first logon and used throughout the session:
public sealed class ApplicationUser
{
// SINGLETON IMPLEMENTATION
// from http://csharpindepth.com/articles/general/singleton.aspx#lazy
public static ApplicationUser CurrentUser { get { return lazy.Value; } }
private static readonly Lazy<ApplicationUser> lazy =
new Lazy<ApplicationUser>(() => new ApplicationUser());
private ApplicationUser()
{
GetUserDetails(); // determine if user is authorized/admin
}
// Public members
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
// Private members
// more code
}
The Singleton is instantiated for the first time in my EntryPointController that all other controllers derive from:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
This patterns allows me to use ApplicationUser.CurrentUser.Name or ApplicationUser.CurrentUser.IsAuthorized etc all over my application.
However, the problem is this:
The Singleton holds the reference of the very first user that logs in at the launch of the web application! All subsequent users who log in see the name of the earliest logged-in user!
How can I make the Singleton session specific?
I think you are looking for the Multiton pattern, where each instance is linked to a key.
An example from here
http://designpatternsindotnet.blogspot.ie/2012/07/multiton.html
using System.Collections.Generic;
using System.Linq;
namespace DesignPatterns
{
public class Multiton
{
//read-only dictionary to track multitons
private static IDictionary<int, Multiton> _Tracker = new Dictionary<int, Multiton> { };
private Multiton()
{
}
public static Multiton GetInstance(int key)
{
//value to return
Multiton item = null;
//lock collection to prevent changes during operation
lock (_Tracker)
{
//if value not found, create and add
if(!_Tracker.TryGetValue(key, out item))
{
item = new Multiton();
//calculate next key
int newIdent = _Tracker.Keys.Max() + 1;
//add item
_Tracker.Add(newIdent, item);
}
}
return item;
}
}
}
I got it working with a mixed Singleton-Multiton approach (thanks #Kickaha for the Multiton pointer).
public sealed class ApplicationUser
{
// SINGLETON-LIKE REFERENCE TO CURRENT USER ONLY
public static ApplicationUser CurrentUser
{
get
{
return GetUser(HttpContext.Current.User.Identity.Name);
}
}
// MULTITON IMPLEMENTATION (based on http://stackoverflow.com/a/32238734/979621)
private static Dictionary<string, ApplicationUser> applicationUsers
= new Dictionary<string, ApplicationUser>();
private static ApplicationUser GetUser(string username)
{
ApplicationUser user = null;
//lock collection to prevent changes during operation
lock (applicationUsers)
{
// find existing value, or create a new one and add
if (!applicationUsers.TryGetValue(username, out user))
{
user = new ApplicationUser();
applicationUsers.Add(username, user);
}
}
return user;
}
private ApplicationUser()
{
GetUserDetails(); // determine current user's AD groups and access level
}
// REST OF THE CLASS CODE
public string Name { get { return name; } }
public bool IsAuthorized { get { return isAuthorized; } }
public bool IsAdmin { get { return isAdmin; } }
private string name = HttpContext.Current.User.Identity.Name;
private bool isAuthorized = false;
private bool isAdmin = false;
// Get User details
private void GetUserDetails()
{
// Check user's AD groups and determine isAuthorized and isAdmin
}
}
No changes to my model and controllers.
The current user's object is instantiated in the EntryPointController:
public abstract class EntryPointController : Controller
{
// this is where the ApplicationUser class in instantiated for the first time
protected ApplicationUser currentUser = ApplicationUser.CurrentUser;
// more code
// all other controllers derive from this
}
In my model and everywhere else, I can access the current user's properties using ApplicationUser.CurrentUser.Name or ApplicationUser.CurrentUser.IsAuthorized etc.
How can I make the Singleton session specific?
Will lead to your problem below.
The Singleton holds the reference of the very first user that logs in
at the launch of the web application! All subsequent users who log in
see the name of the earliest logged-in user!
I think you just simply need to store your ApplicationUser object in session per user.
The mechanism should look like this:
Create an instance of your ApplicationUser every authenticated user.
Store ApplicationUser instance in a session with key. ( Don't worry about same key per user because ASP.NET HttpSessionState will handle it for you. )
If you want to access your ApplicationUser object per user just simply get it from HttpSessionState.
You have an option to create/re-create your session in Session_OnStart or in your base controller.
Setup your session setting if you want it to expire or not.
I hope this solution will make sense to you. :)
I have a custom IPrincipal called UserPrincipal which I use within my controllers. I use a base controller to set the User then implement that base controller within all my other MVC controllers. My BaseController:
public class BaseController : Controller
{
protected virtual new UserPrincipal User
{
get { return HttpContext.User as UserPrincipal; }
}
}
That works perfectly well however now I am attempting to setup an API using using the ApiController class. I would like those ApiControllers to use the same UserPrincipal so I have essentially copied and pasted the same code into a BaseApiController class:
public class BaseApiController : ApiController
{
protected virtual new UserPrincipal User
{
get { return HttpContext.User as UserPrincipal; }
}
}
This second version has a Compiler error at HttpContext.User stating the following:
Cannot access non-static property 'User' in static context.
What is different about the ApiController from Controller and why am I getting this error?
ApiController already has a property called User which returns an IPrincipal
MSDN: ApiController.User Property
If I correctly understand what you wish to do, then I believe that you should be able to leverage this property without adding any custom code or other properties.
I came by this solution with the help of David Tansey's answer. Instead of HttpContext.User I use base.User.
public class BaseApiController : ApiController
{
protected virtual new UserPrincipal User
{
get { return base.User as UserPrincipal ?? new UserPrincipal("defaultuser"); }
}
}
I added that null check and supplied a default user because the casting will result in null if the user isn't logged in and I don't want to null check constantly throughout my application.
Try setting the principal. See http://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api for more information.
private void SetPrincipal(IPrincipal principal)
{
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = principal;
}
}
Also look into Token-based authentication.
I've been searching the web for this, and couldn't really find a solution that actually worked. Situation is as follows: I've got a WPF application, where I want to present the user with a simple logon form. Trying to work MVVM, so I've got a LoginViewModel with the following code behind the login command:
try
{
WithClient(servfact.GetServiceClient<IAccountService>(), proxy =>
{
principal = proxy.AuthenticateUser(Login, password);
});
Thread.CurrentPrincipal = principal;
}
catch(...) { ... }
"WithClient" is a short method in my viewmodel baseclass, which I use to instantiate and dispose of my service proxies:
protected void WithClient<T>(T proxy, Action<T> codeToExecute)
{
try { codeToExecute(proxy); }
finally
{
IDisposable toDispose = (proxy as IDisposable);
if(toDispose != null) { toDispose.Dispose(); }
}
}
Now, most of my services are Async, and I've got an async variant of WithClient going on, which also works fine:
protected async Task WithClientAsync<T>(T proxy, Func<T, Task> codeToExecute)
{
try { await codeToExecute(proxy); }
finally
{
IDisposable toDispose = (proxy as IDisposable);
if(toDispose != null) { toDispose.Dispose(); }
}
}
The trouble begins whenever I also want to do the login asynchronously. Obviously I don't want the UI to freeze up as I do the login (or visit any WCF service for that matter). That in itself is working fine, but the problem sits in the piece of code where I set the CurrentPrincipal. This problem is probably familiar to most of you: it seems to set it just fine. Then in my program I want to use the CurrentPrincipal (either on the client side or to send the users login to a WCF service in a messageheader), but it seems to be reset to a standard GenericPrincipal. When I revert the login back to being synchronous, the CurrentPrincipal is just fine. So in short: how do I set the principal in the asynchronous code, having it persist later on, instead of reverting back to a standard principal?
Well, well, no answer in a year. No worries, since I managed to solve this myself: I simply wrapped a singleton around it all:
public sealed class CurrentPrincipalFacade : IPrincipal
{
#region Singleton mechanism
private static readonly CurrentPrincipalFacade instance = new CurrentPrincipalFacade();
public static CurrentPrincipalFacade Instance { get { return instance; } }
private CurrentPrincipalFacade() { }
#endregion
#region IPrincipal members
public IPrincipal Principal { get; set; }
public IIdentity Identity { get { return Principal == null ? null : Principal.Identity; } }
public bool IsInRole(string role) { return Principal != null && Principal.IsInRole(role); }
public void Reset() { Principal = new GenericPrincipal(new GenericIdentity(""), new string[] { }); }
#endregion}
So I set that after login. I guess the problem was I was setting the principal in another thread, which got lost when I got out of that?
I am just about to start on a project, where I will be using MVC5. But as I want to use IoC and later reuse my user tables, and add custom stuff to it, I am finding it very hard to see how I can use the new Identity framework that came with MVC5.
I am more and more looking towards basic forms auth. What are your solutions?
My needs:
User repository/service must be injected
User repository must reside in the DAL
User repository must be able to support other technologies than EF
Authentication with OpenID and OAuth must be somewhat easy to implement
MUST BE SECURE
Should be reusable in other projects, eg. WPF
I have been looking for a long time for an answer, but everything I see is hardcoded in the controller.
How are you solving this? Are you writing most from scratch, or can you bind into something that will scale to other .NET platforms as WCF and WPF?
The below code is taken directly from the AccountController in the default ASP.NET MVC 5 Template.
The first thing it does is a Bastard Injection.
[Authorize]
public class AccountController : Controller
{
public AccountController()
: this(
new UserManager<ApplicationUser>(
new UserStore<ApplicationUser>(
new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
}
The accepted answer will go to the person, that shows me what they have done, that incorporates the above requirements
Since this is .NET, the standard approach to security is to authenticate at the application boundary, and convert the authentication information into an IPrincipal. MVC supports this out of the box.
If you need other information gained during authentication, you can gather that at in the Composition Root and use it to compose your services.
As an example, imagine that you need the authenticated user's email address in a lower layer. Any class that requires the user's email address can simply request it as a Concrete Dependency:
public class EmailThingy
{
private readonly string userEmail;
public EmailThingy(string userEmail)
{
if (userEmail == null)
throw new ArgumentNullException("userEmail");
this.userEmail = userEmail;
}
// other members go here...
}
In ASP.NET MVC, the Composition Root is IControllerFactory. IIRC, you can pull the authentication data from within the CreateController method and use it to compose your object graph.
These days, I use IPrincipal in the same way: I inject it as a dependency, instead of relying on the Thread.CurrentPrincipal Ambient Context, because it's easier to unit test when everything is consistently injected via Constructor Injection.
You might be interested to get a look at Thinktecture.IdentityServer.v2 https://github.com/thinktecture/Thinktecture.IdentityServer.v2. Many of your concerns are already implemented and encapsulated. If you don't find what you need you'll have to think about how to abstract all these concerns and implement it on your own.
I ended up deciding to implement the IUserStore, IUserStore, IUserPasswordStore, IUserLoginStore, to be able to move the UserRepository down into it's rightful place, the DataAccess Layer. But still get the Security Benifits of the Owin and new Identity Framework.
It's quite easy to implement, and doesn't take much to abstract it. Here is a taste of the UserStoreWrapper
namespace qubis.booking.WebApp.App_Code.Identity
{
public class UserServiceWrapper : IUserStore<ApplicationUserWrapper>,
IUserPasswordStore<ApplicationUserWrapper>,
IUserLoginStore<ApplicationUserWrapper>
{
public IUserRepository UserRepos { get; set; } // My own Interface.
public UserServiceWrapper(IUserRepository userRepo)
{
UserRepos = userRepo;
}
public async Task CreateAsync(ApplicationUserWrapper user)
{
UserRepos.Insert(user.RealUser);
}
public async Task<ApplicationUserWrapper> FindByIdAsync(string userId)
{
var appUser = UserRepos.FindByUserName(userId);
ApplicationUserWrapper wrappedUser;
if (appUser != null)
{
wrappedUser = new ApplicationUserWrapper(appUser);
}
else
wrappedUser = null;
return wrappedUser;
}
In the Account controller I Simply just ask for it to be injected:
public AccountController(UserManager<ApplicationUserWrapper> userManager)
{
UserManager = userManager;{ AllowOnlyAlphanumericUserNames = false };
}
And as I am using Ninject I just set it upin the kernel like so:
// <summary>
// Load your modules or register your services here!
// </summary>
// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUserStore<ApplicationUserWrapper>>().To<UserServiceWrapper>();
kernel.Bind<UserManager<ApplicationUserWrapper>>().ToSelf();
}
To see the Identity frameworks structure, please see this article. http://www.asp.net/identity/overview/extensibility/implementing-a-custom-mysql-aspnet-identity-storage-provider
If all you need is to inject custom UserStore implementation this article may help you
Basically you need to inject this (depends if you want to use roles, claims etc..):
Write a User class that implements the IUser interface
public class IdentityUser : IUser {
public IdentityUser(){...}
public IdentityUser(string userName) (){...}
public string Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string SecurityStamp { get; set; }
}
Write a User store class that implements the IUserStore, IUserClaimStore, IUserLoginStore, IUserRoleStore and IUserPasswordStore
public class UserStore : IUserStore<IdentityUser>,
IUserClaimStore<IdentityUser>,
IUserLoginStore<IdentityUser>,
IUserRoleStore<IdentityUser>,
IUserPasswordStore<IdentityUser> {
public UserStore(){...}
public Task CreateAsync(IdentityUser user){...}
public Task<IdentityUser> FindByIdAsync(string userId){...}
.. .
}