Skip to content
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.

InvalidOperationException: Scheme already exists: Bearer after upgrade to netcoreapp2.0 #1412

Closed
RobinHerbots opened this issue Sep 7, 2017 · 25 comments

Comments

@RobinHerbots
Copy link

Hi all,

I'm a bit stuck here and any suggestions are welcome.
I upgraded my netcoreapp1.1 to netcoreapp2.0, => after some struggle I got everything compiled.

When running after the app.UseAuthentication(); command I got the below.

I stripped down the startup to solely the authentication

services.AddAuthentication()
                .AddJwtBearer(o =>
                {
                    o.Authority =
                        $"{Configuration["Authentication:AzureAd:AADInstance"]}{Configuration["Authentication:AzureAd:TenantId"]}";
                    o.Audience = Configuration["Authentication:AzureAd:Audience"];
                });

...

   app.UseAuthentication();

InvalidOperationException: Scheme already exists: Bearer
Microsoft.AspNetCore.Authentication.AuthenticationOptions.AddScheme(string name, Action<AuthenticationSchemeBuilder> configureBuilder)
Microsoft.AspNetCore.Authentication.AuthenticationBuilder+<>c__DisplayClass4_0.<AddScheme>b__0(AuthenticationOptions o)
Microsoft.Extensions.Options.ConfigureNamedOptions.Configure(string name, TOptions options)
Microsoft.Extensions.Options.OptionsFactory.Create(string name)
Microsoft.Extensions.Options.OptionsManager+<>c__DisplayClass5_0.<Get>b__0()
System.Lazy.ViaFactory(LazyThreadSafetyMode mode)
System.Lazy.ExecutionAndPublication(LazyHelper executionAndPublication, bool useDefaultConstructor)
System.Lazy.CreateValue()
Microsoft.Extensions.Options.OptionsCache.GetOrAdd(string name, Func<TOptions> createOptions)
...
@davidfowl
Copy link
Member

I think you need to show more code. Show the entire Startup.cs file.

@RobinHerbots
Copy link
Author

@davidfowl ,

Here you go. I only stripped irrelevant parts

using System;
using System.Collections.Generic;
using System.Linq;
using AspNetIdentity.Ldap.Extensions;
using AspNetIdentity.MSGraph.Extensions;
using AutoMapper;
using IISEnvironmentSwitcher;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using Contact = Swashbuckle.AspNetCore.Swagger.Contact;

namespace .....
{
    public class Startup
    {
        private string swaggerCommentXmlPath;
        private IHostingEnvironment _hostingEnvironment;

