Проблема с использованием пользовательского принципала и идентичности со службами WCF
Мы используем пользовательский принципал и тип идентификации (ProdigyPrincipal/ProdigyIdentity), потому что нам нужна дополнительная информация в наших программах и службах. В программе мы устанавливаем принципала и личность. При взаимодействии со службой WCF принципал и идентификатор задаются, но после приведения к нашему собственному типу принципал и идентификатор равны нулю.
Я заметил, что между режимом отладки и модульным тестом есть разница. В режиме отладки тип участника и удостоверение имеют тип WindowsPrincipal и WindowsIdentity. В режиме модульного тестирования используются следующие типы: GenericPrincipal и GenericIdenity. В обеих ситуациях при приведении к пользовательскому типу значение равно нулю.
Установка и получение принципала / идентичности осуществляется через Thread.CurrentPrincipal. В файле App.configs в разделе привязки режим безопасности установлен на "Транспорт".
Используемая функция для настройки / получения принципала и личности:
protected static bool SetProdigyPrincipal()
{
#region require Thread.CurrentPrincipal should not be null
if (Thread.CurrentPrincipal == null) // OK
{
throw new InvalidOperationException("SetProdigyPrincipal(): Thread.CurrentPrincipal should not be null");
}
#endregion require Thread.CurrentPrincipal should not be null
var prodigyPrincipal = Thread.CurrentPrincipal as ProdigyPrincipal;
#region require prodigyPrincipal should not be null
if (prodigyPrincipal == null) // NOT OK
{
throw new InvalidOperationException("SetProdigyPrincipal(): prodigyPrincipal should not be null");
}
#endregion require prodigyPrincipal should not be null
// Get the Windows identity from the current principal
var prodigyIdentity = Thread.CurrentPrincipal.Identity as ProdigyIdentity;
#region require windowsIdentity should not be null
if (prodigyIdentity == null) // NOT OK
{
throw new InvalidOperationException("SetProdigyPrincipal(): prodigyIdentity should not be null");
}
#endregion require windowsIdentity should not be null
// Create new instance of Prodigy principal
var newProdigyPrincipal = new ProdigyPrincipal(prodigyIdentity);
#region require prodigyPrincipal should not be null
if (prodigyPrincipal == null)
{
throw new InvalidOperationException("SetProdigyPrincipal(): prodigyPrincipal should not be null");
}
#endregion require prodigyPrincipal should not be null
// Set the prodigy principal
var principalIsSet = ProdigyPrincipal.SetCurrentPrincipal(newProdigyPrincipal, ProdigyService.EnterpriseServiceBus);
// Return principal is set status
return principalIsSet;
}
Кто-нибудь знает, почему пользовательский принципал и тип идентификации не могут быть получены из потока?
С уважением, Ганс
1 ответ
У WCF есть более стандартный способ достижения той же цели через ServiceAuthorizationBehavior.
Если вы установите его свойство PrincipalPermissionMode равным "Custom", это позволит вам IAuthorizationPolicy
с помощью которого вы можете сделать заказ IPrincipal
доступный для WCF ServiceSecurityContext. DispatchRuntime назначит этот (ваш пользовательский) IPrincipal для Thread.CurrentPrincipal - что вам нужно, верно?
Это пример реализации IAuthorizationPolicy:
public class DemoAuthorizationPolicy : IAuthorizationPolicy
{
private readonly string id = Guid.NewGuid().ToString();
public string Id { get { return this.id; } }
public ClaimSet Issuer { get { return ClaimSet.System; } }
public bool Evaluate(EvaluationContext context, ref object state)
{
// Here, create your custom principal
IIdentity customIdentity = new GenericIdentity("myUserName", "myCustomAuthenticationType");
IPrincipal customPrincipal = new GenericPrincipal(customIdentity, new[] { "user", "powerUser" });
// Set EvaluationContext properties
context.Properties["Identities"] = new List<IIdentity> { customIdentity };
context.Properties["Principal"] = customPrincipal;
return true;
}
}
И вот как вы объявляете ServiceAuthorizationBehavior в Web.config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceAuthorization principalPermissionMode="Custom" >
<authorizationPolicies>
<add policyType="PrincipalPermissionModeDemo.DemoAuthorizationPolicy, YourAssemblyName"/>
</authorizationPolicies>
</serviceAuthorization>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Внутри вашего сервиса вы можете использовать декларативную безопасность через [PrincipalPermission]
атрибут, вы можете получить пользовательский IPrincipal из Thread.CurrentPrincipal
и (альтернативно) вы также можете получить ServiceSecurityContext.Current.PrimaryIdentity
,
Надеюсь, что решит вашу проблему!