IdentityModel / AuthorizationServer

Sample implementation of an OAuth2 Authorization Server
Other
281 stars 136 forks source link

ClaimsAuthorizationManager ID1029 The custom type is not suitable because it does not extend the correct base class #215

Closed cotepatrice closed 10 years ago

cotepatrice commented 10 years ago

Hi ! This is not 100% related to the Authorization Server app, but rather to the samples that comes along with it. I'm trying to implement a custom AuthorizeAttribute in the "Ressource Server v2 web api" app provided in the "Flows" solution, since it is the exact same thing we want to do in our production app. So basically, here's what I did :

-Added a class ClaimsAuthorizeAttribute extending System.Web.Http.AuthorizeAttribute -Added an AuthorizationExtension that gets a reference to the registered AutorizationManager

The extension is part of a shared infrastructure project. All our other projects works the same so I reused it. Note that most of the code below comes from some Thinktecture version (at least that's why my team told me)

Here's the extrension code :

using System.Collections.ObjectModel; using System.IdentityModel.Services; using System.Linq; using System.Security; using System.Security.Claims;

namespace My.Infrastructure.Core.Security { ///

/// Provides direct access methods for evaluating authorization policy
/// </summary>

public static class AuthorizationExtension
{
    /// <summary>

    /// Default action claim type.
    /// </summary>

    private const string ActionType = "http://application/claims/authorization/action";
    /// <summary>
    /// Default resource claim type
    /// </summary>
    private const string ResourceType = "http://application/claims/authorization/resource";

    /// <summary>
    /// Gets the registered authorization manager.
    /// </summary>
    private static ClaimsAuthorizationManager AuthorizationManager
    {
        get
        {
            return FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthorizationManager;
        }
    }

    /// <summary>
    /// Create the authorization context.
    /// </summary>
    /// <param name="principal"></param>
    /// <param name="actions"></param>
    /// <param name="resource"></param>
    /// <returns></returns>
    private static AuthorizationContext CreateAuthorizationContext(ClaimsPrincipal principal, string resource, params string[] actions)
    {
        var actionsClaims = new Collection<Claim>();

        if (actions != null && actions.Any())
            actions.ToList().ForEach(ar => actionsClaims.Add(new Claim(ActionType, ar)));

        return new AuthorizationContext(principal, new Collection<Claim> { new Claim(ResourceType, resource) }, actionsClaims);
    }

    /// <summary>
    /// Checks the authorization policy.
    /// </summary>
    /// <returns>true when authorized, otherwise false</returns>
    public static bool CheckAccess(string resource, string action)
    {
        return CheckAccess(resource, new[] { action });
    }

    /// <summary>
    /// Checks the authorization policy.
    /// </summary>
    /// <returns>true when authorized, otherwise false</returns>
    public static bool CheckAccess(string resource, params  string[] action)
    {
        return ClaimsPrincipal.Current.CheckAccess(resource, action);
    }

    /// <summary>
    /// Checks the authorization policy.
    /// </summary>
    /// <returns>true when authorized, otherwise false</returns>
    public static bool CheckAccess(this ClaimsPrincipal user, string resource, string action)
    {
        return user.CheckAccess(resource, new[] { action });
    }

    /// <summary>
    /// Checks the authorization policy.
    /// </summary>
    /// <returns>true when authorized, otherwise false</returns>
    public static bool CheckAccess(this ClaimsPrincipal user, string resource, params string[] action)
    {
        try
        {
            return AuthorizationManager.CheckAccess(CreateAuthorizationContext(user, resource, action));
        }
        catch (SecurityException)
        {
            return false;
        }
    }
}

}

Now the AuthorizeAttribute code :

using System; using System.Web.Http; using GUI.Infrastructure.Core.Security; using GUI.Infrastructure.Entities;

namespace Thinktecture.Samples.Helpers { ///

/// Permet de gérer l'authorisation en attribut sur les actions des controllers.
/// </summary>

public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
    #region Membres
    private readonly string _resources;
    private readonly string[] _action;
    private const string _label = "GUI.UI.Authorization.Mvc.ClaimsAuthorizeAttribute";

    #endregion Membres

    #region Constructeurs

    public ClaimsAuthorizeAttribute()
    { }

    public ClaimsAuthorizeAttribute(string resources, params string[] action)
    {
        _action = action;
        _resources = resources;
    }

    public ClaimsAuthorizeAttribute(ContexteBorne resources, params string[] action)
    {
        _action = action;
        _resources = Enum.GetName(typeof(ContexteBorne), resources);
    }

    #endregion

    #region Méthodes publiques

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        actionContext.ActionArguments.Add(_label, actionContext);
        base.OnAuthorization(actionContext);
    }

    protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //return !string.IsNullOrWhiteSpace(_resources) ?
        //    AuthorizationExtension.CheckAccess(_resources, _action) : CheckAccess(actionContext.ActionArguments[_label] as System.Web.Http.Controllers.HttpActionContext);
        return AuthorizationExtension.CheckAccess(_resources, _action);
    }

    protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //var messages = new List<MessageInfo> { new MessageInfo { TypeMessage = TypeMessage.Erreur, Detail = Resources.Resources.NotAllowed } };
        //filterContext.Result = new JsonResult<> { Data = new { messages, data = string.Empty }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
    }

    /// <summary>
    /// Checks the authorization policy.
    /// </summary>
    /// <returns>true when authorized, otherwise false</returns>
    protected virtual bool CheckAccess(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var action = actionContext.ControllerContext.RouteData.Values["action"] as string;
        var controller = actionContext.ControllerContext.RouteData.Values["controller"] as string;

        return AuthorizationExtension.CheckAccess(controller, action);
    }

    #endregion
}

}

The problem is that I get an error saying ID1029 The custom type is not suitable because it does not extend the correct base class in the get AuthorizationManager static property. Do you have any idea what could be my mistake here ? Probably has to do with loading from configuration while it has been added by AuthConfig.Configure ?

leastprivilege commented 10 years ago

This is a known problem - use the static CustomAuthorizationManager property on ClaimsAuthorization to set your specific authorization manager instance (or move to the new OWIN based one if you are using OWIN hosting)

cotepatrice commented 10 years ago

Good ! I've moved to OWIN based solution as recommended and it works fine. Thanks for the quick response.

Vinchenzo24 commented 9 years ago

I know its been a while, but I just ran into this for a silly reason, in my web.config file I had used the wrong XML tag for the Authorisation. claimsAuthenticationManager instead of claimsAuthorizationManager.