Транспортная безопасность WCF с помощью Сертификатов игнорирует цепочечное доверие

ВНИМАНИЕ: В этом примере требуется Python 2.7 или выше.

Встроенный в Python объект Counter - это именно то, что вы ищете. Подсчет слов является даже первым примером в документации:

>>> # Tally occurrences of words in a list
>>> from collections import Counter
>>> cnt = Counter()
>>> for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
...     cnt[word] += 1
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

Как указано в комментариях, Counter использует итерацию, поэтому приведенный выше пример приведен только для иллюстрации и эквивалентен:

>>> mywords = ['red', 'blue', 'red', 'green', 'blue', 'blue']
>>> cnt = Counter(mywords)
>>> cnt
Counter({'blue': 3, 'red': 2, 'green': 1})

6
задан Daniel Chambers 8 June 2009 в 15:29
поделиться

2 ответа

Я нашел решение своей проблемы, однако оно оказалось намного неприятнее, чем я ожидал.

По сути, для проверки учетных данных транспорта и сообщений вам необходимо определить пользовательская привязка. (Я нашел информацию по этому поводу здесь ).

Я обнаружил, что самый простой способ сделать это - продолжить настройку в XML, но во время выполнения скопировать и немного изменить привязку netTcp из XML конфигурация. Вам нужно включить буквально один переключатель. Вот код на стороне службы и на стороне клиента:

Сторона службы

ServiceHost businessHost = new ServiceHost(typeof(DHTestBusinessService));
ServiceEndpoint endpoint = businessHost.Description.Endpoints[0];
BindingElementCollection bindingElements = endpoint.Binding.CreateBindingElements();
SslStreamSecurityBindingElement sslElement = bindingElements.Find<SslStreamSecurityBindingElement>();
sslElement.RequireClientCertificate = true; //Turn on client certificate validation
CustomBinding newBinding = new CustomBinding(bindingElements);
NetTcpBinding oldBinding = (NetTcpBinding)endpoint.Binding;
newBinding.Namespace = oldBinding.Namespace;
endpoint.Binding = newBinding;

Сторона клиента

DHTestBusinessServiceClient client = new DHTestBusinessServiceClient();
ServiceEndpoint endpoint = client.Endpoint;
BindingElementCollection bindingElements = endpoint.Binding.CreateBindingElements();
SslStreamSecurityBindingElement sslElement = bindingElements.Find<SslStreamSecurityBindingElement>();
sslElement.RequireClientCertificate = true; //Turn on client certificate validation
CustomBinding newBinding = new CustomBinding(bindingElements);
NetTcpBinding oldBinding = (NetTcpBinding)endpoint.Binding;
newBinding.Namespace = oldBinding.Namespace;
endpoint.Binding = newBinding;

Вы могли подумать, что это все, но ошиблись! :) Вот где он становится лишним. Я приписывал своим конкретным методам службы PrincipalPermission ограничение доступа на основе ролей пользователя службы, например:

[PrincipalPermission(SecurityAction.Demand, Role = "StandardUser")]

Это начало давать сбой, как только я применил вышеупомянутые изменения. Причина заключалась в том, что

OperationContext.Current.ServiceSecurityContext.PrimaryIdentity

в конечном итоге оказался неизвестным, не прошедшим проверку подлинности лицом II. Это произошло потому, что на самом деле существует два идентификатора, представляющих пользователя: один для сертификата X509, используемого для аутентификации через транспорт, и один для учетных данных имени пользователя и пароля, используемых для аутентификации на уровне сообщений. Когда я перепроектировал двоичные файлы WCF, чтобы понять, почему он не дает мне мой PrimaryIdentity, я обнаружил, что в нем есть явная строка кода, которая заставляет его возвращать этот пустой IIdentity, если он находит более одного IIdentity. Я предполагаю, что это потому, что у него нет возможности определить, какой из них является основным .

Это означает, что использование атрибута PrincipalPermission невозможно. Вместо, Я написал метод, имитирующий его функциональность, который может иметь дело с несколькими IIdentity:

private void AssertPermissions(IEnumerable<string> rolesDemanded)
{
    IList<IIdentity> identities = OperationContext.Current.ServiceSecurityContext.AuthorizationContext.Properties["Identities"] as IList<IIdentity>;
    if (identities == null)
        throw new SecurityException("Unauthenticated access. No identities provided.");

    foreach (IIdentity identity in identities)
    {
        if (identity.IsAuthenticated == false)
            throw new SecurityException("Unauthenticated identity: " + identity.Name);
    }

    IIdentity usernameIdentity = identities.Where(id => id.GetType().Equals(typeof(GenericIdentity))).SingleOrDefault();
    string[] userRoles = Roles.GetRolesForUser(usernameIdentity.Name);

    foreach (string demandedRole in rolesDemanded)
    {
        if (userRoles.Contains(demandedRole) == false)
            throw new SecurityException("Access denied: authorisation failure.");
    }
}

Это некрасиво (особенно то, как я определяю учетные данные имени пользователя и пароля IIdentity), но он работает! Теперь, в верхней части моих служебных методов, мне нужно назвать это так:

AssertPermissions(new [] {"StandardUser"});
4
ответ дан 17 December 2019 в 07:08
поделиться

ознакомьтесь с разделом Codeplex - Интранет , который предоставляет контрольные списки для различных сценариев. Также следует упомянуть, что netTcpBindings не поддерживаются для использования в IIS5.0 и IIS6.0 - см. 3-й абзац здесь , только IIS7.0 +.

0
ответ дан 17 December 2019 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: