如何修改WIF的ValidatingIssuerNameRegistry以支持Azure AD,ACS,Facebook,LiveID和其他IDP?

时间:2014-01-30 18:31:23

标签: azure wif multi-tenant acs azure-active-directory

我有一个应用程序,我想向尽可能多的用户公开。为实现此目的,我按照as explained here的说明将我的应用程序连接到Azure Active Directory,并将a variation of these instructions to connect AAD连接到Azure ACS 2.0。

Azure ACS 2.0将处理所有联合域和Microsoft帐户(以前称为LiveID或Passport)。它还将处理Facebook,Twitter和其他OAuth服务。

Azure Active Directory将处理Office 365以及将其公司Active Directory同步到云的任何人。

我的主域发现页面将在以下URL发出GET,以确定是否应使用LiveID或AzureAD域。

https://login.microsoftonline.com/GetUserRealmExtended.srf?login=EMAIL@COMPANY.com 

或     http://odc.officeapps.live.com/odc/emailhrd/getidp?hm=0&emailAddress=USER%COMPANY.com

如果用户不存在,我将使用Azure ACS与该公司的联合。缺乏这一点,用户将无法登录。

现在我解释了我的配置,我打算让Windows Identity Foundation(WIF)允许来自ACS 2.0和ADFS的身份验证。

问题

  • 如何获得WIF 4.5,特别是ValidatingIssuerNameRegistry以正确处理多个IDP的多个信任?

以下是将应用程序与Azure Active Directory联合时VS2013附带的代码。它响应所有联合请求并执行其他我不理解的事情。任何有关此课程的链接或信息都会有所帮助

  public class DatabaseIssuerNameRegistry : ValidatingIssuerNameRegistry
  { 
    public static bool ContainsTenant(string tenantId)
    {
        using (TenantDbContext context = new TenantDbContext())
        {
            return context.Tenants
                .Where(tenant => tenant.Id == tenantId)
                .Any();
        }
    }

    public static bool ContainsKey(string thumbprint)
    {
        using (TenantDbContext context = new TenantDbContext())
        {
            return context.IssuingAuthorityKeys
                .Where(key => key.Id == thumbprint)
                .Any();
        }
    }

    public static void RefreshKeys(string metadataLocation)
    {
        IssuingAuthority issuingAuthority = ValidatingIssuerNameRegistry.GetIssuingAuthority(metadataLocation);

        bool newKeys = false;
        foreach (string thumbprint in issuingAuthority.Thumbprints)
        {
            if (!ContainsKey(thumbprint))
            {
                newKeys = true;
                break;
            }
        }

        if (newKeys)
        {
            using (TenantDbContext context = new TenantDbContext())
            {
                context.IssuingAuthorityKeys.RemoveRange(context.IssuingAuthorityKeys);
                foreach (string thumbprint in issuingAuthority.Thumbprints)
                {
                    context.IssuingAuthorityKeys.Add(new IssuingAuthorityKey { Id = thumbprint });
                }
                context.SaveChanges();
            }
        }
    }

    public static bool TryAddTenant(string tenantId, string signupToken)
    {
        if (!ContainsTenant(tenantId))
        {
            using (TenantDbContext context = new TenantDbContext())
            {
                SignupToken existingToken = context.SignupTokens.Where(token => token.Id == signupToken).FirstOrDefault();
                if (existingToken != null)
                {
                    context.SignupTokens.Remove(existingToken);
                    context.Tenants.Add(new Tenant { Id = tenantId });
                    context.SaveChanges();
                    return true;
                }
            }
        }

        return false;
    }

    public static void AddSignupToken(string signupToken, DateTimeOffset expirationTime)
    {
        using (TenantDbContext context = new TenantDbContext())
        {
            context.SignupTokens.Add(new SignupToken
            {
                Id = signupToken,
                ExpirationDate = expirationTime
            });
            context.SaveChanges();
        }
    }

    public static void CleanUpExpiredSignupTokens()
    {
        DateTimeOffset now = DateTimeOffset.UtcNow;
        using (TenantDbContext context = new TenantDbContext())
        {
            IQueryable<SignupToken> tokensToRemove = context.SignupTokens.Where(token => token.ExpirationDate <= now);
            if (tokensToRemove.Any())
            {
                context.SignupTokens.RemoveRange(tokensToRemove);
                context.SaveChanges();
            }
        }
    }

    protected override bool IsThumbprintValid(string thumbprint, string issuer)
    {
        string issuerID = issuer.TrimEnd('/').Split('/').Last();

        return ContainsTenant(issuerID) &&
            ContainsKey(thumbprint);
    }
}

1 个答案:

答案 0 :(得分:1)

Vittorio Bertocci在这篇文章中很好地解释了DatabaseIssuerNameRegistry。

VS2013 RTM, Organizational Accounts and Publishing to Windows Azure Web Sites

底线是DatabaseIssuerNameRegistry只是一个基于实体框架的ValidatingIssuerNameRegistry,它使用令牌的指纹从数据库中查找发行者名称,并验证它是否与配置的值匹配发布者名称,而不是使用web.config。如果/当权限更改时,它更灵活并处理更新指纹。