        public Startup(IHostingEnvironment env)
        {
            env.SelectEnvironment("**********", "************");

            _hostingEnvironment = env;
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

            if (env.IsDevelopment())
            {
                builder.AddUserSecrets<Startup>();
                swaggerCommentXmlPath = $@"{env.ContentRootPath}\bin\Debug\Service.xml";
            }
            else
            {
                swaggerCommentXmlPath = $@"{env.ContentRootPath}\Service.xml";
            }

            builder.AddEnvironmentVariables();
            Configuration = builder.Build();
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var origins = new List<string>();
            Configuration.GetSection("Authentication:CORS").Bind(origins);
            var groups = new List<string>();
            Configuration.GetSection("Authorization:Groups").Bind(groups);
            // Add framework services.
            services.Configure<PostAuthenticateOptions>(Configuration.GetSection("Authentication:PostAuthenticate"));

            services.AddDbContext<IdentityDbContext>(o =>
              o.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddCors(o =>
            {
                o.AddPolicy("AllowAllOrigin",
                    builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowCredentials());
                o.AddPolicy("AllowUIOrigin",
                    builder => builder.WithOrigins(origins.ToArray()).AllowAnyMethod().AllowAnyHeader().AllowCredentials());
            });


            services.AddAuthentication(o => o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(o =>
                {
                    o.Authority =
                        $"{Configuration["Authentication:AzureAd:AADInstance"]}{Configuration["Authentication:AzureAd:TenantId"]}";
                    o.Audience = Configuration["Authentication:AzureAd:Audience"];
                });


            services.AddAuthorization(options =>
            {
                .......
            });

            services.AddMvc()
                .AddJsonOptions(o =>
                {
                    o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                    o.SerializerSettings.Converters.Add(new StringEnumConverter());
                })
                .AddMvcOptions(mo =>
                    {
                        var defaultHeaderModelBinderProvider =
                            mo.ModelBinderProviders.First(p => p is HeaderModelBinderProvider);
                        var index = mo.ModelBinderProviders.IndexOf(defaultHeaderModelBinderProvider);
                        mo.ModelBinderProviders.Remove(defaultHeaderModelBinderProvider);
                        mo.ModelBinderProviders.Insert(index, new HeaderModelBinderEx.HeaderModelBinderProvider());
                    }
                );
            services.AddApiVersioning(o =>
            {
                o.AssumeDefaultVersionWhenUnspecified = true;
                o.DefaultApiVersion = new ApiVersion(1, 0);
                o.ApiVersionReader = new HeaderApiVersionReader("api-version");
            });


            services.AddSwaggerGen(c =>
            {
                c.DocumentFilter<LowerCaseDocumentFilter>();
                c.SchemaFilter<KeyVendorExtension>();
                c.IncludeXmlComments(swaggerCommentXmlPath);
                c.DescribeAllEnumsAsStrings();
                c.DescribeStringEnumsInCamelCase();
                c.SwaggerDoc("v" + ApiVersion.Default.MajorVersion,
                    new Info
                    {
                     .......
                    });
                c.DocInclusionPredicate((docName, apiDesc) =>
                {
                    var versions = apiDesc.ControllerAttributes()
                        .OfType<ApiVersionAttribute>()
                        .SelectMany(attr => attr.Versions);

                    return versions.Any(v => $"v{v.MajorVersion}" == docName);
                });
                c.OperationFilter<AuthResponsesOperationFilter>();
                c.SchemaFilter<AutoRestSchemaFilter>();
                // Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
                c.AddSecurityDefinition("oauth2", new OAuth2Scheme
                {
                    Type = "oauth2",
                    Flow = "implicit",
                    AuthorizationUrl = $"{Configuration["Authentication:AzureAd:AADInstance"]}{Configuration["Authentication:AzureAd:TenantId"]}/oauth2/authorize",
                });
            });

            services.AddSingleton<IMapper>(AutoMapperConfiguration.Configure());

            ......
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            //clear claims mapping from Mickeysoft
            //JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
            //JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();


            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            app.UseAuthentication();
           
            app.UseCors("AllowUIOrigin");

            app.UseStaticFiles();
            app.UseMvc();

            //web api helppages
            app.UseSwagger(c =>
            {
                c.RouteTemplate = "api-docs/{documentName}/swagger.json";
            });
            app.UseSwaggerUI(c =>
            {
                c.RoutePrefix = "api-docs";
                c.SwaggerEndpoint($"v{ApiVersion.Default.MajorVersion}/swagger.json", "RIM Service");
                c.ConfigureOAuth2(
                    Configuration["Authentication:AzureAd:ClientId"],
                    Configuration["Authentication:AzureAd:ClientSecret"],
                    Configuration["Authentication:AzureAd:Audience"], //not used in AAD
                    "RIMService",
                    "",
                        new Dictionary<string, string>
                        {
                            {"resource", Configuration["Authentication:AzureAd:ClientId"]} //needed for AAD
                        }
                    );
            });

        }
    }
}

@RobinHerbots
Copy link
Author

@davidfowl ,

When I specify in the authentication some other scheme for testing like

