In the documentation for ServiceStack, it says that the best practice is:
Normally ServiceStack calls the method bool HasPermission(string
permission) in IAuthSession. This method checks if the list
List Permissions in IAuthSession contains the required
permission.
IAuthSession is stored in a cache client as explained above You can
fill this list in the method OnAuthenticated you've overriden in the
first part of this tutorial.
I am integrating with an existing system, and have my custom BasicAuthProvider working (inherited from the base BasicAuthProvider). Authentication is working perfectly, now I am building out the Authorization portion. I plan on using the Permissions list as listed above, but I need access to the Route information to determine if a user has access to a particular resource. I see in the IAuthServiceBase there is an IRequestContext which has the absolute URL, but before going through and parsing that out, I figured there has to be a way to gain access to the ServiceStack Route structure to give me either the class name of the Service being requested, or the DTO the requested service is related to.
Here is the OnAuthenticated method from my BasicAuthProvider class:
public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
UserSession sess = (UserSession)session;
Model.User currentUser = UserRepository.GetUserByUsername(session.UserAuthName);
//Fill the IAuthSession with data which you want to retrieve in the app eg:
session.FirstName = currentUser.Person.FirstName;
session.LastName = currentUser.Person.LastName;
session.UserName = currentUser.User1;
sess.CurrentUser = currentUser;
//Important: You need to save the session!
authService.SaveSession(session, TimeSpan.FromDays(1));
}
Under MVC I have used some of the Raw Request Data to get the Controller and Action name before, to determine resource authorization, but this is the first project I am using ServiceStack with.
You may find the [RequiredPermission] attribute or even the implementation of it will help you, e.g. the 3rd parameter passed in a RequestFilter is the Request DTO.
And since a Request DTO maps 1:1 with the service, you can be sure that the request is destined for the IService<TRequest> (or its subclasses e.g. ServiceBase<T>, RestServiceBase<T>).
You can access the type of the service programatically as done in the FilterAttributeCache:
var serviceType = EndpointHost.Metadata.GetServiceTypeByRequest(requestDtoType);
I'm not sure of the exact context/use-case you're trying to support but using the [RequiredPermission] or [RequiredRole] attributes may have what you need which by default validates against the list of roles and permissions available in the built-in UserAuth table.
Externally you can use the /assignroles and /unassignroles web services (as part of the AuthorizationFeature plugin) to assign roles and permissions to users (it requires a user with the Admin role by default).
For more info see the documentation pages on Authentication/Authorization and Validation on the ServiceStack GitHub project wiki.
Related
I have to implement authorization for my web api using another/external API. So I have to get the JWT from the request and call another API with that token to know whether the user is authorized.
presently my authentication is working, and I am using
IServiceCollection.AddAuthentication().AddJwtBearer() // removed code to set options
in sample above, I have removed code to provide options and setting the TokenValidationParameters. So my auth logic is working as expected.
Now i am looking to implement custom Authorization. In my custom authorization logic i have to make call to another/external API and pass some parameters. The parameters will be different for different action methods in my controller. The external API will return bool (indicating whether authorized or not), I don't have need to maintain any application role/claims in my code.
is using dynamic policy name and string parsing as mentioned in doc the only/recommended option.
So i have to get jwttoken from request and call another API with that token to know if user is authorized or not.
You should try to prevent having to make an an outbound API request for each request your API gets.
It seems like you have an external authentication service which lets your users log in and returns a token of sorts. You need to know how that third party signs their tokens, then obtain some form of (public) key from them.
With this key you can validate whether the token has been signed by the party you trust. For this, you configure the appropriate TokenValidationParameters which you pass to your services.AddAuthentication().AddJwtBearer() so you can let Identity validate their token using their keys.
See:
Authorize with a specific scheme in ASP.NET Core
Microsoft.AspNetCore.Authentication.JwtBearer Namespace
Ultimately you'd also configure some sort of background job that cycles the keys of the external provider when they do, if they do, which they hopefully do.
As for your updated question: you appear to want to use an external service for authorization, i.e. who can do what.
You'll have to implement this yourself. Usually this is done using scopes, which are retrieved once, during authentication. These can contain values like "finance" to give access to financial controllers, or "finance:orders:list finance:products".
[RequiredScope("finance:orders", "finance:orders:list")]
public IActionResult Index()
{
return View();
}
If the API you're talking to does not have a way to retrieve the relevant scopes, claims or permissions during authentication (or once per resource), then you can't, for example, cache the user's roles to your controllers or entities.
You need to realise this will incur extra overhead per API call, as well as your application being down when the authentication/authorization service is down.
If you still want to do this, the most trivial way to do async authorization on a controller would be a policy:
public class AuthorizeWithAuthServiceRequirement : IAuthorizationRequirement
{
public const string PolicyName = "external-authorization-service";
}
public class AuthorizeWithAuthServiceHandler : AuthorizationHandler<AuthorizeWithAuthServiceRequirement>
{
private IYourApiService _yourApiService;
public AuthorizeWithAuthServiceHandler(IYourApiService yourApiService/* your DI here */)
{
_yourApiService = yourApiService;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizeWithAuthServiceRequirement requirement)
{
var httpContext = context.Resource as HttpContext
?? throw new ArgumentException("Can't obtain HttpContext");
// Get the user or their claims or the ID from the route or something
var user = httpContext.User;
var claim = user.FindAll("foo-claim");
var allClaims = user.Claims;
var id = httpContext.Request.RouteValues["id"];
// TODO: response and error handling
var isUserAuthorized = _yourApiService.IsUserAuthorized(user, id, entity, claim, ...);
if (!isUserAuthorized)
{
context.Fail(/* TODO: reason */);
}
}
}
You register this with DI like this:
// Register the handler for dependency injection
services.AddSingleton<IAuthorizationHandler, AuthorizeWithAuthServiceHandler>();
// Register the policy
services.AddAuthorization(options =>
{
options.AddPolicy(AuthorizeWithAuthServiceRequirement.PolicyName, x => { x.AddRequirements(new AuthorizeWithAuthServiceRequirement()); });
});
And then apply it to a controller or action method:
[Authorize(Policy = AuthorizeWithAuthServiceRequirement.PolicyName)]
public class FooController : Controller
{
}
If you want more fine-grained control like custom attributes with parameters (like [CustomAuthorization(ApiPermission.Foo)]) per controller or action, or if you want to first load an entity and pass that to the handler, see Ilja in Asp.Net Core: Access custom AuthorizeAttribute property in AuthorizeHandler and their GitHub repository demonstrating three different approaches.
I am trying to implement authentication for my web api.
I have read about different techniques of api authentication and the token technique is the most reasonable for me.
I read different articles about how to implement token based authentication in asp.net but they all rely on different libraries such as OAuth or Owin which also provide their own method of database interactions.
The thing is that I have already implemented database interaction with abstract repositories and entities and I would like to find out how can I implement api authentication easily and simply without interfering with my current design.
(By the way, my project is built on top of an empty web api project, so it doesn't come with all the bootstrap and authentication classes).
Thank you
One solution I've seen is to use .NET's HttpApplicationState class and store tokens in appstate; this way you're not directly messing with Session (which would be a REST antipattern), but you can still track all currently logged in users and use HttpContext/HttpActionContext to x-ref active tokens in the app. The benefit to using HttpActionContext is that it is thread-safe, whereas HttpContext is not, so you can lock the appstate, mess with the HttpContext of an individual request, and then unlock the appstate to allow other threads in.
Since locking/unlocking appstate does tie up the app, I'm not sure how well this solution scales, but here it is anyway . . .
General outline:
When a user first logs in, a token is generated for him/her and stored in appstate. Then you can tag any API calls that require authentication (or that need other information stored on that user) with a custom attribute that checks for that token in the appstate, sending the token name as a header in the API call (e.g. "{token-name: TOKEN}").
Here's a brief example:
[in Controller method first activated at login:]
CustomUserObject user = new CustomUserObject();
//store user props
string token = Guid.NewGuid().ToString();
//create AppState instance, mine's called _appState
//...
_appState.Lock();
_appState[token] = user;
_appState.UnLock();
//...
[Then in global.asax:]
public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
HttpRequestMessage request = actionContext.ControllerContext.Request;
string token = string.Empty;
if (request.Headers.GetValues("token-name") != null)
{
token = request.Headers.GetValues("token-name").FirstOrDefault().ToString();
IAppStateService appService; //<--- I've created a custom service tier class for appstate stuff
//Get appState instance, however makes sense for you.
//I'm using repo pattern with UnitOfWork, so mine looks like this...
//"IContainer ioc = DependencyResolution.IoC.Initialize();"
//"IAppStateService appService = ioc.GetInstance<IAppStateService>();"
appService.SetHttpApplicationState(HttpContext.Current.Application);
bool isAuthorized = appService.CheckTokenAndDoStuff(token);
//inside that method ^^^ you'll do stuff like
//"_appState.Lock();"
//"if (_appState[token] == null) return false" (or whatever)
//"_appState.Unlock();"
}
if (isAuthorized)
{
HttpResponseMessage resp = request.CreateResponse(HttpStatusCode.OK);
resp.Headers.Add("AuthenticationToken", token);
resp.Headers.Add("WWW-Authenticate", "Basic");
resp.Headers.Add("AuthenticationStatus", "Authorized");
}
return isAuthorized;
}
[then in webapi]
[HttpPost]
[CustomAuthorize]
public HttpResponseMessage NameOfMethod(...)...
...and that should x-check your appstate for your user token for you. Just make sure to include your token in your request header, and make sure to include the Basic Auth info in your response header.
I'm working on a project where users can log in and create as many number of "work projects" as they like, which are tied to their account Id. We're using OWIN and ASP.NET Identity 2.1.
All the MVC controller actions that respond to HTTP POST requests require the WorkProjectId to be passed in as a HTTP header. The logged in user should only ever be able to interact with WorkProjects that are associated with their login. This presents an important security consideration: is it best practice to interrogate what WorkProjectId are associated with the currently logged in user at the time the controller action is invoked, perhaps by using a custom attribute?
E.g.
[EnsureUserIsAllowedToDoAnythingToThisWPID]
public async Task UpdateWorkProjectTitle(ViewModel vm) {
...
}
Because the user can create as many WorkProjects as they see fit, I don't think I can do this with Claims based security. As far as I understand, if WorkProjectIds were somehow stored as Claims, if they were modified it would necessitate logging the user in and out whenever that happened ... which is obviously not acceptable.
So, to achieve what I need, is it "wrong" to store the Ids the logged in user has access to in session state? I've been burned very badly in the past on other projects with session state abuse (read: far too much data being serialised into session state) bringing the web servers to their knees due. I'd prefer to avoid it if there are equally simple approaches.
Thanks
Why not just add/remove claims for current user? On controller side via UserManager.AddClaim by pasting in logged-in-user id and desired Claim object (i.e. id of workProject?). As far as I know, storing user data (i.e. allowed WorkProjectIds) in cookies is preferable. And your custom authorize attribute will check if requested WorkProject is allowed for current user:
[AttributeUsageAttribute(AttributeTargets.Class | AttributeTargets.Method,
Inherited = true, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
private string _url; // path to action, also you can get it from request
private Operations _operation; // user requested action (CRUD? or administer, execute, etc.)
// example of usage as attribute [CustomAuthAttrib("some string", Operations.Create)]
public CustomAuthorizeAttribute(string url, Operations operation)
{
_url = url;
_operation = operation;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// any httpContext.Request... operations
return base.AuthorizeCore(httpContext);
}
}
Here is my some raw listing, currently I'm facing somewhat similar problem. And, to access claims here probably you will need some extension methods that came within OWIN/Katana and/or ASP.NET Identity framework
I am logging into my service from a c# client like so:
serviceClient.Send<ServiceStack.ServiceInterface.Auth.AuthResponse>(
new ServiceStack.ServiceInterface.Auth.Auth() {
UserName = "xxx",
Password = "yyy" }
);
I would now like to use one of the unused strings in the Auth class to pass some additional information (like a programid). I am using my own subclassed CredentialsAuthProvider. Two questions:
Do you recommend any of the "extra" properties in the Auth class to stuff my programid over any others? I was considering using "State", will that mess anything up if I put a string in there?
Is there a way from within the TryAuthenticate override of my CredentialsAuthProvider to access the Auth class instance that was sent to me (so I can access the programid that I stuck into the State property).
Thank you.
Answered half of my question.
Not sure if any of the properties are better than any other, but I'm using "State" to stuff some extra data. Now that multiple end user programs are accessing the same service, sending a program ID in the State property lets me log the programs attempting to log into the service, along with the users.
If you are authenticating by overriding CredentialsAuthProvider, you can override the Authenticate method to gain access to the Authenticate object that is passed in from the user. From there, you can read the State property (or any other).
I have been working on a web site (using ASP.NET C#) that uses both forms based and claims based authentication. I wanted to override the ClaimsIdentity class so I could implement a custom IsAuthenticated method and add more properties for the identity specific for the claims authentication.
I'm implementing a custom WSFederationAuthentionModule currently, but I was trying to figure out what module I should override (specifically what method) so I can set my custom identity/principal rather than the default ClaimsPrincipal?
So far I have looked at both the SessionAuthenticationModule and ClaimsPrincipalHTTPModule, but I could not figure out at what step the principal is set/the best way to override it.
Thanks
Addition:
Since I'm kind of new at this let me be sure this is correct: The way to set an identity is to set a custom principal which is set to use that identity:
System.Threading.Thread.CurrentPrincipal = customClaimsPrincipal;
Alternatively if a custom principal was not needed then the ClaimPrincipal class could be constructed with a ClaimsIdentityCollection.
There are several places you can do this, but if you are using the SessionAuthenticationModule, some of the process is not documented well which can make using a custom principal tricky. The rest of this answer explains one possible way to handle this when using the SessionAuthenticationModule.
Override the SessionAuthenticationModule.SetPrincipalFromSessionToken method.
The SessionAuthenticationModule stores the security token, principal, identities, and claims in a cookie and an in-memory cache to avoid having to make round-trips to the identity provider/token service on every request. What's not documented well is the existence of the cache and that it is the first place checked, then the cookie, and the limits on serializing the ClaimsPrincipal.
If you already set a custom principal in ClaimsAuthenticationManager.Authenticate and the cache is intact, your custom principal will most likely be there already since the cache stores native .NET objects. If you haven't yet set a custom principal, or the cache is not populated, then the security token will be retrieved from the FedAuth session cookie.
When the token is serialized/deserialized to/from the cookie, the process uses custom serialization that is only capable of reading and writing attributes of the IClaimsPrincipal and IClaimsIdentity interfaces (or the ClaimsPrinicpal and ClaimsIdentity classes - I can't remember which). Any custom principal and identity object attributes will not be included. It may be possible to override the serialization, but that requires several (3 IIRC) more layers of class overrides.
You'll also need to be aware of the fact that the base SetPrincipalFromSessionToken method creates a new ClaimsPrincipal object and sets it on the thread and context, so even if the sessionSecurityToken parameter contains a custom principal object, it will get translated back into a ClaimsPrincipal object.
Here's an example override method:
protected override void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
SessionSecurityToken newToken = MyClaimsPrincipalUtility.CreateCustomClaimsPrincipalToken(sessionSecurityToken);
base.SetPrincipalFromSessionToken(newToken);
//the following lines need to be set after the base method call, because the base method overwrites the Principal object
HttpContext.Current.User = newToken.ClaimsPrincipal;
Thread.CurrentPrincipal = newToken.ClaimsPrincipal;
}
The base class (SessionAuthenticationModule) implementation looks like the following. So there are a couple different ways you can achieve the overriding and getting the custom claims principal.
protected virtual void SetPrincipalFromSessionToken(SessionSecurityToken sessionSecurityToken)
{
IClaimsPrincipal fromIdentities = ClaimsPrincipal.CreateFromIdentities(this.ValidateSessionToken(sessionSecurityToken));
HttpContext.Current.User = (IPrincipal) fromIdentities;
Thread.CurrentPrincipal = (IPrincipal) fromIdentities;
//tracing code removed
this.ContextSessionSecurityToken = sessionSecurityToken;
}
And just in case you're wondering, here's the base class implementation for SessionAuthenticationModule.ContextSessionSecurityToken.
public virtual SessionSecurityToken ContextSessionSecurityToken
{
get
{
return (SessionSecurityToken) HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName];
}
internal set
{
HttpContext.Current.Items[(object) typeof (SessionSecurityToken).AssemblyQualifiedName] = (object) value;
}
}
You're correct in that HttpModules are the way to go in terms of extensibility, but make sure that whatever logic you implement doesn't inhibit the performance of your application. I've had websites go thoroughly berserk performance-wise after adding too many HttpModules to the application. It might be worth caching results of your queries, depending on what auth model you're using.
You need to figure out under what conditions you need to use your custom ClaimsPrincipal. Until you do this you're stabbing in the dark. Are there specific URLs for which you need claims authentication?