How to deploy asp.net web application to development team via TFS when setting up ADFS authentication

荒凉一梦 提交于 2020-01-02 13:10:38

问题


I am working on a asp.net web application that has is a part of TFS and is used by the development team. Recently as part of the project we setup ADFS and are now attempting to enforce authentication of the project to an ADFS server.

On my development machine I have gone through the steps of adding STS reference which generates the Federation Meta-Data as well as updates the web.config file for the project. Authorization within the web.config uses thumbprint certification which requires me to add to my local machine the ADFS certificate as well as generate a signed certificate for the dev machine and add this to ADFS.

All is setup and working but in looking at the web.config. and FederationMetadata.xml document these "appear" to be machine specific. I suspect that if I check the project/files into TFS the next developer or tester that takes a build will end up with a broken build on their machine.

My question is within TFS what is the process for a scenario like this to check in and still allow my team to check out, build, and test the project with the latest code in their development or test environments?

My work around at this time is to exclude the FederationMetaData.xml and web.config from check in then on each development machine manually setup ADFS authentication as well as for product test. Once done each person can prevent their local copy of the FederationMetatData.xml and web.config from being checked in.(aka have their own local copy) then when checking in/out just ensure that each developer preserves their own copy (or does not check them into TFS)

This seems extremely inefficient, and all but bypasses the essence of source code management as developers are being required to keep local copies of files on their machine. This also seems to introduce the opportunity for accidental check-in of local files or overwriting local files.

Does anyone have any references, documentation or information on how to check-in code for (ADFS) machine specific configurations and not hose up the entire development environment?

Thanks in advance,


回答1:


I agree that the way that the WIF toolset does configuration is not great for working in teams with multiple developers and test environments. The approach that I've taken to get past this is to change WIF to be configured at runtime.

One approach you can take is to put a dummy /FederationMetadata/2007-06/FederationMetadata.xml in place and check that in to TFS. It must have valid urls and be otherwise a valid file.

Additionally, you will need a valid federationAuthentication section in web.config with dummy (but of valid form) audienceUris, issuer and realm entries.

  <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...

Then, change your application's ADFS configuration to be completely runtime driven. You can do this by hooking into various events during the ADFS module startup and ASP.NET pipeline.

Take a look at this forums post for more information.

Essentially, you'll want to have something like this in global.asax.cs. This is some code that I've used on a Windows Azure Web Role to read from ServiceConfiguration.cscfg (which is changeable at deploy/runtime in the Azure model). It could easily be adapted to read from web.config or any other configuration system of your choosing (e.g. database).

    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.");
        }
    }
}

This will then allow you to configure the following settings at runtime:

  <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" />


来源:https://stackoverflow.com/questions/8491114/how-to-deploy-asp-net-web-application-to-development-team-via-tfs-when-setting-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!