    services.AddAuthentication(o => o.DefaultScheme = "test")
                .AddJwtBearer("test",o =>
                {
                    o.Authority =
                        $"{Configuration["Authentication:AzureAd:AADInstance"]}{Configuration["Authentication:AzureAd:TenantId"]}";
                    o.Audience = Configuration["Authentication:AzureAd:Audience"];
                });

Then I get another message

InvalidOperationException: Scheme already exists: Identity.Application
Microsoft.AspNetCore.Authentication.AuthenticationOptions.AddScheme(string name, Action<AuthenticationSchemeBuilder> configureBuilder)

Maybe this can give some clue?

@RobinHerbots
Copy link
Author

Hi @davidfowl ,

I found the problem. I has some custom middleware which uses parts of aspnet identity and there I had
services.AddIdentity<IdentityUser, ... (totally unnecessary), which causes the above.

Anyway THX for the quick response!

@x3igh7
Copy link

x3igh7 commented Sep 11, 2017

@RobinHerbots I'm seeing the same issue - what exactly did you change?

@RobinHerbots
Copy link
Author

@x3igh7 ,

As in my previous comment. I had some custom middleware which also added authentication, which causes the above error.

@wgutierrezr
Copy link

Hi
I have the same issue after the upgrade and I'm not using another middleware. Any advice, please?

@RobinHerbots
Copy link
Author

@wgutierrezr ,

Try commenting all in startup | configureservices, then uncomment until you got the error.
This will give some direction to where to look.

@wgutierrezr
Copy link

wgutierrezr commented Sep 19, 2017

Hi @RobinHerbots
I removed the lines for cookie configuration and this error disappears but I have another when running the app:
InvalidOperationException: The entity type 'IdentityUserLogin<int>' requires a primary key to be defined.

Any help, please?

@herbat73
Copy link

check if you do not have 2x services.AddIdentity... it caused this problem in my code

@jhudsoncedaron
Copy link

Got here with "Scheme already exists: Windows" with an empty Configure. I have just converted Startup to IStartup so I can pass arguments to it.

@Tratcher
Copy link
Member

@jhudsoncedaron please share your Startup code.

@jhudsoncedaron
Copy link

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Cedaron.Login.Windows
{
    public class Startup : IStartup
    {
        public Startup(IConfigurationRoot config)
        {
            Configuration = config;
        }

        public IConfigurationRoot Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddSingleton<IConfigurationRoot>(Configuration);
            services.AddMvc();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            //loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            //loggerFactory.AddDebug();

            //app.UseDeveloperExceptionPage(); // Since we don't have anything else to do...
            if (env.IsDevelopment())
            {
                //app.UseBrowserLink();
            }

            //app.UseStaticFiles();

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

        IServiceProvider IStartup.ConfigureServices(IServiceCollection services)
        {
            ConfigureServices(services);
            return services.BuildServiceProvider();
        }

        void IStartup.Configure(IApplicationBuilder app){/* we configured long ago*/}
    }
}

@Tratcher
Copy link
Member

There's no auth in that Startup. What's the full stack trace of the exception?

@jhudsoncedaron
Copy link

jhudsoncedaron commented Dec 14, 2017

System.InvalidOperationException occurred
  HResult=0x80131509
  Message=Scheme already exists: Windows
  Source=<Cannot evaluate the exception source>
  StackTrace:
   at Microsoft.AspNetCore.Authentication.AuthenticationSchemeProvider.AddScheme(AuthenticationScheme scheme) in C:\b\w\f92f3e96777ec37d\.r\HttpAbstractions\src\Microsoft.AspNetCore.Authentication.Core\AuthenticationSchemeProvider.cs:line 121


Microsoft.AspNetCore.Authentication.Core.dll!Microsoft.AspNetCore.Authentication.AuthenticationSchemeProvider.AddScheme(Microsoft.AspNetCore.Authentication.AuthenticationScheme scheme) Line 121	C#	Symbols loaded.
Microsoft.AspNetCore.Server.IISIntegration.dll!Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.IISMiddleware(Microsoft.AspNetCore.Http.RequestDelegate next, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Builder.IISOptions> options, string pairingToken, Microsoft.AspNetCore.Authentication.IAuthenticationSchemeProvider authentication, Microsoft.AspNetCore.Hosting.IApplicationLifetime applicationLifetime) Line 63	C#	Symbols loaded.
[Native to Managed Transition]		Annotated Frame
[Managed to Native Transition]		Annotated Frame
Microsoft.AspNetCore.Http.Abstractions.dll!Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(System.IServiceProvider provider) Line 294	C#	Symbols loaded.
Microsoft.AspNetCore.Http.Abstractions.dll!Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(System.IServiceProvider provider, System.Type instanceType, object[] parameters) Line 53	C#	Symbols loaded.
Microsoft.AspNetCore.Http.Abstractions.dll!Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.UseMiddleware.AnonymousMethod__0(Microsoft.AspNetCore.Http.RequestDelegate next) Line 92	C#	Symbols loaded.
Microsoft.AspNetCore.Http.dll!Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build() Line 88	C#	Symbols loaded.
Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication() Line 192	C#	Symbols loaded.
Microsoft.AspNetCore.Hosting.dll!Microsoft.AspNetCore.Hosting.WebHostBuilder.Build() Line 182	C#	Symbols loaded.
Cedaron.Login.Windows.dll!Cedaron.Login.Windows.Program.Main(string[] args) Line 27	C#	Symbols loaded.

The only auth is:

