What is the different between the following 3 methods to retrieve the claim?
Called in a ApiController:
((ClaimsIdentity) HttpContext.Current.User.Identity).Claims
((ClaimsIdentity) Thread.CurrentPrincipal.Identity).Claims
((ClaimsIdentity) User.Identity).Claims
The first two attributes have stored the same data but the last one has stored the data from the previous session.
This is done in the logout method:
UserCache.Instance.Clear();
FederatedAuthentication.SessionAuthenticationModule.SignOut();
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
Update
Mixed WebForms, WebApi, MVC Application
Most of the application is build using WebForms.
If you are working with WebApi, then HttpContext.Current should not be available directly (see this answer). So I'm guessing you are using MVC as well and you see MVC context there.
Thread.CurrentPrincipal is dangerous to use because it contains thread principle which can be something you never expect, like user that actually runs IIS (AppPool user). Most of the time it is what you think, but sometimes it is not. And this will cause you endless bug-chasing that you can never recreate yourself.
User.Identity as ClaimsIdentity is the correct way to get what you need and it is used in the default template from VS. However if you see the data from "previous session" - means your cookies are not cleared properly. And the way you sign-out user looks suspicious:
What is UserCache.Instance?
SignOut method does not actually sign out user until the request is complete. So if you call this and then check for user identity within the same request, you'll see the same identity intact.
Assigning HttpContext.Current.User will not give you much within the request. See very first point if we are talking about pure WebAPI.
Default sign-out is done via IAuthenticationManager
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
[Route("Logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
Try this and then adjust for your needs.
Related
So I have an application that's calling the graph API.
See the following snippet:
When the try (AquireTokenSilent) is called, the Web Request completes successfully no problem.
However, when make the same web request with the token I get from AcquireTokenAsync, I'm getting a 404 error and an exception thrown.
1) Can you recommend some good tools to analyze the HTTP request (so I can compare the difference and identify a problem). The Visual Studio debugger is helpful, but I can't see the whole picture, which obfuscates a possible problem here.
2) Can you help me identify why exactly one is successful and one fails? Both tokens seem to be acquired successfully, so I'm not sure what the problem is.
So I have figured out what was the underlying cause here.
In our authentication scenario, we have multiple products using azure AD SSO in the ecosystem. Since 'OnAuthorizationCodeReceived' is only called on login, and NOT when a valid login cookie is already held, the token cache will not be populated with the authorization code. So in this case, the Microsoft code samples for this scenario are dead wrong. Issuing an authentication challenge wont cause 'OnAuthorizationCodeReceived' to be called, as you already hold a valid login token.
So, while it's a litte ugly, the fix is dead simple. Force a logout, so that the token cache can be populated.
catch (AdalSilentTokenAcquisitionException e)
{
//in this case, it's possible there's no authorization code because the login cookie is from another session in
//the ecosystem. So in this scenario, force a logout so we can get a token into the tokencache
context.GetOwinContext().Authentication.SignOut(OpenIdConnectAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType);
sessionState.Abandon();
}
Now, because we're using this code outside the Controllers, and we call await, HttpContext will be null. Some serious voodoo going on in HttpContext, but I digress. We can use this little workaround to hang onto the context:
var context = HttpContext.Current;
var sessionState = context.Session;
EDIT: Came across one more problem when deploying the application to an azure app-service. You want to make sure Azure AD Authentication is toggle on in the 'Authentication' panel on Azure. We had some infinite login loop problems until I toggled this.
EDIT:
So, forcing a logout in this scenario really didn't sit well with me. BUT, I came across this question:
Azure Active Directory Graph API - access token for signed in user
And what we can do is follow the answer, and call AcquireTokenByAuthorizationCodeAsync(...), and make sure to use the 4 parameter method overload, where the last param is "https://graph.windows.net/"
Now, as long as we store the authorization code somewhere (in my case stored in a DB table). We should be able to get the authorization code for a given user, and get a new GraphAPI token, in the case where AcquireTokenSilentAsync(...) fails.
Now your statefull tokencache can be backed up by a stateless database call!
catch (AdalSilentTokenAcquisitionException e)
{
//in this case, the stateful cache is empty, so lets get the codeId from the DB
PersistentTokenCache pt = db.PersistentTokenCaches.Find(userObjectId);
if (pt != null && pt.token != null)
{
try
{
result = await ath.AcquireTokenByAuthorizationCodeAsync(pt.token,
new Uri(Startup.hostUri),
cc,
"https://graph.windows.net");
}
catch (AdalException ex)
{
Debug.WriteLine(ex.StackTrace);
//both authentication types have failed
pt.token = null;
await db.SaveChangesAsync();
context.GetOwinContext().Authentication.SignOut(OpenIdConnectAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType);
sessionState.Abandon();
return -1;
}
}
}
Is good idea to get user identity in ASP.NET Web API controller constructor, for example:
public PagesController(PageValidator pageValidator, PageMapper pageMapper, PagesManager pagesManager, UsersManager usersManager)
:base(usersManager)
{
_pageValidator = pageValidator;
_pageMapper = pageMapper;
_pagesManager = pagesManager;
if (User.Identity.IsAuthenticated)
_pagesManager.UserId = usersManager.GetByEmail(User.Identity.Name).Id;
}
Is always User.Identity was correct populated before this call raise?
This has bitten me a few times. Depending on where/how you are performing your authentication, you need to be careful where you access your identity, particularly in controller constructors.
For example, whilst the controller action is invoked AFTER an IAuthenticationFilter is instantiated, the controller's constructor is called before AuthenticateAsync; meaning any authentication you do in AuthenticateAsync will not be available in your controller's constructor (like in your example).
I typically don't rely on things being available during controller construction (unless handled by DI). Instead access the identity as you need it in your controller actions.
If you are looking at making identity lookup easier (i.e. pulling in your user object based on the User.Identity.Name property) create a base controller class that has a property or method that does it for you, then have your controllers inherit from that...
public User AuthenticatedUser
{
get
{
if (User.Identity.IsAuthenticated)
{
return usersManager.GetByEmail(User.Identity.Name);
}
return null;
}
}
EDIT
See here for a detailed breakdown of the Web.API lifecycle, showing controller creation occurring prior to authentication.
Yes. You can use this property in Controller in any place. ASP.NET has request pipeline: (http://www.dotnetcurry.com/aspnet/888/aspnet-webapi-message-lifecycle).
As you can see Authorization is early stage step in request pipeline.
Controller creation is the latest stage.
I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated
I have a basic Authentication system on my Asp.net MVC Website
[HttpPost]
public ActionResult Login(LoginViewModel model, string returnUrl)
{
WebSecurity.Login(model.UserName, model.Password, persistCookie: false)
return RedirectToAction("Index", "Home");
}
I also have a UserInfoViewModel class where i keep some user specific information, and i use it on different pages.
To avoid creating the UserInfoViewModel every time i need it, i want to save it in Session on Login method.
public ActionResult Login(LoginViewModel model, string returnUrl)
{
WebSecurity.Login(model.UserName, model.Password, persistCookie: false)
var userInfoViewModel = new UserInfoViewModel();
Session["userInfo"] = userInfoViewModel;
return RedirectToLocal(returnUrl);
}
Considering that i have sensitive information that i rely on inside UserInfoViewModel, like IsSuperuser, is it safe to keep that object in Session? Will it expire when the user login session expires as well?
SOLUTION
System.Security.Principal.IIdentity is exacly made for that. It saves inside AUTH cookie custom user information you need, so you don't recalculate it every time.
Use Custom Principal Objects video turorial
Thank you for answers!
Yes, it is safe because the Session is stored on the server. But you have another problem you should be thinking about if you decide to use ASP.NET Sessions. If this session is stored in the memory of the web server (default), IIS could recycle your application at any time and you will loose this session data. On the other hand the user will still be authenticated because he is tracked by a forms authentication cookie which will still be sent. So if you want to use Sessions I would recommend you switching to an out-of-proc session provider (such as StateServer or SQLServer).
Also as #Mikeb is pointing out in the comments section there's another very serious issue with the Session. If you enabled it for read and write mode for a given controller you will not be able to process multiple requests from the same session in parallel. The server will block and process them sequentially. Think for example multiple AJAX requests from the same session. They will all block and process sequentially.
I'm writing a silverlight application that resembles a shopping cart system.
This app can only be launched from the asp.net website after the user is logged in to the site.
Upon first load, the app will send a request to the backend through WCF service to retreive all the existing items in the shopping cart.
Therefore the silverlight app needs to know who the current user is, to find which shopping cart to load.
I found there are a couple of ways so far, but not happy with any of them:
using wcf aspnet compat. silverlight can ask who the current user is by asking the wcf service.
pass parameters from the page to xaml by using xaml.InitParameters and pass in the minimum amount of information to identify a user in a serialized format.
pass parameters through query string to xaml (apparently this is also possible)
Can anyone share the best practice to achieve this?
Thanks
We use the first solution in our projects. You haven't to invent any type of serialization format or so in this case. A disadvantage of this approach - extra async logic at startup.
The example of service:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class UserInfoService : IUserInfoService
{
public UserInfo GetUserInfo()
{
if (HttpContext.Current.User.Identity.IsAuthenticated)
return null;
var userInfo = new UserInfo
{
Login = HttpContext.Current.User.Identity.Name,
Fullname = ...,
};
return userInfo;
}
}
Sending userid via initParams or query string is not good idea I think. Such things should be more hidden.
The real important thing is to verify user on server on each service call because anyone can call your services in similar way as your app.
HTH