Мне пришлось отказаться от базовой безопасности WCF UserName/Pwd и реализовать свои собственные пользовательские учетные данные для хранения дополнительной информации, кроме того, что предоставляется по умолчанию.Аутентификация WCF с помощью пользовательских ClientCredentials: какой тип clientCredentialType использовать?
Я работал через this MSDN article, но мне что-то не хватает, потому что он не работает.
Во-первых, у меня есть некоторые пользовательские ClientCredentials, которые обеспечивают пользовательский ClientCredentialsSecurityTokenManager:
public class CentralAuthCredentials : ClientCredentials
{
public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager()
{
return new CentralAuthTokenManager(this);
}
}
public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager
{
private CentralAuthCredentials credentials;
public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds)
{
this.credentials = creds;
}
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE)
return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType);
else
return base.CreateSecurityTokenProvider(tokenRequirement);
}
public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
{
outOfBandTokenResolver = null;
if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE)
return new CentralAuthTokenAuthenticator();
else
return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
}
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CentralAuthTokenSerializer();
}
}
Теперь, когда я запустить приложение, мои пользовательские учетные данные и маркер менеджер действительно получить создан. Однако в методе:
CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
...
}
tokenRequirement.TokenType попадается как нечто иное, чем мой пользовательский маркер. Что вызывает мой 1-й вопрос: Как, черт возьми, WCF знает, что означают требования к токену?
Кроме того, метод:
public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
return new CentralAuthTokenSerializer();
}
ли дозвонились один раз клиентом, но ни один из методов на возвращаемой лексемы сериализатором не всегда называется. Это указывает на то, что пользовательский токен никогда не отправляется через провод. Я предполагаю, что это вызвано тем, что вызов CreateSecurityTokenProvider() никогда не возвращал мой пользовательский поставщик токенов, так как SecurityTokenRequirement никогда не передается с указанием моего пользовательского токена.
На стороне клиента, у меня есть:
public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, ICentralAuthorizationManager, IDisposable
{
public PFPrincipal GenerateToken()
{
if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials)))
throw new ArgumentException("Must set CentralAuthCredentials before calling this method.");
return base.Channel.GenerateToken();
}
public PFPrincipal GenerateToken(CentralAuthToken token)
{
this.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token));
return this.GenerateToken();
}
Эти методы в основном должны удалить учетные данные по умолчанию из конечной точки и прикрепить новый экземпляр моих пользовательских CentralAuthCredentials. (Я схватил это Удалить/Добавить комбо из статьи MSDN где-нибудь).
В конфигурации:
<behaviors>
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
<clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" />
<serviceCertificate>
<authentication certificateValidationMode="None" revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="wsHttpServer2Server">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
Обратите внимание, что тип ClientCredentials поведения установлен в моем пользовательском учетные данные клиента. Тем не менее, на данный момент у меня все еще есть clientCredentialType привязки, установленного в «UserName». Это вызывает мой Второй вопрос: Какая черта должна clientCredentialType = "?" быть установленным, если я использую пользовательские учетные данные? Согласно MSDN, доступные значения для Сообщение безопасности не являются: Ни, Окна, UserName, Сертификат и IssuedToken.
Любые идеи? Надеюсь, я просто пропустил что-то простое? Для всей реализации существует как еще 6 классов, но я попытался включить только биты, необходимые для понимания ситуации ...
UPDATE # 1:
Я работал над этим весь день, и благодаря нескольким источникам, я понял, что часть того, что я пропускал был самый последний шаг на this page , который добавляет TokenParameters к привязке, так что привязка знает, как выглядит токен. Это ответ на мой первоначальный 1-й вопрос; «Какая черта устанавливает требования к токену?» Ответ: TokenParameters, назначенные привязке.
Так что теперь я добавил следующее расширение задающий TokenParameters на переплете:
public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement
{
public CentralAuthTokenBindingExtension()
: base()
{
}
public override Type BindingElementType
{
get { return typeof(SymmetricSecurityBindingElement); }
}
protected override System.ServiceModel.Channels.BindingElement CreateBindingElement()
{
X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters();
protectionParams.InclusionMode = SecurityTokenInclusionMode.Never;
SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement();
innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters());
//innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
innerBindingElement.ProtectionTokenParameters = protectionParams;
return innerBindingElement;
}
}
<extensions>
<bindingElementExtensions>
<add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
<bindings>
<customBinding>
<binding name="wsHttpServer2Server">
<CentralAuthCreds />
<binaryMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
Ну что получает меня шаг вперед. Теперь я получаю новое исключение на сервере:
"The security token manager cannot create a token authenticator for requirement ..."
Похоже, ФОС используют некоторые лексемы менеджера по умолчанию, чтобы попытаться справиться с моей пользовательской лексемой, вместо моего пользовательских маркеров обработчика (конструктор моего пользовательского лексемы обработчика никогда называется). Я думаю, что это происходит потому, что для клиента , у меня есть этот конфиг:
<endpointBehaviors>
<behavior name="Server2ServerEndpointBehavior">
<clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
Но на сервере у меня нет никакого эквивалента, чтобы позволить ему знать о пользовательских учетных данных клиента. Итак, новый вопрос: Где в конфигурации для сервера я рассказываю, что такое пользовательские ClientCredentials?
Update # 2:
Ну, я, наконец, понял, немного больше головоломки. Я только реализовал реализацию ClientCredentials, считая, что клиент отправляет кредиты, и это все. Клиент не выполняет аутентификацию службы, поэтому мне не нужны специальные ServiceCredentials. Ну, я был неправ. Указанные ServiceCredentials аутентифицируют токен из ClientCredentials и наоборот. Поэтому мне просто пришлось добавить пользовательскую реализацию ServiceCredentials, которая передала те же классы TokenSerializer и TokenAuthenticator.
К следующему вопросу: WCF теперь игнорирует мои сертификаты x509, указанные в конфигурации, которые отлично работают с UserName auth. Я собираюсь открыть для него совершенно новый вопрос!
Итак, этот вопрос читается почти так же, как мой последний два дня! – basscinner