0

I'm having a hard time getting this to work. Currently I already have got an IdentityServer4, an Angular2SPA and a WebAPI 2.2 for ODATA running. All services are running in individual projects on asp.net core.

  • IdentityServer4
  • Angular2SPA
  • WebAPI2.2 .core targeting .Net462

The WebAPI runs fine as long as i dont try to connect it to the IdentityServer. I have verified that my setup, beside the WebAPI, works correctly. I have also tested the WebAPI connection configuration with the IdentityServer3.Samples on Github by connecting their WebAPISample with my IdentityServer.

WebAPI

Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        //services.AddAuthorization();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(LogLevel.Debug);
        loggerFactory.AddDebug();

        app.UseOwinApp(owinApp =>
        {
            if (env.IsDevelopment())
            {
                owinApp.UseErrorPage(new ErrorPageOptions()
                {
                    ShowCookies = true,
                    ShowEnvironment = true,
                    ShowExceptionDetails = true,
                    ShowHeaders = true,
                    ShowQuery = true,
                    ShowSourceCode = true
                });
            }

            owinApp.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

            HttpConfiguration config = new HttpConfiguration();

            JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();

            owinApp.UseCookieAuthentication(new CookieAuthenticationOptions());
            owinApp.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://authentication.bl.at:5000",
                RequiredScopes = new[] { "bl.API" },
                //ValidationMode = ValidationMode.ValidationEndpoint,
                //DelayLoadMetadata = true,

                //// client credentials for the introspection endpoint
                ClientId = "bl.API",
                ClientSecret = "secret"
            });


            WebAPIConfig.Register(config);


            ODataModelBuilder odataMetadataBuilder = new ODataConventionModelBuilder();
            odataMetadataBuilder.EntitySet<Product>("Products");
            config.MapODataServiceRoute(
                routeName: "ODataRoute",
                routePrefix: "odata",
                model: odataMetadataBuilder.GetEdmModel());
            owinApp.UseWebApi(config);
        });
    }
}

OwinExtensions.cs

public static class OwinExtensions
{
    public static IApplicationBuilder UseOwinApp(this IApplicationBuilder aspNetCoreApp, Action<IAppBuilder> configuration)
    {
        return aspNetCoreApp.UseOwin(setup => setup(next =>
        {
            AppBuilder owinAppBuilder = new AppBuilder();

            IApplicationLifetime aspNetCoreLifetime = (IApplicationLifetime)aspNetCoreApp.ApplicationServices.GetService(typeof(IApplicationLifetime));

            AppProperties owinAppProperties = new AppProperties(owinAppBuilder.Properties);

            owinAppProperties.OnAppDisposing = aspNetCoreLifetime?.ApplicationStopping ?? CancellationToken.None;

            owinAppProperties.DefaultApp = next;

            configuration(owinAppBuilder);

            return owinAppBuilder.Build<Func<IDictionary<string, object>, Task>>();
        }));
    }
}

WebAPIConfig.cs

public class WebAPIConfig
{
    public static void Register(HttpConfiguration config)
    {

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
        jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    }
}

Exceptions

The WebAPI works as expected as long as oauth is disabled, when it's enabled it throws the following exception on startup:

Unbehandelte Ausnahme: System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
   bei IdentityServer3.AccessTokenValidation.DiscoveryDocumentIssuerSecurityTokenProvider..ctor(String discoveryEndpoint, IdentityServerBearerTokenAuthenticationOptions options, ILoggerFactory loggerFactory)
   bei Owin.IdentityServerBearerTokenValidationAppBuilderExtensions.<>c__DisplayClass9.<ConfigureLocalValidation>b__8()
   bei System.Lazy`1.CreateValue()
   bei System.Lazy`1.LazyInitValue()
   bei Owin.IdentityServerBearerTokenValidationAppBuilderExtensions.UseIdentityServerBearerTokenAuthentication(IAppBuilder app, IdentityServerBearerTokenAuthenticationOptions options)
   bei WebAPI.Startup.<>c__DisplayClass1_0.<Configure>b__0(IAppBuilder owinApp) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Startup.cs:Zeile 78.
   bei WebAPI.Config.OwinExtensions.<>c__DisplayClass0_0.<UseOwinApp>b__1(Func`2 next) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Config\OwinExtensions.cs:Zeile 29.
   bei Microsoft.AspNetCore.Builder.OwinExtensions.<>c__DisplayClass0_1.<UseOwin>b__1(RequestDelegate next1)
   bei Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
   bei Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   bei Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   bei WebAPI.Program.Main(String[] args) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Program.cs:Zeile 21.

I have also tried enabling delayLoadMetadata but this throws the following exception:

Unbehandelte Ausnahme: System.Reflection.TargetInvocationException: Ein Aufrufziel hat einen Ausnahmefehler verursacht. ---> System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
   bei IdentityServer3.AccessTokenValidation.IdentityServerBearerTokenValidationMiddleware..ctor(Func`2 next, IAppBuilder app, IdentityServerOAuthBearerAuthenticationOptions options, ILoggerFactory loggerFactory)
   bei lambda_method(Closure , Func`2 , IAppBuilder , IdentityServerOAuthBearerAuthenticationOptions , ILoggerFactory )
   --- Ende der internen Ausnahmestapelüberwachung ---
   bei System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   bei System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   bei System.Delegate.DynamicInvokeImpl(Object[] args)
   bei Microsoft.Owin.Builder.AppBuilder.BuildInternal(Type signature)
   bei Microsoft.Owin.Builder.AppBuilderExtensions.Build[TApp](IAppBuilder builder)
   bei WebAPI.Config.OwinExtensions.<>c__DisplayClass0_0.<UseOwinApp>b__1(Func`2 next) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Config\OwinExtensions.cs:Zeile 31.
   bei Microsoft.AspNetCore.Builder.OwinExtensions.<>c__DisplayClass0_1.<UseOwin>b__1(RequestDelegate next1)
   bei Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()
   bei Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()
   bei Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   bei WebAPI.Program.Main(String[] args) in C:\Users\User\Documents\visual studio 2015\Projects\TestProject\src\WebAPI\Program.cs:Zeile 21.

I think this issue might be related to .Core/Owin dependency injection of ILoggerFactory. Might be a lifespan issue between these two?

Nurfed
  • 139
  • 3
  • 13
  • Is the well known endpoint under https://authentication.bl.at:5000 working? Check by open it in browser – Ming Apr 05 '17 at 07:22
  • Yes, i have verified that the authentication server works correctly. I can login with my ng2-Frontend and I am receiving an accesstoken. The Webapi throws the error on startup, I dont think it is a configuration issue, I believe it has something to do with mixing the frameworks. – Nurfed Apr 05 '17 at 10:39

2 Answers2

0

Exceptions that you got before and after enabled DelayLoadMetadata are different, one is from constructor of DiscoveryDocumentIssuerSecurityTokenProvider while another is from constructor of IdentityServerBearerTokenValidationMiddleware

If you have a look at the implementation of UseIdentityServerBearerTokenAuthentication, you would see both modules depend on loggerFactory which gets from IApplicationBuilder by this line

        var loggerFactory = app.GetLoggerFactory();

I am not a .net core expert, but the way how you use UseOwin extension method looks a bit strange to me, where you have a new instance of AppBuilder inside your owin pipeline instead of using the existing one - aspNetCoreApp, my guess is there is no logger factory registered with the new instance of AppBuilder, therefore when it is needed in modules in IdentityServer3, it blows up with object is null exception.

You can easily find out by setting a breakpoint before call into IdentityServerBearerTokenValidationMiddleware and manualy executes owinAppBuilder.GetLoggerFactory() in Immediate debug window to see if it returns anything

Ming
  • 730
  • 2
  • 8
  • 23
0

I run into the same issue, and i also tried it with the DelayLoadMetadata = true option without any success.

To solve this problem i needed to set a default logger with app.SetLoggerFactory, before you call app.UseIdentityServerBearerTokenAuthentication(GetOptions()); To do this you might need to ad

using Microsoft.Owin.Logging;

to your using’s and maybe add the assembly reference, this will add the SetLoggerFactory method to the app object. (it´s an extension). In my case i´ve done it just with the default logger like this:

app.SetLoggerFactory(Microsoft.Owin.Logging.LoggerFactory.Default);
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
    //some stuff
    });
);
Salmakis
  • 226
  • 3
  • 7