可以将自定义UserNamePasswordValidator用作角色提供程序吗?

时间:2010-08-24 09:00:48

标签: wcf wcf-security

this question相关,我有一个自定义UserNamePasswordValidator,它登录到我们的内部API。作为此登录的一部分,我可以在系统中发现用户的角色。

我想稍后在PrincipalPermissionAttribute中对服务方法使用这些,例如:

[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role = "System Administrator")]
public string HelloWorld()
{ /* ... */ }

2 个答案:

答案 0 :(得分:6)

扩展Ladislav的回答:

没有。自定义UserNamePasswordValidator不能用作角色提供程序。 UserNamePasswordValidator在您想要混淆的OperationContext中的单独上下文(或线程或其他内容)中运行。

您需要做的是实施自定义授权。我发现this page对此非常有用。警告:在你到达有趣的位之前,有很多管道。

基本上,您从ServiceCredentials派生的类开始,在App.config中注册,如下所示:

<serviceBehaviors>
  <behavior name="...">
    <serviceAuthorization principalPermissionMode="Custom" />

    <serviceCredentials type="MyNamespace.MyServiceCredentials, MyAssembly">
      <userNameAuthentication userNamePasswordValidationMode="Custom" />

      <serviceCertificate etc. />
    </serviceCredentials>

将行为与您的服务相关联。

覆盖ServiceCredentials.CreateSecurityTokenManager以返回MySecurityTokenManager,来自ServiceCredentialsSecurityTokenManager。在此,覆盖CreateSecurityTokenAuthenticator,返回MySecurityTokenAuthenticator。这应该来自CustomUserNameSecurityTokenAuthenticator。在那里,覆盖ValidateUserNamePasswordCore。调用基类,它将返回授权策略列表。

在该列表中添加一个新列表:MyAuthorizationPolicy,它实现IAuthorizationPolicy。在那,你只是(哈)需要做以下事情:

public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
    IList<IIdentity> identities = GetIdentities(evaluationContext);

    // Find the GenericIdentity with our user-name in it.
    IIdentity currentIdentity = identities.SingleOrDefault(
        i => i is GenericIdentity &&
        StringComparer.OrdinalIgnoreCase.Equals(i.Name, UserName));
    if (currentIdentity == null)
        throw new InvalidOperationException("No Identity found");

    // Replace the GenericIdentity with a new one.
    identities.Remove(currentIdentity);
    var newIdentity =
        new GenericIdentity(_userName, currentIdentity.AuthenticationType);
    identities.Add(newIdentity);

    // This makes it available as
    // ServiceSecurityContext.Current.PrimaryIdentity later.
    evaluationContext.Properties["PrimaryIdentity"] = newIdentity;

    // This makes it available as Thread.CurrentPrincipal.
    IPrincipal newPrincipal = new GenericPrincipal(newIdentity, _roles);
    evaluationContext.Properties["Principal"] = newPrincipal;

    return true;
}

private static IList<IIdentity> GetIdentities(
    EvaluationContext evaluationContext)
{
    object identitiesProperty;
    if (!evaluationContext.Properties.TryGetValue(
        "Identities", out identitiesProperty))
    throw new InvalidOperationException("No Identity found");

    var identities = identitiesProperty as IList<IIdentity>;
    if (identities == null)
        throw new InvalidOperationException("No Identity found");
    return identities;
}

然后,完成这些操作后,您可以使用PrincipalPermission标记您的服务操作:

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

答案 1 :(得分:2)

我认为它不能因为您需要创建自定义Principal。我认为你不能在验证器中做到这一点的原因是因为我读到了某个地方,验证器运行在与操作上下文不同的线程中。我从来没有检查过,但我们假设它确实如此。基于此假设,验证器中设置的Principal将不会用于WCF操作。您必须创建custom autorization或自定义角色提供程序。