Шаблоны авторизации службы WCF - PullRequest
7 голосов
/ 28 сентября 2008

Я внедряю безопасный сервис WCF. Аутентификация выполняется с использованием имени пользователя / пароля или учетных данных Windows. Служба размещена в процессе службы Windows. Теперь я пытаюсь найти лучший способ реализации авторизации для каждой операции сервиса.

Например, рассмотрим следующий метод:

public EntityInfo GetEntityInfo(string entityId);

Как вы, возможно, знаете, в WCF существует объект OperationContext, из которого вы можете получить учетные данные безопасности, переданные абонентом / клиентом. Теперь аутентификация уже будет завершена к тому времени, когда будет вызвана первая строка в методе. Однако как мы реализуем авторизацию, если решение зависит от самих входных данных? Например, в приведенном выше случае, скажем, пользователям с правами администратора (чьи разрешения и т. Д. Хранятся в базе данных) разрешено получать информацию об объектах, а другим пользователям не разрешается ... куда мы помещаем проверки авторизации? 1010 *

Скажем, мы поместили его в первую строку метода следующим образом:

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

Теперь есть пара вопросов:

  1. Проверяем ли мы идентификатор объекта (например, проверяем нулевое / пустое значение и т. Д.) ДО проверки полномочий или ВНУТРИ проверки авторизации? Другими словами, если проверки авторизации должны быть включены в каждый метод, это хороший шаблон? Что должно произойти первым - проверка аргумента или авторизация?

  2. Как мы можем провести модульное тестирование службы WCF, когда проверки авторизации повсеместно, как это, и у нас нет OperationContext в модульном тесте !? (Предполагается, что я пытаюсь протестировать реализацию этого класса обслуживания напрямую, без установки WCF).

Есть идеи, ребята?

Ответы [ 3 ]

6 голосов
/ 17 марта 2009

Что касается вопроса №2, я бы сделал это с помощью Dependency Injection и настроил реализацию вашей службы примерно так:

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

Обратите внимание, что IAuthorization - это интерфейс, который вы определяете.

Поскольку вы собираетесь тестировать тип сервиса напрямую (то есть без запуска его внутри среды размещения WCF), вы просто настраиваете сервис на использование фиктивного типа IAuthorization, который разрешает все вызовы. Тем не менее, еще более ЛУЧШИЙ тест - это смоделировать IAuthorization и проверить, что он вызывается, когда и с параметрами, которые вы ожидаете. Это позволяет вам проверить правильность ваших вызовов методов авторизации вместе с самим методом.

Разделение авторизации на ее собственный тип также позволяет вам легче проверять ее правильность в отдельности. По моему (хотя и ограниченному) опыту, использование «шаблонов» DI дает вам намного лучшее разделение проблем и тестируемости в ваших типах, а также приводит к более чистому интерфейсу (это, очевидно, открыто для обсуждения).

Мой предпочтительный фреймворк: RhinoMocks , который бесплатный и имеет очень хороший свободный интерфейс, но есть много других. Если вы хотите узнать больше о DI, вот несколько хороших учебников и платформ .Net:

6 голосов
/ 28 сентября 2008

Для вопроса 1 лучше сначала выполнить авторизацию. Таким образом, вы не будете передавать сообщения об ошибках проверки неавторизованным пользователям.

Кстати, вместо использования собственного метода аутентификации (который, как я полагаю, и есть ваш CheckAccessPermission), вы можете подключиться к стандартной поддержке WCF для поставщиков ролей ASP.NET. После этого вы выполняете авторизацию через OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole (). Основной идентификатор - это принцип IP.

3 голосов
/ 29 сентября 2008

Для вопроса 1 обязательно сделайте сначала авторизацию. Ни один код (в пределах вашего контроля) не должен выполняться перед авторизацией для обеспечения максимальной безопасности. Приведенный выше пример Павла превосходен.

В вопросе 2 вы можете решить эту проблему, создав подкласс для конкретной реализации сервиса. Сделайте истинную реализацию бизнес-логики абстрактным классом с абстрактным методом «CheckPermissions», как вы упомянули выше. Затем создайте 2 подкласса, один для использования в WCF и один (очень изолированный в не развернутой DLL), который возвращает true (или все, что вы хотели бы сделать в модульном тестировании).

Пример (обратите внимание, они не должны быть в одном файле или даже в 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;
    }
}

Затем в вашем развертывании WCF используется класс «MyServiceMyAuth», и вы выполняете тестирование модулей в сравнении с другим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...