Pergunta

Estou implementando um serviço WCF seguro. A autenticação é feita usando nome de usuário / senha ou credenciais do Windows. O serviço está hospedado em um processo serviço do Windows. Agora, eu estou tentando descobrir a melhor maneira de implementar autorização para cada operação de serviço.

Por exemplo, considere o seguinte método:

public EntityInfo GetEntityInfo(string entityId);

Como você deve saber, no WCF, existe um objeto OperationContext a partir do qual você pode recuperar as credenciais de segurança passados ??pelo chamador / cliente. Agora, Autenticação já teria terminado no momento da primeira linha no método é chamado. No entanto, como é que vamos implementar a autorização se a decisão depende do próprio dados de entrada? Por exemplo, no caso acima, dizem usuários 'admin' (cujas permissões etc são armazenadas em um banco de dados), são permitidos para obter informações entidade, e outros usuários não devem ser permitidos ... onde é que vamos colocar as verificações de autorização

Say vamos colocá-la na primeira linha do método assim:

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

Agora, há um par de perguntas:

  1. Será que validar o entityId (por exemplo verificação nulo / valor vazio etc) antes de a verificação de autorização ou dentro da verificação de autorização? Em outras palavras, se as verificações de autorização deve ser incluído em cada método, é que um bom padrão? O que deve acontecer primeiro? - validação de argumento ou autorização

  2. Como nós teste de unidade de um serviço WCF quando verificações de autorização estão por todo o lugar como este, e não temos um OperationContext no teste de unidade !? (Supondo que eu estou tentando testar esta implementação classe de serviço diretamente, sem qualquer da configuração WCF).

Qualquer caras idéias?

Foi útil?

Solução

Para a pergunta 1, absolutamente fazer a autorização primeiro. Nenhum código (dentro de seu controle) deve ser executado antes da autorização para manter a segurança apertada. o exemplo de Paulo acima é excelente.

Para a pergunta 2, você poderia lidar com isso por subclasses sua implementação serviço concreto. Faça a verdadeira implementação lógica de negócios uma classe abstrata com um método abstrato "CheckPermissions" como você menciona acima. Em seguida, crie 2 subclasses, um para uso WCF, e um (muito isolado em um não implantado DLL) que retorna verdadeiro (ou o que você gostaria que ele faz em seu teste de unidade).

Exemplo (note, estes não devem ser no mesmo arquivo ou mesmo DLL embora!):

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;
    }
}

Em seguida, a implantação do WCF usa a classe "MyServiceMyAuth", e você faz o seu teste de unidade contra o outro.

Outras dicas

Para a questão 1, é melhor para executar a autorização primeiro. Dessa forma, você não vazar mensagens de erro de validação de volta para usuários não autorizados.

BTW, em vez de usar um método de autenticação home-grown (que eu suponho que é o que o seu CheckAccessPermission é), você pode ser capaz de ligar para o suporte out-of-the-box do WCF para provedores de função ASP.NET. Uma vez feito isso, você executar a autorização via OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole (). O PrimaryIdentity é um IPrincipal.

Sobre a questão # 2, eu faria isso usando Dependency Injection e configurar sua implementação do serviço algo como isto:

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
    }
}

Note que IAuthorization é uma interface que você definiria.

Porque você vai estar testando o tipo de serviço diretamente (ou seja, sem executá-lo dentro do quadro hospedagem WCF) você simplesmente configurar o serviço para usar um manequim tipo IAuthorization que permite que todas as chamadas. No entanto, um teste ainda melhor é zombar do IAuthorization e teste que é chamado quando e com os parâmetros que você espera. Isso permite que você teste que suas chamadas para os métodos de autorização são válidos, juntamente com o próprio método.

Separar a autorização em seu próprio tipo também permite mais facilmente teste que ele está correto em isolamento. Na minha experiência (embora limitado), usando "padrões" de DI dar-lhe muito melhor separação de interesses e capacidade de teste em seus tipos, bem como levando a uma interface mais limpa (isso é, obviamente, aberta para debate).

Meu quadro zombando preferido é RhinoMocks que é gratuito e tem interface fluente muito agradável mas existem muitos outros lá fora. Se você gostaria de saber mais sobre DI aqui estão algumas boas primers e .Net estruturas:

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top