Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenIdDict in ASP.NET 4.5 or alternative frameworks?

Tags:

In an old project we used ASP.NET 4.5 and I would like to use the Framework OpenIdDict in it. It's made vor ASP.NET Core 1 and 2. Can I still use it? What do I have to pay attention to? If I can't use that, which alternatives do you know?

Link to OpenIdDict: https://github.com/openiddict/openiddict-core

like image 815
dafna Avatar asked Aug 02 '18 14:08

dafna


People also ask

What is OpenIddict?

OpenIddict is an open source and versatile framework for building standard-compliant OAuth 2.0/OpenID Connect servers in any ASP.NET Core 2.1 (and higher) and legacy ASP.NET 4.6. 1 (and higher) applications. OpenIddict was born in late 2015 and was initially based on AspNet. Security.

What is the difference between a ASP.NET framework an ASP.NET Core?

. Net Core does not support desktop application development and it rather focuses on the web, windows mobile, and windows store. . Net Framework is used for the development of both desktop and web applications as well as it supports windows forms and WPF applications.

What type of framework is ASP.NET Core?

ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-enabled, Internet-connected apps. With ASP.NET Core, you can: Build web apps and services, Internet of Things (IoT) apps, and mobile backends. Use your favorite development tools on Windows, macOS, and Linux.


1 Answers

Edit: OpenIddict 3.0 is now natively compatible with OWIN/Katana and can be used in any >= ASP.NET 4.6.1 application without using any adapter. Read these two blog posts for more information:

  • Introducing OpenIddict 3.0 beta1
  • Adding OpenIddict 3.0 to an OWIN application

Technically, it's possible to use middleware designed for ASP.NET Core 1.x/2.x in an ASP.NET 4.x application by using the Microsoft.AspNetCore.Owin adapter package and some tweaking.

Here's a prototype of an OWIN self-hosted console application (it would be very similar with an ASP.NET 4.x application using the OWIN SystemWeb host):

Program.cs:

using System;
using Microsoft.Owin.Hosting;

namespace OpenIddictOwinDemo
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            const string address = "http://localhost:12556/";

            using (WebApp.Start<Startup>(address))
            {
                Console.WriteLine($"Server is running on {address}, press CTRL+C to stop.");
                Console.ReadLine();
            }
        }
    }
}

Startup.cs:

using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Owin;

namespace OpenIddictOwinDemo
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseBuilder(ConfigureServices(), Configure);
        }

        IServiceProvider ConfigureServices()
        {
            var services = new ServiceCollection();

            // In a real ASP.NET Core application, these services are
            // registered by the hosting stack. Since this application
            // is actually an OWIN app, they must be registered manually.
            var listener = new DiagnosticListener("Microsoft.AspNetCore");
            services.AddSingleton<DiagnosticListener>(listener);
            services.AddSingleton<DiagnosticSource>(listener);
            services.AddSingleton<IHostingEnvironment, HostingEnvironment>();

            services.AddDbContext<DbContext>(options =>
            {
                options.UseInMemoryDatabase("db");
            });

            services.AddOpenIddict()
                .AddCore(options =>
                {
                    options.UseEntityFrameworkCore()
                        .UseDbContext<DbContext>();
                })

                .AddServer(options =>
                {
                    options.AcceptAnonymousClients();
                    options.AllowPasswordFlow();
                    options.EnableTokenEndpoint("/connect/token");
                    options.DisableHttpsRequirement();

                    options.UseCustomTokenEndpoint();
                });

            return services.BuildServiceProvider(validateScopes: true);
        }

        void Configure(IApplicationBuilder app)
        {
            // This inline middleware is required to be able to use scoped services.
            // In a real ASP.NET Core application, this is done for you by a special
            // middleware automatically injected by the default hosting components.
            app.Use(next => async context =>
            {
                var provider = context.RequestServices;
                using (var scope = provider.CreateScope())
                {
                    try
                    {
                        context.RequestServices = scope.ServiceProvider;

                        await next(context);
                    }

                    finally
                    {
                        context.RequestServices = provider;
                    }
                }
            });

            app.UseDeveloperExceptionPage();

            app.UseAuthentication();
        }
    }
}

