Pregunta

Estoy implementando un servicio seguro WCF. La autenticación se realiza mediante un nombre de usuario / contraseña o credenciales de Windows. El servicio está alojado en un proceso de servicio de Windows. Ahora, estoy tratando de encontrar la mejor manera de implementar autorización para cada operación de servicio.

Por ejemplo, considera el siguiente método:

public EntityInfo GetEntityInfo(string entityId);

Como puede saber, en WCF, hay un objeto OperationContext desde el cual puede recuperar las credenciales de seguridad que le han pasado al llamante / cliente. Ahora, autenticación ya habrá terminado cuando se llame la primera línea del método. Sin embargo, ¿cómo implementamos la autorización si la decisión depende de los propios datos de entrada? Por ejemplo, en el caso anterior, digamos que los usuarios 'admin' (cuyos permisos, etc. están almacenados en una base de datos), pueden obtener información de la entidad y otros usuarios no deberían estar autorizados ... ¿dónde colocamos los controles de autorización? / p>

Digamos que lo colocamos en la primera línea del método de esta manera:

CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext

Ahora, hay un par de preguntas:

  1. ¿Validamos el ID de entidad (por ejemplo, verificamos valor nulo / vacío, etc.) ANTES de la verificación de autorización o DENTRO de la verificación de autorización? En otras palabras, si los controles de autorización deberían incluirse en cada método, ¿es un buen patrón? ¿Qué debería suceder primero: validación de argumentos o autorización?

  2. ¿Cómo probamos en unidad un servicio WCF cuando las verificaciones de autorización están por todas partes así, y no tenemos un OperationContext en la prueba de unidad? (Suponiendo que estoy intentando probar la implementación de esta clase de servicio directamente sin ninguna configuración de WCF).

¿Alguna idea, chicos?

¿Fue útil?

Solución

Para la pregunta 1, primero haga la autorización. Ningún código (dentro de su control) debe ejecutarse antes de la autorización para mantener la seguridad más estricta. El ejemplo anterior de Pablo es excelente.

Para la pregunta 2, puede manejar esto subclasificando la implementación de su servicio concreto. Convierta la verdadera implementación de la lógica empresarial en una clase abstracta con un resumen " CheckPermissions " Método como lo mencionas arriba. Luego cree 2 subclases, una para el uso de WCF y una (muy aislada en una DLL no implementada) que devuelva verdadero (o lo que quiera que haga en su prueba de unidad).

Ejemplo (tenga en cuenta que estos no deberían estar en el mismo archivo o incluso en el archivo DLL):

public abstract class MyServiceImpl
{
    public void MyMethod(string entityId)
    {
        CheckPermissions(entityId);
        //move along...
    }
    protected abstract bool CheckPermissions(string entityId);
}

public class MyServiceUnitTest
{
    private bool CheckPermissions(string entityId)
    {
        return true;
    }
}

public class MyServiceMyAuth
{
    private bool CheckPermissions(string entityId)
    {
        //do some custom authentication
        return true;
    }
}

Luego, su implementación de WCF usa la clase " MyServiceMyAuth " ;, y hace su prueba de unidad contra la otra.

Otros consejos

Para la pregunta 1, es mejor realizar primero la autorización. De esa forma, no perderá los mensajes de error de validación a usuarios no autorizados.

Por cierto, en lugar de utilizar un método de autenticación propio (que supongo que es su CheckAccessPermission), es posible que pueda conectarse a la compatibilidad inmediata con WCF para proveedores de roles de ASP.NET. Una vez hecho esto, realiza la autorización a través de OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole (). El PrimaryIdentity es un IPrincipal.

Sobre la pregunta # 2, haría esto utilizando la inyección de dependencia y configuraría su implementación de servicio algo como esto:

class MyService : IMyService
{
    public MyService() : this(new UserAuthorization()) { }
    public MyService(IAuthorization auth) { _auth = auth; }

    private IAuthorization _auth;

    public EntityInfo GetEntityInfo(string entityId)
    {
            _auth.CheckAccessPermission(PermissionType.GetEntity, 
                    user, entityId);

            //Get the entity info
    }
}

Tenga en cuenta que la Autorización es una interfaz que usted definiría.

Debido a que va a probar el tipo de servicio directamente (es decir, sin ejecutarlo dentro del marco de alojamiento de WCF), simplemente configura su servicio para usar un tipo de Autorización de Autorización que permita todas las llamadas. Sin embargo, una prueba MEJOR es burlarse de la Autorización y probar que se llama cuando y con los parámetros que espera. Esto le permite probar que sus llamadas a los métodos de autorización son válidas, junto con el método mismo.

La separación de la autorización en su propio tipo también le permite probar más fácilmente que es correcta de forma aislada. En mi (aunque limitada) experiencia, usando DI " patrones " le proporciona una separación mucho mejor de las preocupaciones y la capacidad de prueba en sus tipos, así como una interfaz más limpia (esto obviamente está abierto al debate).

Mi marco de burla preferido es RhinoMocks que es gratis y tiene una interfaz muy fluida Pero hay muchos otros por ahí. Si desea saber más acerca de DI, aquí hay algunos buenos cebadores y marcos .Net:

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top