I'm look at Web API 2 with a project that I created as a "proof of concept". I'm trying to see where I inject my own code for customer authentication. I have an internal auth/login service that I would like to call to determine if login credentials are valid and then get user values (id, roles, etc) if it was valid.
I created the project with "Individual Accounts" as the authentication type but I'm having a hard time figuring out where I'm going to call my service and then map the result to an IdentityUser (or some IUser) object.
In the generated ApplicationOAuthProvider class there is code that passes username and password from a context object like so:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (UserManager<IdentityUser> userManager = _userManagerFactory())
{
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
// ...
How do I hook into that call?
You should do this:
Create your own HTTP Message Handler to authenticate the user. You can put your custom code there. This will execute every request, then you can set the credential in the pipeline of the execution.
HTTP Message Handlers
Create or use the default filters to handle the Authorization
Authentication and Authorization in ASP.NET Web API
Related
To enable my service layer to access the current User Id anytime it needs, I use Thread.CurrentPrincipal.
The service layer is used by two front-end layers, one MVC App and one MVC Web Api used for a Mobile App.
In the web app, I use Forms Authentication and the Principal is set into Application_PostAuthenticateRequest. It works fine.
In the web Api, I use Owin. But I cannot find a way to set that Principal after each request is authenticated with the access token.
I can do it when the user logs in with its credentials by overriding GrantResourceOwnerCredentials into my OAuthAuthorizationServerProvider or when he logs with its refresh token by overriding GrantRefreshToken in the same class.
But where could I assign it for requests automatically authenticated with the access token ?
NB. I know that in my Api Controllers I can access the current User, and it is correctly set, but I don't want to pass it with each call to my service layer.
Thanks.
I found how to set it.
The bearer validation is not done by the OAuthAuthorizationServerProvider. I had to implement a custom OAuthBearerAuthenticationProvider, and override the ValidateIdentity method:
public class MyBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
public override Task ValidateIdentity(OAuthValidateIdentityContext context)
{
Thread.CurrentPrincipal = new Principal(context.Ticket.Identity);
return base.ValidateIdentity(context);
}
}
And plug that provider into my app by using:
OAuthBearerAuthenticationOptions bearerAuthenticationOptions = new OAuthBearerAuthenticationOptions()
{
Provider = new MyBearerAuthenticationProvider()
};
app.UseOAuthBearerAuthentication(bearerAuthenticationOptions);
Unfortunately Thread.CurrentPrincipal is null in my Business Layer. I assume the token validation is done in another thread than the request execution. So I'll have to change my method.
I'm developing a Spring boot application using STOMP messaging over a websocket implementing an RPC pattern which exposes public (i.e.: without any need to be authenticated) and private methods.
Two public methods exists to register and authenticate the user, so I need to manually (programmatically) handle the user login, method accessed via a custom #MessageMapping operation.
The question is: how do I authenticate the user of the websocket session?
To make a similar thing using a normal MVC web application I would use a code similar to this:
#MessageMapping("/auth")
public Object auth() {
List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_TEST");
SecurityContextHolder.getContext().setAuthentication(new PreAuthenticatedAuthenticationToken(myname, "dummy", authorities));
}
but this seems not work in a websocket environment because when the user a method like this:
#MessageMapping("/myendpoint")
public Object myEndpoint(Param params, Principal principal) {...}
I get the error:
org.springframework.messaging.simp.annotation.support.MissingSessionUserException: No "user" header in message
So the question is: how do I manually authenticate the user in the auth() method so that in myEndpoint() the Principal parameter is correctly resolved?
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
FormsAuthentication.SetAuthCookie(1.ToString(), true);
}
}
An exception of type 'System.Web.HttpException' occurred in
System.Web.dll but was not handled in user code
Additional information: Request is not available in this context
How else can I automatically login a user without having to do a whole new page request?
What part is confusing you? Forms Auth requires a request in order to work. Part of what it does is send a cookie to the client, and it can't very well do that if there's no client. Application_Start runs outside of the request, so you can't access the request object from there. Even if you could, this isn't run for each request, so it would only work for the first user that caused it to activate.
If you want to do this in a global way, but within the request scope, you'll need to use something like a custom action filter or a custom membership provider. Not sure which would be best for something like or even if an action filter would work, but that's your options.
Given that the FormsAuthentication module fires before a custom http module that handles the OnAuthenticateRequest, I'm curious if one can cancel or invalidate the forms authentication based on my own criteria.
Basically I have a process where the user logs in. After that they get a token. I get the token back after the forms authentication fires upon subsequent requests. What I want to do is then validate that the token hasn't expired against our back end server. If it's expired I need to do something so that they are forced to log back in. My thought was to do something in my OnAuthenticateRequest handler that would get picked up later in the pipeline and force a redirect back to login page or something. Is that possible?
In an ASP.NET MVC application in order to handle custom Authentication and Authorization people usually write custom Authorize attributes. They don't deal with any OnAuthenticateRequest events. That's old school. And by the way if you are going to be doing some custom token authentication why even care about Forms Authentication? Why not replace it?
So:
public class MyAuthorizeAttribute: AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
string token = GetTokenFromHttpContext(httpContext);
if (IsTokenValid(token))
{
// The user has provided a valid token => you need to set the User property
// Obviously here based on the token value you already know which is the
// associated user and potential roles, so you could do additional checks
var identity = new GenericIdentity("john.smith");
var user = new GenericPrincipal(identity, new string[0]);
httpContext.User = user;
return true;
}
// Notice that here we are never calling the base AuthorizeCore method
// but you could call it if needed
return false;
}
private string GetTokenFromHttpContext(HttpContextBase httpContext)
{
// TODO: you know what to do here: get the token from the current HTTP Context
// depending on how the client passed it in: HTTP request header, query string parameter, cookie, ...
throw new NotImplementedException();
}
private bool IsTokenValid(string token)
{
// TODO: You know what to do here: go validate the token
throw new NotImplementedException();
}
}
Now all that's left is to decorate your controllers/actions with this custom attribute instead of using the default one:
[MyAuthorize]
public ActionResult SomeAction()
{
// if you get that far you could use the this.User property
// to access the currently authenticated user
...
}
Is that possible?
This is definitely possible. You could even set your autehtication scheme to None so that forms module isn't there in the pipeline and have only your own module.
However, even if forms is there, your custom module can override the identity set for the current request. Note also that until the forms cookie is issued, forms module doesn't set the identity. This was quite common to use both forms module and the SessionAuthenticationModule - forms does the job of redirecting to the login page and the session auth module handles its own authentication cookie.
This means that you can safely mix the two: the forms module and your own custom module for a similar scenario.
Darin suggests another approach and this of course is valid too. An advantage of an authentication module (versus the authentication filter) is that the authentication module could support other ASP.NET subsystems (web forms / wcf / webapi).
Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.