3
votes

We want our development staff to be able to debug new code in an application which uses ADFS for authentication through the use of OWIN WS-Federation middleware. However WS-fed authentication Relying Party redirects to the Development App-server, not the local VS instance.

Configuring ADFS Relying Party trust with a multitude of localhost developer machines is off-the-table as far as organizational policy goes, so I'm left with trying to disable authentication when in DEBUG mode.

I have tried all of the following to bypass the OWIN middleware call to ADFS:

  1. Use a Custom AuthorizeAttribute as in this question such that the MVC [Authorize] attribute selectively returns a false 'true' when in DEBUG mode.
  2. Wrap the MVC Controller [Authorize] in a conditional so that it only activates in release code as in:

    namespace eim.Controllers
    {
        #if RELEASE
        [Authorize]
        #endif
    public class CoreController : Controller
    {
        // GET: Core
        public ActionResult Index()
        {
            return View();
        }
    }  }
    

Here the RELEASE compiler constant is defined in the Release Build Configuration: enter image description here

  1. When wiring up the OWIN middleware within the Startup class, Configure method, test HttpContext.Current.IsDebuggingEnabled to selectively configure app.AuthenticationOptions as in the following code snippet:

    public void ConfigureAuth(IAppBuilder app)
    {
        if (!HttpContext.Current.IsDebuggingEnabled)
        {
    
    
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
            });
    
            var audienceRestriction = new AudienceRestriction(AudienceUriMode.Never);
    
            var issuerRegistry = new ConfigurationBasedIssuerNameRegistry();
            IDictionary<string, string> trustedIssuers = issuerRegistry.ConfiguredTrustedIssuers;
    
            issuerRegistry.AddTrustedIssuer(param1, param2);
    
    
    
            //Build up Configuration variables before entering the Options
            //Create a SecurityTokenHandlerConfiguration
            SecurityTokenHandlerConfiguration ourSecurityTokenHandlerConfiguration =
                new SecurityTokenHandlerConfiguration()
                {
                    AudienceRestriction = audienceRestriction,
                    IssuerNameRegistry = issuerRegistry
                };
    
            //Create an EncryptedSecurityTokenHandlerEx
            EncryptedSecurityTokenHandlerEx ourEncryptedSecurityTokenHandlerEx =
                new EncryptedSecurityTokenHandlerEx(
                                new X509CertificateStoreTokenResolver(StoreName.My, StoreLocation.LocalMachine)
                             );
            //create a SamlSecurityTokenHandlerEx
            SamlSecurityTokenHandlerEx ourSamlSecurityTokenHandlerEx = new SamlSecurityTokenHandlerEx
            {
                CertificateValidator = X509CertificateValidator.None,
                Configuration = ourSecurityTokenHandlerConfiguration
            };
    
    
            app.UseWsFederationAuthentication(
                new WsFederationAuthenticationOptions
                {
                    Wtrealm = realm,                    //set above from AppSettings
                    MetadataAddress = adfsMetadata,     //set above from AppSettings
                    Configuration = new WsFederationConfiguration()
                    {
                        TokenEndpoint = myTokenEndpoint
                    },
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType,
                        ClientDecryptionTokens = new ReadOnlyCollection<SecurityToken>(
                            new List<SecurityToken>
                                {
                                            new X509SecurityToken(ourCertificate)
                                })
                    },
                    SecurityTokenHandlers = new SecurityTokenHandlerCollection
                        {
                                    ourEncryptedSecurityTokenHandlerEx,
                                    ourSamlSecurityTokenHandlerEx
                        }
                });
    
        };
    }
    

Results of each of these approaches is that ADFS authorization fires and reply redirects work (in otherwords the Authentication process completes) whether the app is in DEBUG or RELEASE.

Let's try to not get off-track by reviewing all the middleware configuration details, as these follow from Scott Brady's SAML decription primer here and Chris Klug's found here. All the stuff works fine except that I cannot disable it (thus far) in debug mode on local VS development environments.

1

1 Answers

2
votes

I found out what my own problem is: Using Automated Build/Release, the Conditional Compiler Constant (CCC) declared "RELEASE" in the Visual Studio configuration U.I. is not available -- i.e. CCCs do not transfer up to VSTS with the solution (or perhaps they do transfer up, but are not consumed by automated build/release.)

Therefore, in my build step, I had to re-define the CCC "RELEASE" with the syntax:

/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation="$(build.artifactstagingdirectory)\" /p:IgnoreDeployManagerRuntimeVersion=true /p:DefineConstants="RELEASE"

Of course only the last parameter is the CCC definition.

Remember that my choice of the CCC constant name "RELEASE" is arbitrary and could be "FOO" or "SERVER" or any other useful constant name.

Once that was put in place, Option #2 above works correctly in both localhost and deployed version.