WsFederation получает сообщение об ошибке «Нет сообщения» во время обратного вызова - PullRequest
0 голосов
/ 14 июня 2019

У меня есть новое приложение .Net Core Razor, которое использует локальные учетные записи, и я пытаюсь добавить федеративную аутентификацию, используя IDP нашей компании (сервис SAML2 от Computer Associates).IDP не предоставляет MetadabaseAddress, поэтому мне приходится все настраивать вручную.Я могу нажать новую кнопку «Вход» и быть перенаправлен на страницу входа в систему IDP, и после входа в систему я перенаправлен на страницу входа в мои приложения, но там я получаю сообщение об ошибке «Нет сообщения».

Я отследил источник ошибки до класса WsFederationHandler.cs здесь , и оказалось, что обработчик не может найти токен saml, однако, используя браузерыИнструменты разработчика. Я вижу, что данные формы содержат маркер в виде (как представляется) строки в кодировке base-64.

Вот мой код:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

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

        services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                // Password settings for local accounts
                options.Password.RequireDigit = true;
                options.Password.RequiredLength = 8;
                options.Password.RequiredUniqueChars = 2;
                options.Password.RequireLowercase = true;
                options.Password.RequireNonAlphanumeric = true;
                options.Password.RequireUppercase = true;
                options.User.RequireUniqueEmail = true;
                options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@!$";
            })
            .AddEntityFrameworkStores<ApplicationContext>()
            .AddDefaultTokenProviders();

        // Creating the configuration object for WsFederation so we can access more settings
        // This is used in lieu of retrieving the MetadataBase xml file from the IDP
        var wsfConfig = new WsFederationConfiguration
        {
            TokenEndpoint = Configuration.GetValue<string>("MyAccess:TokenEndpoint"), // This is where the user gets redirected to, provided by the MyAccess team. Example: https://federatetest.smext.faa.gov/affwebservices/public/saml2sso?SPID=https://training.amc.faa.gov
            Issuer = Configuration.GetValue<string>("MyAccess:Issuer") // This is the entityId from the settings Xml file, typically the URI of the application

        };

        // Add the certificate that will be used by the IDP to sign (encrypt) the token; this way we know how to decrypt the token
        // The cert is a base64 encoded string
        wsfConfig.SigningKeys.Add(new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(Configuration.GetValue<string>("MyAccess:Certificate")))));

        services.AddAuthentication(authOptions =>
            {
                authOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                authOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                authOptions.DefaultChallengeScheme = WsFederationDefaults.AuthenticationScheme;
            })
            .AddWsFederation(WsFederationDefaults.AuthenticationScheme, "My Access", options =>
            {
                options.Configuration = wsfConfig;
                options.Wreply = Configuration.GetValue<string>("MyAccess:Reply");
                options.Wtrealm = Configuration.GetValue<string>("MyAccess:Realm");
                options.TokenValidationParameters.NameClaimType = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
                //options.SkipUnrecognizedRequests = true;
                // Uncomment if IDP requires a wct value
                //options.Events.OnRedirectToIdentityProvider = context =>
                //    {
                //        context.ProtocolMessage.Wct = DateTimeOffset.UtcNow.ToString();
                //        return Task.CompletedTask;
                //    };
            })
            .AddCookie();

        //Configure D I
        services.AddScoped<IEmployeeStore, EmployeeStore>();
        services.AddScoped<IDepartmentStore, DepartmentStore>();

        // Configure additional services
        services.AddMvc();
        // Adds a default in-memory implementation of IDistributedCache.
        services.AddDistributedMemoryCache();

        services.AddSession(options =>
        {
            // Set the session timeout
            options.IdleTimeout = TimeSpan.FromMinutes(45);
            options.Cookie.Name = ".EmployeeTracker.Session";
        });

        // This is where we define our authorization policies
        services.AddAuthorization(options =>
        {
            options.AddPolicy("EmployeeViewer", policy =>
            {
                policy.RequireAuthenticatedUser();
                policy.RequireClaim("Role", "admin");
            });
        });

        services.ConfigureApplicationCookie(options =>
        {
            // Cookie settings
            options.Cookie.HttpOnly = true;
            options.ExpireTimeSpan = TimeSpan.FromMinutes(45);

            options.LoginPath = "/Login/Login";
            options.SlidingExpiration = true;
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    // 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, UserManager<ApplicationUser> userManager)
    {
        GlobalDiagnosticsContext.Set("configDir", Configuration.GetSection("AppSettings")["NLogDir"]);
        GlobalDiagnosticsContext.Set("connectionString", Configuration.GetConnectionString("DefaultConnection"));

        if (env.IsDevelopment())
        {
            // Only enable BrowserLink if it's really needed.  It's a resource hog.
            //app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            // Configure security settings
            app.UseXContentTypeOptions(); // sets the X-Content-Type-Options to no-sniff
            app.UseReferrerPolicy(opts => opts.NoReferrer());
            app.UseXXssProtection(options => options.EnabledWithBlockMode());
            app.UseXfo(options => options.Deny()); // Block iframes
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts(hsts => hsts.MaxAge(1).IncludeSubdomains());
        }

        // Configure middleware
        app.UseAuthentication();
        app.UseStaticFiles();
        app.UseStatusCodePagesWithReExecute("/Status{0}"); // Status403.cshtml, Status404.cshtml, etc.
        app.UseCookiePolicy();
        app.UseSession();
        app.UseMvc();
    }
}

Вот что яв инструментах разработчика: Screen shot of form data in developer tools

Поскольку мне приходится настраивать вещи вручную, из этого следует, что я что-то упустил.Кроме того, просто чтобы подтвердить свои подозрения, я добавил опцию в SkipUnrecognizedRequests и получил другую ошибку.

TIA для любой помощи, которую вы можете предоставить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...