KatanaExtensions.cs:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.FileProviders;
using Owin;

namespace OpenIddictOwinDemo
{
    using AddMiddleware = Action<Func<
        Func<IDictionary<string, object>, Task>,
        Func<IDictionary<string, object>, Task>
    >>;
    using AppFunc = Func<IDictionary<string, object>, Task>;

    public static class KatanaExtensions
    {
        public static IAppBuilder UseBuilder(this IAppBuilder app,
            IServiceProvider provider, Action<IApplicationBuilder> configuration)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            if (provider == null)
            {
                throw new ArgumentNullException(nameof(provider));
            }

            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            AddMiddleware add = middleware =>
            {
                app.Use(new Func<AppFunc, AppFunc>(next => middleware(next)));
            };

            add.UseBuilder(configuration, provider);

            return app;
        }
    }

    public class HostingEnvironment : IHostingEnvironment
    {
        public string EnvironmentName { get; set; }
        public string ApplicationName { get; set; }
        public string WebRootPath { get; set; }
        public IFileProvider WebRootFileProvider { get; set; }
        public string ContentRootPath { get; set; }
        public IFileProvider ContentRootFileProvider { get; set; }
    }
}

OpenIddictExtensions:

using System;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Server;

namespace OpenIddictOwinDemo
{
    public static class CustomOpenIddictServerExtensions
    {
        public static OpenIddictServerBuilder UseCustomTokenEndpoint(
            this OpenIddictServerBuilder builder)
        {
            if (builder == null)
            {
                throw new ArgumentNullException(nameof(builder));
            }

            return builder.AddEventHandler<OpenIddictServerEvents.HandleTokenRequest>(
                notification =>
                {
                    var request = notification.Context.Request;
                    if (!request.IsPasswordGrantType())
                    {
                        return Task.CompletedTask;
                    }

                    // Validate the user credentials.

                    // Note: to mitigate brute force attacks, you SHOULD strongly consider
                    // applying a key derivation function like PBKDF2 to slow down
                    // the password validation process. You SHOULD also consider
                    // using a time-constant comparer to prevent timing attacks.
                    if (request.Username != "[email protected]" ||
                        request.Password != "P@ssw0rd")
                    {
                        notification.Context.Reject(
                            error: OpenIdConnectConstants.Errors.InvalidGrant,
                            description: "The specified credentials are invalid.");

                        return Task.CompletedTask;
                    }

                    // Create a new ClaimsIdentity holding the user identity.
                    var identity = new ClaimsIdentity(
                        notification.Context.Scheme.Name,
                        OpenIdConnectConstants.Claims.Name,
                        OpenIdConnectConstants.Claims.Role);

                    // Add a "sub" claim containing the user identifier, and attach
                    // the "access_token" destination to allow OpenIddict to store it
                    // in the access token, so it can be retrieved from your controllers.
                    identity.AddClaim(OpenIdConnectConstants.Claims.Subject,
                        "71346D62-9BA5-4B6D-9ECA-755574D628D8",
                        OpenIdConnectConstants.Destinations.AccessToken);
                    identity.AddClaim(OpenIdConnectConstants.Claims.Name, "Alice",
                        OpenIdConnectConstants.Destinations.AccessToken);

                    // ... add other claims, if necessary.
                    var principal = new ClaimsPrincipal(identity);
                    notification.Context.Validate(principal);

                    return Task.CompletedTask;
                });
        }
    }
}

In practice, I wouldn't recommend it as it's a bit hackish (the Microsoft.AspNetCore.Owin adapter hasn't been updated for years). Instead, you may want to adopt a micro-service architecture and move your OpenIddict-based authorization server to a separate ASP.NET Core service.

like image 114
Kévin Chalet Avatar answered Nov 03 '22 00:11

Kévin Chalet