        var host = new WebHostBuilder()
            .UseHttpSys(options =>
            {
                options.Authentication.Schemes = AuthenticationSchemes.NTLM | AuthenticationSchemes.Kerberos | AuthenticationSchemes.Negotiate;
                options.Authentication.AllowAnonymous = false;
                /* I'm convinced I should not have to do this but it wouldn't work otherwise. -JH */
                foreach (var url in config.GetValue<string>("server.urls", "http://+:5002/").Split(';', StringSplitOptions.RemoveEmptyEntries))
                    options.UrlPrefixes.Add(url);
            })
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .ConfigureServices((services) =>
            {
                services.AddSingleton<IStartup>((sp) => new Startup(config));
            })
            .UseSetting(WebHostDefaults.ApplicationKey, "redacted")
            .UseApplicationInsights()
            .UseConfiguration(config)
            .Build();

@Tratcher
Copy link
Member

Ah, HttpSys cannot be used with IIS, you must use Kestrel with IIS.

@Tratcher
Copy link
Member

As for your server.urls issue, see aspnet/MetaPackages#226

@jhudsoncedaron
Copy link

I'm reading server.urls out of appsettings.json.

Back to the main issue; commenting out .UseIISIntegration() doesn't change anything.

@Tratcher
Copy link
Member

Are you trying to run this application in IIS/Express?

@jhudsoncedaron
Copy link

Nope. It wouldn't work anyway.

@jhudsoncedaron
Copy link

On further probing I found the failure happens only when starting under Visual Studio. I'm not going to say I understand this because I definitely don't.

@Tratcher
Copy link
Member

VS runs the IIS Express profile by default, you have to change your launch profile in the dropdown to launch as a console app.

@jhudsoncedaron
Copy link

Ok I managed to work everything else out from there. VS appears pretty broken after changing the setting but that might be my fault.

@Bogatinovski
Copy link

@wgutierrezr I also had and fixed the same error: InvalidOperationException: The entity type 'IdentityUserLogin<int>' requires a primary key to be defined. I got this error when I included the Logins property in my ApplicationUserClass when I followed the migration guide: public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();
What I did to fix it I just changed the ints to strings in the property definitions, so I got: public virtual ICollection<IdentityUserLogin<string>> Logins { get; } = new List<IdentityUserLogin<string>>();
The reason this error appeared is that the IdentityUser class which is inherited by the ApplicationUser entity uses a string as a primary key and in the Logins property definition I used int as per the guide.

@replaysMike
Copy link

For others that come across this error, in my case I had setup using OpenIddict and the following line caused the error for me:

services
.AddAuthentication()
.AddJwtBearer()
.AddOAuthValidation(); < -- remove this!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants