How to test Filters that verify Claim data?

6

I have a ActionFilter for some controllers and actions that make use of the user information that is in claims .

The filter itself gets the user's claims information and performs the authorization validation process:

public void OnAuthorization(AuthorizationContext filterContext)
{
    if (Perfil >= Perfil.Administrativo)
        return;

    var cookie = new CookieInfo(HttpContext.Current.User.Identity as ClaimsIdentity);

    if (Perfil == Perfil.Usuario)
    {
        filterContext.Result = new RedirectResult("/Home/Index");
        filterContext.Controller.TempData["ErrorMessage"] = "Acesso inválido!";
        return;
    }

    if (Perfil <= Perfil.Suporte)
    {
        filterContext.Result = new RedirectResult("/Home/Index");
        filterContext.Controller.TempData["ErrorMessage"] = "Acesso inválido!";
    }
    ...
}

How do I write / create test methods to test filter functionality?

    
asked by anonymous 23.11.2015 / 12:59

3 answers

3

Write a method that instantiates the execution (which in turn instantiates the authorization attribute, which is a filter) and make a mock of the request, something like this:

public void TesteDoFiltroDeAutorizacao()
{
    var context = new ActionExecutedContext();
    var httpRequest = new HttpRequest("", "http://umenderecoqualquer/", "");
    var stringWriter = new StringWriter();
    var httpResponse = new HttpResponse(stringWriter);
    context.HttpContext = new ControllerContext(new HttpContextBase { Request = httpRequest, Response = httpResponse }, 
              new RouteData(), 
              new QualquerController());
    var filter = new MinhaAutorizacaoAttribute(/* Aqui acho que você passa um perfil, pelo que eu entendi */);

    filter.OnActionExecuted(context);

    Assert.True(/* Teste aqui context.Result */);
}
    
23.11.2015 / 14:10
1

How I solved:

protected static ActionExecutedContext FakeExecutedContext(IPrincipal principal = null, 
    Controller controller = null)
{
    var request = new Mock<HttpRequestBase>();
    request.SetupGet(x => x.HttpMethod).Returns("GET");
    request.SetupGet(x => x.Url).Returns(new Uri("http://example.com/action"));

    var httpContext = new Mock<HttpContextBase>();
    httpContext.SetupGet(x => x.Request).Returns(request.Object);

    // aqui adiciono o principal quando passado por parâmetro
    if (principal != null)
        httpContext.SetupGet(x => x.User).Returns(principal);

    var executedContext = new Mock<ActionExecutedContext>();
    executedContext.SetupGet(x => x.HttpContext).Returns(httpContext.Object);
    if (controller != null)
        executedContext.SetupGet(x => x.Controller).Returns(controller);

    return executedContext.Object;
}

Simplifying the test method for this:

[TestMethod]
public void TentativaDeAcessoComPerfilInferiorAoSolicitadoPeloFiltro()
{
    // variáveis
    // Uma claim será setada com nível de acesso de Suporte
    var identity = new ClaimsIdentity(new List<Claim>
    {
        new Claim(CustomClaimTypes.Perfil, Perfil.Suporte.ToString())
    });

    var principal = new GenericPrincipal(identity, new[] { "" });

    // A simulação requer um nível de acesso Administrativo
    var filter = new PerfilFilterAttribute(Perfil.Administrativo, Context);
    var fakeExecutedContext = FakeExecutedContext(principal, new HomeController());

    // execução
    filter.OnActionExecuted(fakeExecutedContext);

    // validação
    // O resultado deve apontar um redirecionamento para o /Home/Index
    Assert.IsNotNull(fakeExecutedContext.Controller.TempData["ErrorMessage"]);
    Assert.IsNotNull(fakeExecutedContext.Result as RedirectResult);
    Assert.AreEqual(((RedirectResult)fakeExecutedContext.Result).Url, "/Home/Index");
}

There is a detail in the filter that has been changed from:

var cookie = new CookieInfo(HttpContext.Current.User.Identity as ClaimsIdentity);

To:

var cookie = new CookieInfo(filterContext.HttpContext.User.Identity as ClaimsIdentity);
    
23.11.2015 / 19:21
0

You can make a foreach on your Saved Claims as follows:

IEnumerable<System.Security.Claims.Claim> Claims = HttpContext.GetOwinContext().Authentication.User.Claims;
foreach (var t in Claims)
{
    if(t.Type.Equals("http://schemas.microsoft.com/ws/2008/06/identity/claims/primarysid"))
        idUsuario = t.Value;
}
    
23.11.2015 / 14:24