2

I have an Identity Server 4 solution with EF Identity DB. I can login with my email and external gmail account, but when I try to login using OpenID (User name and Password) I receive the error below. The issue maybe with the info stored in the Identity DB tables. I'm new to Identity Server and this is my first attempt working with EF Identity DB. I can post DB info if it helps resolve the issue.

Source code: https://github.com/gotnetdude/GotNetDude-PublicRepository/tree/master/AuthServer

Identity Server Log File: https://github.com/gotnetdude/GotNetDude-PublicRepository/blob/master/AuthServer_log.txt

MVC Client Log: https://github.com/gotnetdude/GotNetDude-PublicRepository/blob/master/MVCClient_log.txt

Here is the AuthServer Startup code where I add oidc mvc client as the challenge option ("OpenID Connect") which is fail. The MVC client works fine if I login with the email credentials. I guess is that this has some to do with the way the scope is being handled on the mvc client. Any suggestion are appreciated.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using AuthServer.Data;
using AuthServer.Models;
using AuthServer.Services;
using System.Reflection;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Extensions.Logging;

namespace AuthServer
{
    public class Startup
    {
        #region "Startup"
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        #endregion

        #region "ConfigureServices"
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();

            // Add application services.
            services.AddTransient<IEmailSender, EmailSender>();

            services.AddMvc();

            string connectionString = Configuration.GetConnectionString("DefaultConnection");
            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            // configure identity server with in-memory stores, keys, clients and scopes
            services.AddIdentityServer()
                .AddDeveloperSigningCredential()
                .AddAspNetIdentity<ApplicationUser>()
                // this adds the config data from DB (clients, resources)
                .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                // this adds the operational data from DB (codes, tokens, consents)
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = builder =>
                        builder.UseSqlServer(connectionString,
                            sql => sql.MigrationsAssembly(migrationsAssembly));

                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    options.TokenCleanupInterval = 15; // interval in seconds. 15 seconds useful for debugging
                });

            services.AddAuthentication()
                .AddGoogle("Google", options =>
                {
                    options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com";
                    options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo";
                })
                //.AddOpenIdConnect("oidc", "OpenID Connect", options =>
                //{
                //    //options.Authority = "https://demo.identityserver.io/";
                //    //options.ClientId = "implicit";
                //    //options.SaveTokens = true;
                .AddOpenIdConnect("oidc", "OpenID Connect", options =>
                {
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;
                    options.SaveTokens = true;
                    options.ClientId = "mvc";
                    //options.Scope.Add("api1.APIScope");
                    //options.Scope.Add("api1.IdentityScope");
                    //options.Scope.Add("openid");
                    //options.GetClaimsFromUserInfoEndpoint = true;
                    //options.Scope.Add("email");
                    //options.Scope.Add("profile");
                    //options.Scope.Add("offline_access");

                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = "name",
                        RoleClaimType = "role"
                    };
                });
        }
        #endregion

        #region "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)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseBrowserLink();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();

            // app.UseAuthentication(); // not needed, since UseIdentityServer adds the authentication middleware
            app.UseIdentityServer();

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

After working with the AccountService, BuildLoginViewModelAsync method for awhile, I came to the realization that the email login and the user id login are both using OpenId. I decided that rather than challenging with another OpenId for the user id that I would update the account controller sign in manager passwordsigninasync method:

//var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, lockoutOnFailure: false);

I also updated the login view:

   

 <div class="form-group">
      @*<label asp-for="Email"></label>
        <input asp-for="User" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>*@
    <label asp-for="Username"></label>
    <input asp-for="Username" class="form-control" />
    <span asp-validation-for="Username" class="text-danger"></span>
    </div>

I also updated the InputViewModel:

public class LoginViewModel
    {
        [Required]
        //[EmailAddress]
        //public string Email { get; set; }
        public string Username { get;  set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Display(Name = "Remember me?")]
        public bool RememberMe { get; set; }
        //public object Username { get; internal set; }
        public object RememberLogin { get; internal set; }
        public string Email { get; internal set; }
    }

Lastly I removed the OpenID Connect challenge for the Authority startup class.

After making the above listed changes, I'm able to login with the EF Identity DB Username rather than the email using OpenID. For my purposes this is good enough of a solution. I appreciate all the contributions feel free to leave me any comments. Paul

Paul
  • 93
  • 2
  • 11
  • Are those real keys in your example code? – ti7 Jan 30 '18 at 23:12
  • @ti7 You mean the Google client? It's from a sample: https://github.com/IdentityServer/IdentityServer4.Samples/blob/release/Quickstarts/5_HybridFlowAuthenticationWithApiAccess/src/QuickstartIdentityServer/Startup.cs –  Jan 31 '18 at 01:05
  • No, the OpenId connect challenge... This post was demonstrating that the optional challenge in the authority server was correct. The problem appears to be with the commented out code in the AccountService class BuildLoginViewModelAsync methods. See my comments above. This code is also sample code, but was commented out. I'm trying to get the user login openid to work. The goal is to import the ldap user id information into the authority server for single sign in. – Paul Jan 31 '18 at 14:14

1 Answers1

0

As I told you in your previous question - start by getting the service and controller back to default. Then - remove this:

.AddOpenIdConnect("oidc", "OpenID Connect", options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.SaveTokens = true;
                options.ClientId = "mvc";
                //options.Scope.Add("api1.APIScope");
                //options.Scope.Add("api1.IdentityScope");
                //options.Scope.Add("openid");
                //options.GetClaimsFromUserInfoEndpoint = true;
                //options.Scope.Add("email");
                //options.Scope.Add("profile");
                //options.Scope.Add("offline_access");

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                };
            }

from your IdentityServer configuration and debug the AccountService.cs and the AccountController.cs. The fact, that you have in your DataBase configurations allowing local login for your clients, doesn't make this certain true. In the code there is also logic for this, before the client gets to the authorize endpoint, and may be there something is not OK.

So 3 steps - revert back to original code, remove the code that confuses Identity server, and - debug.

m3n7alsnak3
  • 3,026
  • 1
  • 15
  • 24
  • Please see the update I made to the original post. I messed around with the AccountController code all morning and part of yesterday with no success. It wasn't as simple as just uncomment and debugging. It would have been nice to be able to switch between the default openid connection (email) and the challenge openid connection (userid), but I have to be conscious as to the mount of effort it will take to get it working. It's probably more than I can spend on it right now. – Paul Jan 31 '18 at 17:09
  • Well honestly I can't offer a better solution. The code is a mess. You either start from scratch and use the default configuration (and copy the things from your code that work), or you waste even more time trying to fix this. – m3n7alsnak3 Jan 31 '18 at 17:15