Search code examples
asp.netasp.net-mvcazureazure-active-directoryopenid-connect

Auto renew of thumbprint in an ASP.NET MVC Application which uses Azure AD


I have configured Azure AD (Microsoft Entra ID) authentication in an ASP.NET MVC project using WS-Federation. For that, I am getting a thumbprint from the Azure App, storing that into the web.config file.

Authentication has been working perfectly fine since last year. Still, the problem is that after every few months the thumbprint expires, I have to get the new thumbprint from the Azure Portal and replace it in the web.config file.

I am wondering if there is a way to automate this process or a better way of not manually updating the thumbprint after every couple of months.

web.config content for a reference:

<microsoft.identityModel>
    <service saveBootstrapTokens="true">
        <audienceUris>
            <add value="api://1233d47f-63a3-47KP-97b9-83225b1daXYA" />
        </audienceUris>
        <federatedAuthentication>
            <wsFederation passiveRedirectEnabled="true" issuer="https://login.microsoftonline.com/asdfghjk-50c5-44e9-a5a3-ff1cdf3227e5/wsfed" realm="api://1233d47f-63a3-47KP-97b9-83225b1daXYA" requireHttps="true" />
            <cookieHandler requireSsl="false" />
        </federatedAuthentication>
        <applicationService>
            <claimTypeRequired>
                <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
                <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
            </claimTypeRequired>
        </applicationService>
        <certificateValidation certificateValidationMode="None" />
        <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
            <trustedIssuers>
                <add thumbprint="ASDF1234d2d3bf259183107febbeaef25678GHJK" name="https://sts.windows.net/1233d47f-63a3-47KP-97b9-83225b1daXYA/" />
            </trustedIssuers>
        </issuerNameRegistry>
    </service>
</microsoft.identityModel>

Thanks in advance.


Solution

  • I managed to get the thumbprint directly from Azure and set that during Application_AuthenticateRequest. Following were the code changes in Global.asax.cs:

    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();
    
                ...
            }
    
    
    private static void ConfigureWSFederation()
            {
                // Load the federatedAuthentication settings
                WSFederationAuthenticationModule federatedModule = FederatedAuthentication.WSFederationAuthenticationModule as WSFederationAuthenticationModule;
                if (federatedModule?.ServiceConfiguration != null)
                {
                    #region Get Thumbprint from the Azure App Registration directly and and use that for WS Fed authentication, ignore the thumbprint from web.config file
    
                    //replace issuer(https://login.microsoftonline.com/tenant-id/wsfed) to get the meta address(https://login.microsoftonline.com/tenant-id/FederationMetadata/2007-06/FederationMetadata.xml)
                    var metadataAddress = federatedModule.Issuer.Replace("wsfed", "FederationMetadata/2007-06/FederationMetadata.xml");
                    var configurationManager = new ConfigurationManager<WsFederationConfiguration>(
                        metadataAddress,
                        new WsFederationConfigurationRetriever(),
                        new HttpDocumentRetriever { RequireHttps = true });
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
                    var wsFedConfig = configurationManager.GetConfigurationAsync().Result;
    
                    // Access the thumbprint from wsFedConfig object
                    var thumbprint = wsFedConfig.SigningKeys.FirstOrDefault()?.KeyId;
    
                    // Update the thumbprint in the web.config
                    if (thumbprint != null)
                    {
                        var issuer = ((Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry)federatedModule?.ServiceConfiguration?.IssuerNameRegistry).ConfiguredTrustedIssuers;
                        if (issuer != null)
                        {
                            var oldIssuer = issuer.First();
                            if (oldIssuer.Key != thumbprint.ToString())//UPDATE THMUBPRINT ONLY IF THEY ARE DIFFERENT
                            {
                                issuer.Remove(oldIssuer);
                                var newValue = new KeyValuePair<string, string>(thumbprint.ToString(), oldIssuer.Value);
                                issuer.Add(newValue);
                            }
                        }
                    }
                    #endregion
                }
                else
                {
                    Trace.TraceError("Unable to configure the federated module. The modules weren't loaded.");
                }
            }