RequestSecurityToken с использованием учетных данных Windows и.net 4.5 WIF
Может ли кто-нибудь указать пример кода для активной выдачи RequestSecurityToken с использованием учетных данных NT Thread.CurrentPrincipal as ClaimsPrincipal
?
Сценарий представляет собой веб-приложение asp.net с включенной аутентификацией Windows (поэтому существует аутентифицированная WindowsIdentity). Мое желание состоит в том, чтобы активнее вызывать STS, а не активировать passiveRedirect, и делать это с помощью библиотек идентификации.Net 4.5.
Большинство примеров кода, таких как Claims Helper для Windows Phone или Использование Active STS, устанавливают учетные данные с помощью ввода имени пользователя /pwd и UserNameWSTrustBinding.
Я думал, что решение может включать в себя подражание или призыв к channelFactory.CreateChannelWithActAsToken()
с токеном, созданным из идентификатора Windows.
- Следующий код.Net4.5 действительно получает GenericXmlSecurityToken при обращении к конечной точке /adfs/services/trust/13/windowsmixed. Однако претензии относятся к учетной записи домена, под которой работает сайт, а не к учетной записи домена аутентифицированного пользователя. Когда я переключаю конечную точку на /adfs/services/trust/13/kerberossmixed, я получаю сообщение об ошибке "не могу договориться", как описано в нескольких вопросах и на форумах, но я не могу применить какие-либо предлагаемые решения с.Net 4.5. Одним из классов, не перенесенных из Microsoft.IdentityModel, является KerberosWSTrustBinding...
public static void CallSts()
{
try
{
var wsMod = FederatedAuthentication.WSFederationAuthenticationModule;
var appliesToEp = new EndpointReference(wsMod.Realm);
var stsEp = new EndpointAddress(new Uri(wsMod.Issuer), EndpointIdentity.CreateSpnIdentity("stsSpn"));
var msgBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
msgBinding.Security.Message.EstablishSecurityContext = false;
msgBinding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
using(var factory = new WSTrustChannelFactory(msgBinding, stsEp))
{
factory.Credentials.SupportInteractive = false;
factory.TrustVersion = TrustVersion.WSTrust13;
var myRst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = appliesToEp,
KeyType = KeyTypes.Bearer,
};
var channel = factory.CreateChannel();
var stsToken = channel.Issue(myRst) as GenericXmlSecurityToken;
if(stsToken != null)
{
Log.DebugFormat("Reply Token is {0}", stsToken.GetType().Name);
var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
var token = handlers.ReadToken(new XmlTextReader(new StringReader(stsToken.TokenXml.OuterXml)));
var identity = handlers.ValidateToken(token).First();
//TODO write to session
}
else
{
Log.Debug("Reply Token is null.");
}
}
}
catch(Exception ex)
{
Log.Error("Rst.Call has failed", ex);
}
}
Для предложения @leastprivilege я добавлю этот код:
var user = Thread.CurrentPrincipal as ClaimsPrincipal;
var winId = user.Identity as WindowsIdentity;
if(winId != null)
{
// shows my domain account after I was prompted for credentials;
// my domain account does not exist on the client machine, so it is a true domain credential
Log.DebugFormat("WindowsIdentity Name is {0}", winId.Name);
}
using(winId.Impersonate())
{
// again, shows my domain account
Log.DebugFormat("Impersonation Context {0}", WindowsIdentity.GetCurrent(true).Name);
var channel = factory.CreateChannel();
var stsToken = channel.Issue(myRst) as GenericXmlSecurityToken;
// request is issued, but results in SecurityNegotiationException: The caller was not authenticated by the service.
}
Который не работает с "Звонящий не был аутентифицирован сервисом". Тот же STS аутентифицирует мою учетную запись домена в сценарии пассивного перенаправления... поэтому, хотя я знаю, что я делаю что-то не так, сама учетная запись должна быть распознана.
Обновить:
Я получил уведомление о том, что этот вопрос получил заметное количество просмотров, поэтому я предложу следующее в качестве одного из обходных путей: хотя мы настроили наши серверы для делегирования (как предложил Доминик ниже), мы все еще не преодолели проблему двойного перехода. Если я помню, мы сталкиваемся с препятствиями, связанными с простыми политиками управления сетями над нашими локальными ИТ-отделами, которые могут затронуть и любое предприятие. Таким образом, хотя олицетворение с использованием двойного прыжка на сервере с проверкой подлинности Windows не допускается, учетные данные могут быть олицетворены с помощью двойного прыжка с помощью обычной проверки подлинности. Это может или не может быть приемлемой ситуацией (интранет для нашего случая). Если вы это сделаете, вы бы добавили
msgBinding.Security.Message.NegotiateServiceCredential = true;
к вышеупомянутой конфигурации ChannelBinding.
1 ответ
Ну, это на самом деле не тривиально. Для этого вам нужно выполнить олицетворение и делегирование Kerberos.
Прежде всего, подражание. Вам необходимо вызвать Impersonate() для WindowsIdentity, который вы получаете из Thread.CurrentPrincipal.
Вы можете убедиться, что вы олицетворяете себя, вызвав WindowsIdentity.GetCurrent. Эта идентификация должна указывать на клиента (в отличие от идентификации сервера).
Затем во время олицетворения вам нужно сделать запрос WS-Trust. Скорее всего, это по умолчанию запрещено. Таким образом, сетевой администратор должен настроить делегирование для идентификации сервера в STS.