Search code examples
asp.net-corepiranha-cms

JWT Based API + Piranha CMS HiJacks the [Authorize] Routes


Recently setup JWT for an api within a Piranha project. I can hit the login endpoint (anonymous) without Piranha hijacking the request.

When I hit an API end point (after successful auth & receiving the JWT) with the [Authorize] attribute it gets picked up always by Piranha. it attempts to redirect me to the CMS login.

Being that this is an API the redirection to a web page is not acceptable behavior. Anyway to rectify this behavior?

        var appSettingsSection = config.GetSection("AppSettings");
        services.Configure<AppSettings> (appSettingsSection);
        // configure jwt authentication
        var appSettings = appSettingsSection.Get<AppSettings> ();
        var key = Encoding.UTF8.GetBytes (appSettings.Secret); // todo - UTF8 vs ASCII?!
        services.AddAuthentication (x => {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer (x => {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey (key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });
        services.AddPiranhaApplication ();
        services.AddPiranhaFileStorage ();
        services.AddPiranhaImageSharp ();

            services.AddPiranhaEF (options =>
                options.UseSqlite ("Filename=./piranha.db"));
            services.AddPiranhaIdentityWithSeed<IdentitySQLiteDb> (options =>
                options.UseSqlite ("Filename=./piranha.db"));
        }
        services.AddPiranhaManager ();
        services.AddPiranhaMemCache ();

        services.AddMvc (config => {
                config.ModelBinderProviders.Insert (0,
                    new Piranha.Manager.Binders.AbstractModelBinderProvider ());
            }).SetCompatibilityVersion (CompatibilityVersion.Version_2_1);

--------- Update --------- With help from @hakan the following attribtute works:

[ApiController]
[Route ("api/v1/")]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class ApiController : ControllerBase {

Solution

  • The issue here is really how ASP.NET Identity is interacting with JWT. In your startup your calling:

    services.AddPiranhaIdentityWithSeed<IdentitySQLiteDb> (options =>
        options.UseSqlite ("Filename=./piranha.db"));
    

    which means that the setup uses the default options Piranha sets, some of these options are actually more geared towards development (like password strength). You can provide your own options and cookie options into the method, like so:

    services.AddPiranhaIdentityWithSeed<IdentitySQLiteDb> (options =>
        options.UseSqlite ("Filename=./piranha.db"), identityOptions, cookieOptions);
    

    The default Identity Options used are:

    // Password settings
    options.Password.RequireDigit = false;
    options.Password.RequiredLength = 6;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequireUppercase = false;
    options.Password.RequireLowercase = false;
    options.Password.RequiredUniqueChars = 1;
    
    // Lockout settings
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
    options.Lockout.MaxFailedAccessAttempts = 10;
    options.Lockout.AllowedForNewUsers = true;
    
    // User settings
    options.User.RequireUniqueEmail = true;
    

    And these are the default cookie options:

    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
    options.LoginPath = "/manager/login";
    options.AccessDeniedPath = "/manager/login";
    options.SlidingExpiration = true;
    

    Best regards

    Håkan