Search code examples
c#asp.net-coreoauth-2.0asp.net-core-2.0pingfederate

ASP .NET Core 2.0 - JWT External Auth


I am trying to get started with authentication on an ASP.NET Core 2.0 web app.

My company is using Ping Federate and I am trying to authenticate my users using the company login page and in return validating the returned token using my signing key (X509SecurityKey down here).

The login page link looks like:

https://companyname.com/authorization.oauth2?response_type=code&redirect_uri=https%3a%2f%2fJWTAuthExample%2fAccount%2fLogin&client_id=CompanyName.Web.JWTAuthExample&scope=&state=<...state...>

Out of the box, I configured the Startup.cs to be able to log in and challenge against this site.

I decorated my HomeController with a [Authorize(Policy="Mvc")] but when I access one of the pages, I just get a blank page.

Debug is not hitting the OnChallenge or OnAuthenticationFailed methods when I add it to options.Events (I think because user needs to be authenticated first).

So, what am I missing in order for a redirect to my authentication website to happen? Is it built in or do I have to do some manual configuration?

(Note: In other web apps, using asp net framework, I use a redirect in an Authorize attribute when authentication fails)

Related post: Authorize attribute does not redirect to Login page when using .NET Core 2's AddJwtBearer - From this post, does it mean I am not using the right authentication method? I am building a web app, not an API.

namespace JWTAuthExample
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            HostingEnvironment = hostingEnvironment;

            string certificatepath = Path.Combine(HostingEnvironment.ContentRootPath, $"App_Data\\key.cer");
            KEY = new X509SecurityKey(new X509Certificate2(certificatepath));
        }

        public IConfiguration Configuration { get; }
        public IHostingEnvironment HostingEnvironment { get; }
        private string AUTH_LOGINPATH { get; } = Configuration["DefaultAuth:AuthorizationEndpoint"];
        private X509SecurityKey KEY { get; }


        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
                {
                    options.IncludeErrorDetails = true;
                    options.SaveToken = true;
                    options.TokenValidationParameters = new TokenValidationParameters
                    {   
                        // Ensure token expiry
                        RequireExpirationTime = true,
                        ValidateLifetime = true,
                        // Ensure token audience matches site audience value
                        ValidateAudience = false,
                        ValidAudience = AUTH_LOGINPATH,
                        // Ensure token was issued by a trusted authorization server
                        ValidateIssuer = true,
                        ValidIssuer = AUTH_LOGINPATH,
                        // Specify key used by token
                        RequireSignedTokens = true,
                        IssuerSigningKey = KEY
                    };
                });

            services.AddAuthorization(options =>
            {
                options.AddPolicy("Mvc", policy =>
                {
                    policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
                    policy.RequireAuthenticatedUser();                    
                });
            });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Solution

  • Following Brad's suggestion,

    Here is a sample of code to perform an OpenId Connect confirguration on ASP NET 2.0

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect(options =>
        {
            options.Authority = Configuration["AuthoritySite"];
            options.ClientId = Configuration["ClientId"];
            options.ClientSecret = Configuration["ClientSecret"];
            options.Scope.Clear();
            // options.Scope.Add("Any:Scope");
            options.ResponseType = OpenIdConnectResponseType.CodeIdTokenToken;
            options.SaveTokens = true;
    
            options.GetClaimsFromUserInfoEndpoint = true;
    
            options.TokenValidationParameters = new TokenValidationParameters
            {
                // Compensate server drift
                ClockSkew = TimeSpan.FromHours(12),
                // Ensure key
                IssuerSigningKey = CERTIFICATE,
    
                // Ensure expiry
                RequireExpirationTime = true,
                ValidateLifetime = true,                    
    
                // Save token
                SaveSigninToken = true
            };                
    
        });
    
        services.AddAuthorization(options =>
        {
            options.AddPolicy("Mvc", policy =>
            {
                policy.AuthenticationSchemes.Add(OpenIdConnectDefaults.AuthenticationScheme);
                policy.RequireAuthenticatedUser();
            });
        });
    }
    

    More details here: https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x?view=aspnetcore-2.1