Integration Test Web Api con

Así que he encontrado fragmentos y piezas que me han iluminado un poco en la etiqueta [Autorizar], pero nada que resuelva mi problema.

Mi escenario es que tengo métodos Web Api que quiero alcanzar con las pruebas de integración utilizando RestSharp. Sin embargo, RestSharp está recibiendo mi página de inicio de sesión, en lugar de los resultados de la llamada.

[Authorize] public Item GetItem([FromBody] int id) { return service.GetItem(id); } 

El producto utiliza un sistema de inicio de sesión personalizado, y lo que REALMENTE me gustaría sería una forma de deshabilitar la credencial [Autorizar] solo para las pruebas de integración. Sin embargo, leí que puede permitir a los usuarios anónimos y que “deshabilitaría” la credencial, por lo que en la solución, tengo un proyecto de pruebas de integración, y en ese proyecto tengo un archivo App.config. En ese archivo pongo:

         

Pero esto tampoco parece estar funcionando. Cualquier explicación sobre qué está sucediendo, por qué no funciona y qué se puede hacer para que esto funcione sería muy apreciada.

He intentado establecer un Thread.CurrentPrincipal pero no funcionó (tal vez lo hice mal, ¿puedes configurar “algo” para que se autorice en el código?). La autenticación se maneja en un httpmodule si eso ayuda.

Aquí es cómo debe establecer el Thread.CurrentPrincipal . Agregue un controlador de mensajes como este a su proyecto de API Web y agregue el controlador en el método de Register de WebApiConfig.cs así: config.MessageHandlers.Add(new MyTestHandler()); .

 public class MyTestHandler : DelegatingHandler { protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { var local = request.Properties["MS_IsLocal"] as Lazy; bool isLocal = local != null && local.Value; if (isLocal) { if (request.Headers.GetValues("X-Testing").First().Equals("true")) { var dummyPrincipal = new GenericPrincipal( new GenericIdentity("dummy", "dummy"), new[] { "myrole1" }); Thread.CurrentPrincipal = dummyPrincipal; if (HttpContext.Current != null) HttpContext.Current.User = dummyPrincipal; } } return await base.SendAsync(request, cancellationToken); } } 

Este controlador establece un principal autenticado para que todos sus [Authorize] contentos. Hay un elemento de riesgo con este enfoque. Solo para las pruebas, debe conectar este controlador en la canalización de la API web. Si conecta este controlador a la tubería (intencional o no) en su código de producción, básicamente anula su mecanismo de autenticación. Para mitigar el riesgo en cierta medida (con la esperanza de que no se acceda a la API), verifico que el acceso sea local y que haya un encabezado X-Testing con un valor true .

Desde RestSharp, agregue el encabezado personalizado.

 var request = new RestRequest(...); request.AddHeader("X-Testing", "true"); 

Por cierto, para las pruebas de integración, preferiría usar hosting en memoria, en lugar de alojamiento web. De esa manera, la API web se ejecuta en el mismo proyecto de prueba y puede hacer lo que quiera con él, sin el temor de romper algo en producción. Para obtener más información sobre el alojamiento en memoria, vea esto y esto .

Me doy cuenta de que esta pregunta es sobre el envío de solicitudes “reales” de RestSharp a los puntos finales de webapi, por lo que esta sugerencia no se aplica inmediatamente al escenario de OPs. PERO:

Estoy usando pruebas Web Api en memoria usando HttpConfiguration , HttpServer y HttpMessageInvoker (muy parecido a la sugerencia de Badri, creo). De esta manera, no necesito oyentes o puertos abiertos, ya que puedo probar la stack completa (prueba de extremo a extremo) en la memoria; realmente útil en un servidor de comstackción, instancia de Heroku, etc.

Usando pruebas en memoria, aquí es cómo puede configurar Thread.CurrentPrincipal … Tengo un ayudante en mi clase base de prueba como esta:

 protected void AuthentateRequest() { Thread.CurrentPrincipal = new AuthenticatedPrincipal(Thread.CurrentPrincipal); } 

Que utiliza esto:

 public class AuthenticatedPrincipal : IPrincipal { private readonly IPrincipal _principalToWrap; private readonly IIdentity _identityToWrap; public AuthenticatedPrincipal(IPrincipal principalToWrap) { _principalToWrap = principalToWrap; _identityToWrap = new AuthenticatedIdentity(principalToWrap.Identity); } public bool IsInRole(string role) { return _principalToWrap.IsInRole(role); } public IIdentity Identity { get { return _identityToWrap; } private set { throw new NotSupportedException(); } } } public class AuthenticatedIdentity : IIdentity { private readonly IIdentity _identityToWrap; public AuthenticatedIdentity(IIdentity identityToWrap) { _identityToWrap = identityToWrap; } public string Name { get { return _identityToWrap.Name; } private set { throw new NotSupportedException(); } } public string AuthenticationType { get { return _identityToWrap.AuthenticationType; } private set { throw new NotSupportedException(); } } public bool IsAuthenticated { get { return true; } private set { throw new NotSupportedException(); } } } 

Puede parecer excesivo IPrincipal el IPrincipal manualmente, pero lo intenté con mi marco de burla y exploté en algunos de mis corredores de prueba (Resharper y TeamCity, pero no NCrunch, algo sobre la serialización de AppDomains, creo).

Esto establecerá Thread.CurrentPrincipal dentro del método de acción ApiController y, por lo tanto, engañará al AuthorizeAttribute para que crea que está autenticado.

Configure el autenticador para su RestClient :

 RestClient.Authenticator = new HttpBasicAuthenticator(username, password); 

Usando el autenticador que su sistema de inicio de sesión personalizado realmente acepta … Básico, NTLM, OAuth, Simple …

Está documentado en la segunda línea del ejemplo en http://restsharp.org/