I am trying to implement CustomAuthorization via IsAuthorized method of AuthorizeAttribute.
Assumption here is by this time user would have been Authenticated and i can retriev userName and other Claims that were assigned to user during authentication. I am using Bearer Authentication.
But when i check for actionContext.RequestContext.Principal.Identity.IsAuthenticated it is always returning false.
How do i access who the user is and any claims that were assigned to him during authentication in this method?
Here is the code that i am referring to, this is not the full blown implementation, incomingPrincipal.Identity.IsAuthenticated is always false.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
IPrincipal incomingPrincipal = actionContext.RequestContext.Principal;
if (!incomingPrincipal.Identity.IsAuthenticated)
return false;
else
{
return true;
}
Debug.WriteLine(string.Format("Principal is authenticated at the start of IsAuthorized in CustomAuthorizationFilterAttribute: {0}", incomingPrincipal.Identity.IsAuthenticated));
}
}
Did you write your own AuthenticationFilter? You have to set the "Principal" to the Http-Context. Otherwise you can't access the information. Could you post your code?
Have a look here.
Authentication Filters in ASP.NET Web API 2
Related
I want to authorize users before accessing any data using my core api, so I tried is using JWT authentication.
I have successfully generated token while signing in user using api and saved that token on client side in session, now whenever user wants to access any data using api, I'll send that token in header to api and I want to validate that JWT token using custom authorization filter. I have created custom authorization filter and applied it on my GetMenu api and I'm able to validate that token successfully but after token validation in authorization filter it is not hitting it on my GetMenu api.
Here is my AccountController code:
[Filters.Authorization]
[AllowAnonymous]
[HttpPost]
[Route("GetMenu")]
public IActionResult GetMenu(string clientid, int rolecode, string repcode)
{
//further process
}
Here is my Filters.Authorization code:
public class Authorization: AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (!ValidateToken(filterContext.HttpContext.Request.Headers["token"]))
{
filterContext.Result = new UnauthorizedResult();
}
}
}
I have breakpoints on OnAuthorization method and on GetMenu api.
I'm calling my GetMenu api through postman to test, it is successfully hitting it on OnAuthorization method in Filters.Authorization and validating my JWT Token and displays Status Code: 200 in postman but after successful token validation it should hit on GetMenu api for further data processing but it is not hitting.
What can be the issue? what am i missing? please help.
You should not set the filterContext.Result if the request is successfully authorize.
//
// Summary:
// A context for authorization filters i.e. Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter
// and Microsoft.AspNetCore.Mvc.Filters.IAsyncAuthorizationFilter implementations.
public class AuthorizationFilterContext : FilterContext
{
//
// Summary:
// Gets or sets the result of the request. Setting Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext.Result
// to a non-null value inside an authorization filter will short-circuit the remainder
// of the filter pipeline.
public virtual IActionResult Result { get; set; }
}
You only need to set Result when it's failed.
public class Authorization: AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext filterContext)
{
if (!ValidateToken(filterContext.HttpContext.Request.Headers["token"]))
{
filterContext.Result = new UnauthorizedResult();
}
}
}
I am working on an MVC site that has some pages that need authentication and others that don't. This is determined using the Authorize and AllowAnonymous attributes in a pretty standard way. If they try to access something restricted they get redirected to the login page.
I'm now wanting to add the functionality to automatically log them in using an encrypted token passed in the querystring (the link will be in emails sent out). So the workflow I want now is that if a request goes to a page that is restricted and there is a login token in the querystring I want it to use that token to log in. If it logs in successfully then I want it to run the original page requested with the new logged in context. If it fails to log in then it will redirect to a custom error page.
My question is where would I need to insert this logic into the site?
I have seen some suggestions on subclassing the Authorize attribute and overriding some of the methods but I'm not 100% sure how to go about this (eg what I would override and what I'd do in those overridden methods.
I've also had a look at putting the logic at a controller level but I am led to understand that the authorize attribute would redirect it away from the controller before any code in the controller itself was run.
It would be better to write a custom authorization attribute that will entirely replace the default functionality and check for the query string parameter and if present, decrypt it and authenticate the user. If you are using FormsAuthentication that would be to call the FormsAuthentication.SetAuthCookie method. Something along the lines of:
public class TokenAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string token = filterContext.HttpContext.Request["token"];
IPrincipal user = this.GetUserFromToken(token);
if (user == null)
{
this.HandleUnAuthorizedRequest(filterContext);
}
else
{
FormsAuthentication.SetAuthCookie(user.Identity.Name, false);
filterContext.HttpContext.User = user;
}
}
private IPrincipal GetUserFromToken(string token)
{
// Here you could put your custom logic to decrypt the token and
// extract the associated user from it
throw new NotImplementedException();
}
private void HandleUnAuthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/CustomError.cshtml",
};
}
}
and then you could decorate your action with this attribute:
[TokenAuthorize]
public ActionResult ProcessEmail(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
Here is my code:
[HttpGet, Authorize(Roles = "Admin")]
public ActionResult ActivityLog()
{
'code to do stuff
return View(model);
}
It's pretty simple - if you are in the "Admin" role you can get into this action. However I have a custom ActionFilter that populates my IPrinciple with all the custom claims (I cant use ADFS to send the claims because I have ONE ADFS for multiple sites so my claims have to be for that specific site).
public class CustomFilter: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
'go get custom claims
}
}
}
I tie the custom filter into the application from the Global.asax file
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomFilter());
}
The problem is since the Authorize attribute runs before my custom filter I don't have the
"Admin" role and i get a 401 - Unauthorized Access error. How do I still keep the filter AND use the "Roles" tag in the Authorize attribute?
In regards to
"The problem is since the Authorize attribute runs before my custom
filter I don't have the "Admin" role"
You can create a another Authorize attribute which access the claims first, and then your standard Authorization which sets up the Admin.
The way you do this is to register and specify the Order property
filters.Add(new AuthorizeAttribute(), 1);
filters.Add(new CustomAuthorizeAttribute(), 2);
See more information on Filter Ordering
AuthorizeAttribute is no longer supported in MVC 4. You should now use the new AllowAnonymous attribute.
http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx
ASP.NET MVC 4 includes the new AllowAnonymous attribute, you no longer need to write that code. Setting the AuthorizeAttribute globally in global.asax and then whitelisting (That is, explicitly decorating the method with the AllowAnonymous attribute) the methods you want to opt out of authorization is considered a best practice in securing your action methods.
If you attempt to use an action filter and override AuthorizeCore, you'll get a compile time error "There is no suitable method for override".
Here is another method of performing attribute authorization in MVC 4:
public class AuthAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
HandleUnauthorizedRequest(actionContext);
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var response = actionContext.Request.CreateResponse(System.Net.HttpStatusCode.Redirect);
response.Headers.Add("Location", "http://www.google.com");
actionContext.Response = response;
}
}
I have a custom username/password validation in a WCF service. I followed the steps on this site to create this authentication.
I want to develop some kind of authorization based on the already validated credentials but don't know where to find this kind of information. I googled a lot and found lots of ways to regulate authorization but can't find a way to base this authorization on the custom username validation.
I am new to wcf and overwhelmed by all it's different kinds of methods.
Can someone provide me with some links where i can find information about this specific subject?
I have found this article to be a great summary of all the things WCF has to offer to support authorization. The article starts with the simplest implementation and then discusses each incremental step in complexity all the way to full blown claims based authorization.
Based on the information you provided regarding your specific situation, I would recommend that you create a custom implementation of IPrincipal, as illustrated in Figure 3 of the article I linked. I have included the code sample from the article here as well.
class CustomPrincipal : IPrincipal
{
IIdentity _identity;
string[] _roles;
Cache _cache = HttpRuntime.Cache;
public CustomPrincipal(IIdentity identity)
{
_identity = identity;
}
// helper method for easy access (without casting)
public static CustomPrincipal Current
{
get
{
return Thread.CurrentPrincipal as CustomPrincipal;
}
}
public IIdentity Identity
{
get { return _identity; }
}
// return all roles (custom property)
public string[] Roles
{
get
{
EnsureRoles();
return _roles;
}
}
// IPrincipal role check
public bool IsInRole(string role)
{
EnsureRoles();
return _roles.Contains(role);
}
// cache roles for subsequent requests
protected virtual void EnsureRoles()
{
// caching logic omitted – see the sample download
}
}
In the custom username and password validator referenced in your original post, you would simply populate an instance of the new IPrincipal and attach it to the static value Thread.CurrentPrincipal. This will allow you to then simply decorate any methods you wish to control access to by using the PrincipalPermission attribute as illustrated below. This code sample is also Figure 1 from the article I linked.
class Service : IService {
// only 'users' role member can call this method
[PrincipalPermission(SecurityAction.Demand, Role = 'users')]
public string[] GetRoles(string username) {
// only administrators can retrieve the role information for other users
if (ServiceSecurityContext.Current.PrimaryIdentity.Name != username) {
if (Thread.CurrentPrincipal.IsInRole('administrators')) {
...
}
else {
// access denied
throw new SecurityException();
}
}
}
}
So I set this above my Controller:
[Authorize(Roles="Administrator")]
The problem is whether they are not logged in, or don't have the right role, it redirects them to the login page. Is there a way to have it handle authorization and authenticate differently?
I might not understand you clearly, but authentication and authorization are always coming together.. One says which mechanism use to authenticate user (forms, windows etc.), and second which roles or users are allowed to see the content...
As far as authentication method is set in your web config it is fixed, and only think you can use to protect your controller methods is to put those attributes.
Also if you want to use it diffrently, f.e. redirect to diffrent page you can use following code:
public class RedirectAuthorizeAttribute : AuthorizeAttribute
{
public string RedirectUrl { get; set; }
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new RedirectResult(RedirectUrl);
}
}
and then put it onto your controller method like that:
[RedirectAuthorize(Roles = "MyRole", RedirectUrl = "SomeUrl")]
public ActionResult SomeAction()
{
...
}