asp.net - 如何在设置 ADFS 身份验证时通过 TFS 将 asp.net web 应用程序部署到开发团队

标签 asp.net tfs adfs2.0 adfs

我正在开发一个 asp.net web 应用程序,它是 TFS 的一部分并由开发团队使用。最近,作为项目的一部分,我们设置了 ADFS,现在正尝试将项目的身份验证强制执行到 ADFS 服务器。

在我的开发机器上,我完成了添加生成联合元数据的 STS 引用以及更新项目的 web.config 文件的步骤。 web.config 中的授权使用指纹认证,这要求我将 ADFS 证书添加到我的本地机器,并为开发机器生成签名证书并将其添加到 ADFS。

所有设置和工作都在查看 web.config。和 FederationMetadata.xml 记录这些“看起来”是特定于机器的。我怀疑如果我将项目/文件 checkin TFS,那么下一个进行构建的开发人员或测试人员最终会在他们的机器上出现损坏的构建。

我的问题是在 TFS 中, checkin 这样的场景并仍然允许我的团队在其开发或测试环境中使用最新代码 checkout 、构建和测试项目的过程是什么?

此时我的工作是从 checkin 中排除 FederationMetaData.xml 和 web.config,然后在每台开发机器上手动设置 ADFS 身份验证以及产品测试。一旦完成,每个人都可以阻止他们的 FederationMetatData.xml 和 web.config 的本地副本被 checkin 。(也就是拥有自己的本地副本)然后在 checkin / checkout 时确保每个开发人员保留他们自己的副本(或不保留)将它们检查到 TFS 中)

这看起来效率极低,而且几乎绕过了源代码管理的本质,因为开发人员需要在他们的机器上保留文件的本地副本。这似乎也引入了意外 checkin 本地文件或覆盖本地文件的机会。

有没有人有关于如何为 (ADFS) 机器特定配置 checkin 代码而不是管理整个开发环境的任何引用、文档或信息?

提前致谢

最佳答案

我同意 WIF 工具集进行配置的方式不适合在具有多个开发人员和测试环境的团队中工作。我为克服此问题而采取的方法是将 WIF 更改为在运行时配置。

您可以采取的一种方法是放置一个虚拟的 /FederationMetadata/2007-06/FederationMetadata.xml 并将其 checkin TFS。它必须具有有效的 URL,否则就是一个有效的文件。

此外,您需要在 web.config 中有一个有效的 federationAuthentication 部分,其中包含虚拟(但格式有效)audienceUrisissuerrealm 条目。

  <microsoft.identityModel>
    <service>
      <audienceUris>
        <add value="https://yourwebsite.com/" />
      </audienceUris>
      <federatedAuthentication>
        <wsFederation passiveRedirectEnabled="true" issuer="https://yourissuer/v2/wsfederation" realm="https://yourwebsite.com/" requireHttps="true" />
        <cookieHandler requireSsl="false" />
      </federatedAuthentication>
      etc...

然后,将应用程序的 ADFS 配置更改为完全运行时驱动。您可以通过在 ADFS 模块启动和 ASP.NET 管道期间挂接各种事件来执行此操作。

看看this forums post获取更多信息。

本质上,您会希望在 global.asax.cs 中有这样的东西。这是我在 Windows Azure Web 角色上使用的一些代码,用于从 ServiceConfiguration.cscfg(在 Azure 模型中的部署/运行时可更改)中读取。它可以很容易地适应从 web.config 或您选择的任何其他配置系统(例如数据库)中读取。

    protected void Application_Start(object sender, EventArgs e)
    {
        FederatedAuthentication.ServiceConfigurationCreated += OnServiceConfigurationCreated;
    }

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        /// Due to the way the ASP.Net pipeline works, the only way to change 
        /// configurations inside federatedAuthentication (which are configurations on the http modules)
        /// is to catch another event, which is raised everytime a request comes in.
        ConfigureWSFederation();
    }

    /// <summary>
    /// Dynamically load WIF configuration so that it can live in ServiceConfiguration.cscfg instead of Web.config
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="eventArgs"></param>
    void OnServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs eventArgs)
    {
        try
        {
            ServiceConfiguration serviceConfiguration = eventArgs.ServiceConfiguration;

            if (!String.IsNullOrEmpty(RoleEnvironment.GetConfigurationSettingValue("FedAuthAudienceUri")))
            {
                serviceConfiguration.AudienceRestriction.AllowedAudienceUris.Add(new Uri(RoleEnvironment.GetConfigurationSettingValue("FedAuthAudienceUri")));
                Trace.TraceInformation("ServiceConfiguration: AllowedAudienceUris = {0}", serviceConfiguration.AudienceRestriction.AllowedAudienceUris[0]);
            }

            serviceConfiguration.CertificateValidationMode = X509CertificateValidationMode.None;
            Trace.TraceInformation("ServiceConfiguration: CertificateValidationMode = {0}", serviceConfiguration.CertificateValidationMode);

            // Now load the trusted issuers
            if (serviceConfiguration.IssuerNameRegistry is ConfigurationBasedIssuerNameRegistry)
            {
                ConfigurationBasedIssuerNameRegistry issuerNameRegistry = serviceConfiguration.IssuerNameRegistry as ConfigurationBasedIssuerNameRegistry;

                // Can have more than one. We don't.
                issuerNameRegistry.AddTrustedIssuer(RoleEnvironment.GetConfigurationSettingValue("FedAuthTrustedIssuerThumbprint"), RoleEnvironment.GetConfigurationSettingValue("FedAuthTrustedIssuerName"));
                Trace.TraceInformation("ServiceConfiguration: TrustedIssuer = {0} : {1}", RoleEnvironment.GetConfigurationSettingValue("FedAuthTrustedIssuerThumbprint"), RoleEnvironment.GetConfigurationSettingValue("FedAuthTrustedIssuerName"));
            }
            else
            {
                Trace.TraceInformation("Custom IssuerNameReistry type configured, ignoring internal settings");
            }

            // Configures WIF to use the RsaEncryptionCookieTransform if ServiceCertificateThumbprint is specified.
            // This is only necessary on Windows Azure because DPAPI is not available.
            ConfigureWifToUseRsaEncryption(serviceConfiguration);
        }
        catch (Exception exception)
        {
            Trace.TraceError("Unable to initialize the federated authentication configuration. {0}", exception.Message);
        }
    }

    /// <summary>
    /// Configures WIF to use the RsaEncryptionCookieTransform, DPAPI is not available on Windows Azure.
    /// </summary>
    /// <param name="requestContext"></param>
    private void ConfigureWifToUseRsaEncryption(ServiceConfiguration serviceConfiguration)
    {
        String svcCertThumbprint = RoleEnvironment.GetConfigurationSettingValue("FedAuthServiceCertificateThumbprint");

        if (!String.IsNullOrEmpty(svcCertThumbprint))
        {
            X509Store certificateStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);

            try
            {
                certificateStore.Open(OpenFlags.ReadOnly);
                // We have to pass false as last parameter to find self-signed certs.
                X509Certificate2Collection certs = certificateStore.Certificates.Find(X509FindType.FindByThumbprint, svcCertThumbprint, false /*validOnly*/);

                if (certs.Count != 0)
                {
                    serviceConfiguration.ServiceCertificate = certs[0];
                    // Use the service certificate to protect the cookies that are sent to the client.
                    List<CookieTransform> sessionTransforms =
                        new List<CookieTransform>(new CookieTransform[] { new DeflateCookieTransform(),
                                new RsaEncryptionCookieTransform(serviceConfiguration.ServiceCertificate)});

                    SessionSecurityTokenHandler sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());

                    serviceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
                    Trace.TraceInformation("ConfigureWifToUseRsaEncryption: Using RsaEncryptionCookieTransform for cookieTransform");
                }
                else
                {
                    Trace.TraceError("Could not find service certificate in the My store on LocalMachine");
                }
            }
            finally
            {
                certificateStore.Close();
            }
        }
    }

    private static void ConfigureWSFederation()
    {
        // Load the federatedAuthentication settings
        WSFederationAuthenticationModule federatedModule = FederatedAuthentication.WSFederationAuthenticationModule as WSFederationAuthenticationModule;
        if (federatedModule != null)
        {
            federatedModule.PassiveRedirectEnabled = true;

            if (!String.IsNullOrEmpty(RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationRequireHttps")))
            {
                federatedModule.RequireHttps = bool.Parse(RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationRequireHttps"));
            }
            if (!String.IsNullOrEmpty(RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationIssuer")))
            {
                federatedModule.Issuer = RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationIssuer");
            }
            if (!String.IsNullOrEmpty(RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationRealm")))
            {
                federatedModule.Realm = RoleEnvironment.GetConfigurationSettingValue("FedAuthWSFederationRealm");
            }

            CookieHandler cookieHandler = FederatedAuthentication.SessionAuthenticationModule.CookieHandler;
            cookieHandler.RequireSsl = false;
        }
        else
        {
            Trace.TraceError("Unable to configure the federated module. The modules weren't loaded.");
        }
    }
}

这将允许您在运行时配置以下设置:

  <Setting name="FedAuthAudienceUri" value="-- update with audience url. e.g. https://yourwebsite/ --" />
  <Setting name="FedAuthWSFederationIssuer" value="-- update with WSFederation endpoint. e.g. https://yourissuer/v2/wsfederation--" />
  <Setting name="FedAuthWSFederationRealm" value="-- update with WSFederation realm. e.g. https://yourwebsite/" />
  <Setting name="FedAuthTrustedIssuerThumbprint" value="-- update with certificate thumbprint from ACS configuration. e.g. cb27dd190485afe0f62e470e4e3578de51d52bf4--" />
  <Setting name="FedAuthTrustedIssuerName" value="-- update with issuer name. e.g. https://yourissuer/--" />
  <Setting name="FedAuthServiceCertificateThumbprint" value="-- update with service certificate thumbprint. e.g. same as HTTPS thumbprint: FE95C43CD4C4F1FC6BC1CA4349C3FF60433648DB --" />
  <Setting name="FedAuthWSFederationRequireHttps" value="true" />

关于asp.net - 如何在设置 ADFS 身份验证时通过 TFS 将 asp.net web 应用程序部署到开发团队,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8491114/

相关文章:

c# - 从代码隐藏 (.NET) 访问 html 表循环内的复选框

angular - Angular 2 应用程序的 TFS 构建失败(TypeScript 错误),但在本地构建一切正常

asp.net - ADFS 2.0超时以及Freshness Value,TokenLifetime和WebSSOLifetime参数之间的关系

asp.net - 如何使用引导警报在 asp.net 网页上显示任何操作状态?

C#、ASP.NET - 限制对 Controller 方法的访问

c# - "context.Resource as AuthorizationFilterContext"在 ASP.NET Core 3.0 中返回 null

c# - Team Foundation Server 是将 .net 网站自动发布到远程服务器的正确解决方案吗?

tfs - 如何以编程方式跨多个分支跟踪 TFS 变更集?

adfs2.0 - 将 ADFS 与 Spring SAML 扩展集成时的问题

.net - 是否可以对复杂的声明进行建模(分层/嵌套/等)?