#c# #web-services #adfs #wif
#c# #веб-службы #adfs #с помощью
Вопрос:
Я пытаюсь перейти с WIF 3.5 на WIF 4.5. Однако преобразование оказывается более сложным, чем я ожидал. Вопросы будут соответствовать комментариям в коде.
Полное сообщение об ошибке:
System.Web.Services.Протоколы.Исключение SoapException: ‘System.Web.Services.Протоколы.Исключение SoapException: ошибка аутентификации —>
Система.ServiceModel.Безопасность.Исключение SecurityNegotiationException: не удается открыть защищенный канал, поскольку не удалось согласовать безопасность с удаленной конечной точкой. Это может быть связано с отсутствием или неправильно указанным EndpointIdentity в EndpointAddress, используемом для создания канала. Пожалуйста, убедитесь, что EndpointIdentity, указанный или подразумеваемый EndpointAddress, правильно идентифицирует удаленную конечную точку.
Не удается открыть защищенный канал, поскольку не удалось согласовать безопасность с удаленной конечной точкой. Это может быть связано с отсутствием или неправильно указанным EndpointIdentity в EndpointAddress, используемом для создания канала. Пожалуйста, убедитесь, что EndpointIdentity, указанный или подразумеваемый EndpointAddress, правильно идентифицирует удаленную конечную точку.
# 1. Какая комбинация имени пользователя и пароля необходима, а какая нет?
#2. Именно здесь возникает исключение SecurityNegotiationException. Чего именно мне не хватает?
Итак, я ошибаюсь или мне не хватает чего-то простого? Нужно ли мне полностью переписывать, как создается WSTrustChannelFactory
?
Код:
public string GetToken(string url, string domain, string realm, string username, string password)
{
string rp = realm;
string token = "";
WSTrustChannelFactory trustChannelFactory = new WSTrustChannelFactory
(
new WSHttpBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(new Uri(url))
);
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.Credentials.Windows.ClientCredential.Domain = domain;
trustChannelFactory.Credentials.Windows.ClientCredential.UserName = username; // #1; not sure which pair is needed?
trustChannelFactory.Credentials.Windows.ClientCredential.Password = password;
trustChannelFactory.Credentials.UserName.Password = password;
trustChannelFactory.Credentials.UserName.UserName = username;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
try
{
RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue, KeyTypes.Bearer);
rst.AppliesTo = new EndpointReference(rp);
rst.TokenType = SecurityTokenTypes.Saml;
WSTrustChannel channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
GenericXmlSecurityToken token = channel.Issue(rst) as GenericXmlSecurityToken; // #2; Exception thrown here
token = token.TokenXml.OuterXml;
}
catch (SecurityNegotiationException e)
{
LogError("Authentication Failed", e);
}
catch (TimeoutException e)
{
LogError("Unable to authenticate", e);
}
catch (CommunicationException e)
{
LogError("Communication exception", e);
}
catch (Exception e)
{
LogError("Unknown exception", e);
}
return token;
}
Ответ №1:
Вам необходимо использовать SecurityTokenHandlerCollection
public SecurityToken GetToken(string url, string realm, string username, string password)
{
string rp = realm;
WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.EstablishSecurityContext = false;
EndpointAddress endpoint = new EndpointAddress(url);
WSTrustChannelFactory factory = new WSTrustChannelFactory(binding, endpoint);
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = username;
factory.Credentials.UserName.Password = password;
WSTrustChannel channel = (WSTrustChannel) factory.CreateChannel();
RequestSecurityToken rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference(rp),
TokenType = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0"
};
GenericXmlSecurityToken genericXmlSecurityToken = (GenericXmlSecurityToken) channel.Issue(rst, out RequestSecurityTokenResponse rstr);
SecurityTokenHandlerCollection tokenHandlers = new SecurityTokenHandlerCollection(
new SecurityTokenHandler[]
{
new SamlSecurityTokenHandler(),
new Saml2SecurityTokenHandler()
}
);
tokenHandlers.Configuration.AudienceRestriction = new AudienceRestriction();
tokenHandlers.Configuration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(rp));
TrustedIssuerNameRegistry trustedIssuerNameRegistry = new TrustedIssuerNameRegistry();
tokenHandlers.Configuration.IssuerNameRegistry = trustedIssuerNameRegistry;
SecurityToken token =
tokenHandlers.ReadToken(
new XmlTextReader(new StringReader(genericXmlSecurityToken.TokenXml.OuterXml)));
return token;
}
public class TrustedIssuerNameRegistry : IssuerNameRegistry
{
public override string GetIssuerName(SecurityToken securityToken)
{
return "Trusted Issuer";
}
}
Ответ №2:
Мы решили пока продолжать использовать WIF 3.5 и полностью перепишем для WIF 4.5 вместо того, чтобы пытаться сделать что-то невозможное.
Было просто слишком много изменений и недостаточно документации, чтобы «включить» наш существующий код с версии WIF 3.4 на версию WIF 4.5