Mono with Owin Authentication

I have an Owin application that I run in Mono and am trying to authenticate on it. I used the information in this page as a start. I quickly realized that Owin Authentication uses some specific Windows libraries. This question had a workaround for this, although it seemed to me that was enough. This is not true.

The following code throws an exception described in another question (in a different place than the question describes (see the comment in the code)). If I try to comment on material to detect errors related to the Owin pipeline, it gets called (due to dependencies). If I comment enough to remove this first exception, it will appear again.

Has anyone successfully configured authentication in Owin (using AspNet Identity) in Mono?

Enter

public void Configure(IAppBuilder app)
{
    // Add the AspNet Identity user manager to the Owin context
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

    // This was the first line to fail, but adding the AesDataProtectorProvider as
    // described in the referred question fixed that
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/login"),
        Provider = new CookieAuthenticationProvider
        {
            OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
        },
        TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
            DataSerializers.Ticket,
            new AesDataProtectorProvider("myAuthKey"),
            TextEncodings.Base64)
    });

    // This causes an exception complaining that the Windows only assembly
    // DpapiDataProtector can't be loaded, as described in the referred question
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

    // Set up the custom middleware as described in the first link
    // Something inside this causes other exceptions.
    app.Use(typeof(AuthMiddleware), app, new AuthOptions());
}

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions>
{
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options)
        : base(next, options)
    {
        if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
        {
            options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
        }
        if (options.StateDataFormat == null)
        {
            var dataProtector = app.CreateDataProtector(typeof(AuthMiddleware).FullName,
            options.AuthenticationType);
            options.StateDataFormat = new PropertiesDataFormat(dataProtector);
        }
    }

    protected override AuthenticationHandler<AuthOptions> CreateHandler()
    {
        return new AuthHandler();
    }
}

Authoptions

public class AuthOptions : AuthenticationOptions
{
    public AuthOptions()
        : base("MyApp")
    {
        Description.Caption = "MyApp";
        // Where to redirect requests if not authenticated
        CallbackPath = new PathString("/login");            AuthenticationMode = AuthenticationMode.Passive;
    }

    public PathString CallbackPath { get; set; }
    public string SignInAsAuthenticationType { get; set; }
    public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
}

Authhandler

public class AuthHandler : AuthenticationHandler<AuthOptions>
{
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        var identity = new ClaimsIdentity(Options.SignInAsAuthenticationType);
        var properties = Options.StateDataFormat.Unprotect(Request.Query["state"]);
        return Task.FromResult(new AuthenticationTicket(identity, properties));
    }

    protected override Task ApplyResponseChallengeAsync()
    {
        if (Response.StatusCode == 401)
        {
            var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                var state = challenge.Properties;
                if (string.IsNullOrEmpty(state.RedirectUri))
                {
                    state.RedirectUri = Request.Uri.ToString();
                }
                var stateString = Options.StateDataFormat.Protect(state);
                Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString));
            }
        }
        return Task.FromResult<object>(null);
    }

    public override async Task<bool> InvokeAsync()
    {
        Request.Environment.Add("Context", Context);

        // If user is not logged in and tries to access any page that is not in
        // the list of allowed pages, redirect to login page
        if (Context.Authentication.User == null && 
            !Request.Path.ToString().StartsWith("/login"))
        {
            Response.Redirect(Options.CallbackPath.Value);
            return true;
        }

        return false;
    }
}
+2
source share
4 answers

Apparently, the above code includes more than necessary to get Owin authentication to work (and which does not work with Mono). Having studied and tried many permutations, I am sure that I now have authentication in working condition. I do not know if this condition is correct, but so far it works ...

, ( public override async Task<bool> InvokeAsync() AuthHandler) , . ApplicationUserManager . , Owin, .

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(30),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
    },
    TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
        DataSerializers.Ticket,
        new AesDataProtectorProvider("myAuthKey"),
        TextEncodings.Base64)
});

app.Use(typeof(AuthMiddleware), app, new AuthOptions());

AuthMiddleware

public class AuthMiddleware : AuthenticationMiddleware<AuthOptions>
{
    public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options)
        : base(next, options)
    {
        if (options.StateDataFormat == null)
        {
            options.StateDataFormat = new PropertiesDataFormat(new AesDataProtectorProvider("myAuthKey"));
        }
    }

    protected override AuthenticationHandler<AuthOptions> CreateHandler()
    {
        return new AuthHandler();
    }
}

AuthHandler

public class AuthHandler : AuthenticationHandler<AuthOptions>
{
    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
    {
        // This method never gets called in the current setup,
        // but it is required because the compilation fails otherwise.
        // Therefore only return an empty object.
        return Task.FromResult<AuthenticationTicket>(null);
    }

    protected override Task ApplyResponseChallengeAsync()
    {
        if (Response.StatusCode == 401)
        {
            var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
            if (challenge != null)
            {
                var state = challenge.Properties;
                if (string.IsNullOrEmpty(state.RedirectUri))
                {
                    state.RedirectUri = Request.Uri.ToString();
                }
                var stateString = Options.StateDataFormat.Protect(state);
                Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString));
            }
        }
        return Task.FromResult<object>(null);
    }

    public override async Task<bool> InvokeAsync()
    {
        // If user is not logged in and tries to access any page that is not in
        // the list of allowed pages, redirect to login page.
        // Add any additional pages not protected by authentication here
        if (Context.Authentication.User == null && 
            !Request.Path.ToString().StartsWith("/login"))
        {
            Response.Redirect(Options.CallbackPath.Value);
            return true;
        }

        return false;
    }
}
0

GitHub Mono WebAPI, OAuth2, AspNet.Identity + UserStore:

https://github.com/shturm/mono-webapi

enter image description here enter image description here

:

  • AspNet.Identity - (Microsoft.AspNet.Identity.Core) (Microsoft.AspNet.Identity.EntityFramework/Owin), .
  • AspNet.Identity /. , , , , .
  • AspNet.Identity UserManager ( Microsoft.AspNet.Identity.Core) SignInManger ( Microsoft.AspNet.Identity.Owin). SignInManager - OWIN.
  • , , Microsoft.Owin AspNet.Identity, ApplicationUserManager, Visual Studio Microsoft.AspNet.Identity.UserManager.
+1

Owin , Mono .

pull mono https://github.com/mono/mono/pull/3048. -api-.

Owin Authentication .

0

, OP, , , .NET Core.

Mono, Mod-Mono Apache , regenerateIdentity Mono, VS.

(startup.auth.cs)

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
   LoginPath = new PathString("/Account/Login"),
   Provider = new CookieAuthenticationProvider
   {  
       OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
           validateInterval: TimeSpan.FromMinutes(2),
           regenerateIdentity: (manager, user) => AuthenticationService.RefreshIdentityAsync(manager, user))
   }
});

Chrome Dev Tools ( ) , cookie , 2 .

, "Expires" cookie , . cookie, Mono cookie . , , , .

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
   AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
   LoginPath = new PathString("/Account/Login"),
   ExpireTimeSpan = TimeSpan.FromMinutes(2),
   SlidingExpiration = false,
   Provider = new CookieAuthenticationProvider
   {
       OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
           validateInterval: TimeSpan.FromMinutes(2),
           regenerateIdentity: (manager, user) => AuthenticationService.RefreshIdentityAsync(manager, user))
   }
});
0

Source: https://habr.com/ru/post/1623051/


All Articles