I have tried a plethora of solutions over the course of 2 days and still have not been able to get this to work. What I want is for a user cookie to expire after a set amount of time
E.g. User A logs in and goes to home page, User A goes for a lunch break. User A comes back and clicks on the nav bar and gets redirected to the login page.
I have tried everything from AddAuthentication(), AddSession() and AddCookie() options all having an ExpireTimeSpan and Cookie.Expiration of my choosing. Nothing seems to work. The project uses ASP.NET Identity and I am aware this service should be called before the cookie options. Please see my current StartUp.cs below, this is the last thing i tried:
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public IContainer ApplicationContainer { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
})
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
//other services e.g. interfaces etc.
services.AddAuthentication().AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromSeconds(60);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/AccessDenied";
options.ExpireTimeSpan = TimeSpan.FromSeconds(5);
options.SlidingExpiration = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//services.AddSession();
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(services);
this.ApplicationContainer = containerBuilder.Build();
var serviceProvider = new AutofacServiceProvider(this.ApplicationContainer);
return serviceProvider;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.ConfigureCustomExceptionMiddleware();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
//app.UseSession();
app.UseMvc();
}
}
The following code isn't affecting the Identity cookie:
services.AddAuthentication().AddCookie(options => ...);
Instead, it's adding a new cookie-based authentication scheme, named Cookies, and configuring that. With all the standard Identity setup, this scheme is unused, so any changes to its configuration will have no effect.
The primary authentication scheme used by Identity is named Identity.Application and is registered inside of the AddIdentity<TUser, TRole> method in your example. This can be configured using ConfigureApplicationCookie. Here's an example:
services.ConfigureApplicationCookie(options => ...);
With that in place, the cookie options will be affected as intended, but in order to set a cookie with a non-session lifetime, you also need to set isPersistent to true inside your call to PasswordSignInAsync. Here's an example:
await signInManager.PasswordSignInAsync(
someUser, somePassword, isPersistent: true, lockoutOnFailure: someBool);
Related
hello community I have a project created with asp.net core, blazor webassembly and Identity4, the local project works very well, I published it on an IIS server so that it could be seen from the internet, the project was loaded perfectly, the only detail is that when I enter the login it is loading, until I give it to empty cache and load in a forced way, I can enter the login form, then I enter my credentials and again it stays loading until I empty the cache again and enter the page that indicates I'm already logged in.
How can I enter the login form without emptying the cache and loading
forcefully?
When I click the login button, it sends me to this route but it's wrong:
connect/authorize?client_id=BlazorApp.Client&redirect_uri=https%3A%2F%2
this is the route that is fine to take me:
Identity/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id
this is my class startup:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SimulexContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("SimulexConnection")));
services.AddDefaultIdentity<ApplicationUser>(options => {
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddProfileService<IdentityProfileService>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.Configure<PayPalConfiguration>(Configuration.GetSection("PayPal"));
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAutoMapper(typeof(Startup));
services.AddScoped<NotificacionesService>();
services.AddScoped<IAlmacenadorDeArchivos, AlmacenadorArchivosLocal>();
services.AddHttpContextAccessor();
services.AddMvc().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/api/config/notificacionesllavepublica", async context =>
{
var configuration = context.RequestServices.GetRequiredService<IConfiguration>();
var llavePublica = configuration.GetValue<string>("notificaciones:llave_publica");
await context.Response.WriteAsync(llavePublica);
});
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
this is my page appsettingsjson:
"IdentityServer": {
"Key": {
"Type": "Development"
},
"Clients": {
"BlazorApp.Client": {
"Profile": "IdentityServerSPA"
}
}
},
Can you share your startup for the blazor app?
I had the same issue a couple weeks ago but with an asp.net mvc app when integrating is4 with which had identity configured. So it could be same for you.
Enet's solution might work, but I have not tried it. Below is another solution which worked for me only if you have Identity configured in your Blazor app. Try setting the schemes in your services.AddAuthentication and AddOpenIdConnect:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "Oidc";
options.DefaultAuthenticateScheme = "Cookies"; // <-- add this line
})
.AddCookie("Cookies", options =>
{
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies"; // <-- add this line
})
;
I am a MVC5 newbie, creating a test web Site to look at MVC5 and Razor
I have a very simple site after user logs on and I need to change menus via _Layout from "Login" to add "Logout" "Account".
Note: The site is has its own authentication, I will look at single login later.
I am really struggling with managing session data in MVC5, not sure which is the best approach. I have tried TEMP DATA , but although I peak I have found that after user has been redirected between a couple of pages the data is lost. So looked at good old cookie, but since GDPR I can tell there is a lot less default support for cookies out of the box.
Anyway in the Startup I believe I am doing all the right things
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set session timeout value
options.IdleTimeout = TimeSpan.FromSeconds(30);
options.Cookie.HttpOnly = true;
});
}
services.AddMvc();
services.AddCaching();
services.AddSession();
services.AddHttpContextAccessor();
dependency inject it in , but in the Post when I attempt to call the SetString , the "private readonly IHttpContextAccessor _httpContextAccessor;" is null
Oddly the _Layout is not throwing same null exception
#using Microsoft.AspNetCore.Http
#inject IHttpContextAccessor HttpContextAccessor
#{
string UserId = HttpContextAccessor.HttpContext.Session.GetString("UserId");
}
After working on ASP.Net , the simple approach to handling Session , beginning to question whether I have missed something as it seems a lot of work in MVC5. So should I be using a different approach in MVC5
Just want to add this this for anyone else , probably not the cleanest code
With help form Sanjay now got a crude site up and running
Startup class , example code
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddHttpContextAccessor();
services.AddRazorPages();
services.AddRazorPages();
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(30);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
}
}
Code for .csHtml
#using Microsoft.AspNetCore.Http;
#inject IHttpContextAccessor HttpContextAccessor
#{
if (Context.Session.GetString("UserRole") != null)
{
code for .cs
private readonly IHttpContextAccessor HttpContextAccessor;
public LoginModel(ISiteUserService siteUserService,
IHttpContextAccessor httpContextAccessor)
{
this.HttpContextAccessor = httpContextAccessor;
}
public IActionResult OnGet()
{
if(HttpContextAccessor.HttpContext.Session.GetString("UserRole")!= null)
{
Set
options.CheckConsentNeeded = context => false;
this to true i.e
options.CheckConsentNeeded = context => true;
and your session will not be null anymore.
I'm developing an ASP.NET Core 2.2 web application. I want to store user claims in application memory, not in cookies.
I add AddDistributedMemoryCache, AddSession and UseSession as described here, but when page is requested, I still see cookie data sent to server and received from the server.
My Startup class:
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.AddDistributedMemoryCache();
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
// Make the session cookie essential
options.Cookie.IsEssential = true;
});
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddDefaultUI(UIFramework.Bootstrap4)
.AddEntityFrameworkStores<ApplicationDbContext>();
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)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc();
}
}
Cookie data:
cookie: .AspNet.Consent=yes; .AspNetCore.Antiforgery.WGD7B_OvtEU=CfDJ8K-fe5FucclFpIYHgLvWwKY0RPLnAZQX6JnN1muQjDbx0UK4C310gp8L2RHdWlsHmoYJihQxtGuUB5GNG742rl7N-UgTynSNz09Jsb11kVgRcxAgQk5yaZnbcaQGQ0tiJUCoKAdwxEgykc2Fc3-vVCY; .AspNetCore.Identity.Application=CfDJ8K-fe5FucclFpIYHgLvWwKaod7oR4502P-cppU0aQI_WYHsvaTEL-Y5Ca1hnJOBznUpadpPkq5ubrH04UhMBpXTnK1ASjuMXMPBhr3PKqPSnXPYPFmhgki1_RicCVDQyl7mRYuWPUY2RjVkgoEIXCBj96zCRK9PWZo0N6N4hAETl-z0LAExj1Sjo6Xz3uWvHsg5GtJijlQmE6BjSh0ObMulxgDFJZEw13IbWJmlLFv7kdvs9va59wBPlEhHFER1Rs0iKW2cpVqQTPK7SjgQrSlo8_KQYHWzYa3xFSjuhrWJnm-Y4u9jXA6yCoaVxG1U-1EbOaQRfUXFs2F9IX6dU7iExsNqhPR4o2CKlt6ERI0JT_p7jHv0hrHbBiUjUVMYi_qoAQRv1OXfVZBLkoRve20gvjQtD3aRZFZR5poX-bq0pw6CNBTLexzD_bU1jJnpaf61OKbQM2-qJnWPS7YayFjJt3k_qALbnquUsSBMDMm3PoFcU26_Ubyu6RTZ-aanKc1bdcEA5o3WF8JksZkrvRFhZZuvWahDpnQCxxy-rELKwXcybcWHi-QB7gxSm6Q6S84NX2390mbHVJ1RO8eUmUF4
How can I make it store only in memory, not in cookies?
You need to set SessionStore for identity cookie authentication, so your authentication cookie is only an identifier.
Instead of
services.AddDefaultIdentity<IdentityUser>()
Use this
services.AddAuthentication(o =>
{
o.DefaultScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddIdentityCookies(o =>
{
o.ApplicationCookie.PostConfigure(cookie => cookie.SessionStore = new MemoryCacheTicketStore());
});
services.AddIdentityCore<IdentityUser>(o =>
{
o.Stores.MaxLengthForKeys = 128;
}).AddDefaultUI()
.AddDefaultTokenProviders();
MemoryCacheTicketStore.cs
public class MemoryCacheTicketStore : ITicketStore
{
private const string KeyPrefix = "AuthSessionStore-";
private IMemoryCache _cache;
public MemoryCacheTicketStore()
{
_cache = new MemoryCache(new MemoryCacheOptions());
}
public async Task<string> StoreAsync(AuthenticationTicket ticket)
{
var guid = Guid.NewGuid();
var key = KeyPrefix + guid.ToString();
await RenewAsync(key, ticket);
return key;
}
public Task RenewAsync(string key, AuthenticationTicket ticket)
{
var options = new MemoryCacheEntryOptions();
var expiresUtc = ticket.Properties.ExpiresUtc;
if (expiresUtc.HasValue)
{
options.SetAbsoluteExpiration(expiresUtc.Value);
}
options.SetSlidingExpiration(TimeSpan.FromHours(1)); // TODO: configurable.
_cache.Set(key, ticket, options);
return Task.FromResult(0);
}
public Task<AuthenticationTicket> RetrieveAsync(string key)
{
AuthenticationTicket ticket;
_cache.TryGetValue(key, out ticket);
return Task.FromResult(ticket);
}
public Task RemoveAsync(string key)
{
_cache.Remove(key);
return Task.FromResult(0);
}
}
I'm working on a asp.net core 2.1 project with identity server 4 installed in it and the users stored in SQL database using entity framework. The Web project has a login page and a dashboard once login is successful.
Please find below the code in Startup.cs,
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)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddMvc();
services.AddDbContext<ApplicationDbContext>(builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)));
services.AddDbContext<SingleSignOn_dbContext>(builder =>
builder.UseSqlServer(connectionString));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer(options =>
{
options.UserInteraction.LoginUrl = "/Master/Login"; // Set the default login page for Identity server.
}).AddOperationalStore(options =>
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
.AddConfigurationStore(options =>
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
.AddAspNetIdentity<IdentityUser>()
.AddDeveloperSigningCredential();
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Master/Error");
app.UseHsts();
}
// Only need to run this once.
InitializeDbTestData(app);
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Master}/{action=Login}/{id?}");
});
}
Client Details below in IDS:
new Client {
ClientId = "SingleSignOnInternalClient",
ClientName = "Example Implicit Client Application",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"role",
"customAPI.write"
},
AllowedCorsOrigins = new List<string> {"192.168.6.112"},
RedirectUris = new List<string> {"https://localhost:44330/signin-oidc"}, // Configuration.GetSection("TestClient").GetSection("RedirectURL").Value
PostLogoutRedirectUris = new List<string> {"https://localhost:44330"},
RequireConsent = false,
AllowRememberConsent = false,
AccessTokenType = AccessTokenType.Jwt
},
I've created a client project using asp.net core 2.1 and authorize attribute in the contact page (Home controller).
When we clicked on the contact page, it redirects to the Login page of the other project where identity server is installed and when successful user authorization is made. The page is redirected to an infinite loop.
Startup file of client:
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)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
// Use cooking authentication for signing in users.
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration.GetValue<string>("Authority:EndPoint"); //services.Configure<"Authority">(Configuration.GetSection("EndPoint"));
options.ClientId = "SingleSignOnInternalClient";
options.SignInScheme = "cookie";
options.SaveTokens = true;
//options.GetClaimsFromUserInfoEndpoint = true;
options.RequireHttpsMetadata = false;
});
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc(options =>
{
///options.Filters.Add
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Output Log in Client(infinite redirect Loop):
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:44330/signin-oidc application/x-www-form-urlencoded 1473
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: cookie signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 5.4353ms 302
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44330/Home/Contact
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Contact", controller = "Home", page = "", area = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Contact() on controller IdentityTestClient.Controllers.HomeController (IdentityTestClient).
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: AuthenticationScheme: oidc was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action IdentityTestClient.Controllers.HomeController.Contact (IdentityTestClient) in 8.3527ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 17.5244ms 302
The Url of the infinite loop is below,
https://localhost:44307/connect/authorize?client_id=SingleSignOnInternalClient&redirect_uri=https%3A%2F%2Flocalhost%3A44330%2Fsignin-oidc&response_type=id_token&scope=openid%20profile&response_mode=form_post&nonce=636969892902312620.YzUzMWRiNTktN2Q5Mi00NzZiLWJhMjQtNzEzMjI5Mzk1MTE2ZjM5NWQ2NTEtOTQ4Yi00MDljLWIyYzQtNWE5OTA3YWZkMDFj&state=CfDJ8HSRls71XI5DkQoP2L7ypNS9cYyKsLJm7m1dhd3hXQldeb3Esa0g7uZHU6MiqjlsqTk6h7QaqxXsFuMk05KZfdVdN2qJ9j9v5zVg-BeAFNT5rH_Suq8NUl47VUSfTl6zyrBLxYYgeLn8gfdaQpbmwsynpBuMZ9FR8C8eoVNxyPyQ0nGdBryxybey4QFO1xnwiENQtddWxPexgDBNsAGFNd5l6IYhdHaunWz9Ab7NHS68xdfwORdsNFMJRHtUxAGGhQ08U1WP_-TD2xm1rctVfUFZ_GqoNyc_KDanEmp4AVo5eEF0KgQl6mx4kH0PRMPHeDh3KjZTddKEVQglT0J2Kjo&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0
Both the projects have SSL configured to run https locally.
I'm trying to achieve a single sign on solution which has multiple websites in different domain and using the Identity server for login.
Any inputs will be much appreciated.
services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();
is not needed client side.
Beyond the other things, only your IdP should have access to, it re-configures your auth scheme parameters. Anytime you can compare your configuration with the minimum working one from the official repository.
In my case the issue was that both apps (IS4 and my api) were using http. After logging in (and leaving that session open in the browser) I moved both apps to SSL. Then the loop began.
My solution was deleting all the cookies.
I want to use Windows Auth in my intranet application, but I need to extend the identity object to get some extra data. As of now, I only have access to the domain name in the identity user. I tried to implement my own user/role store in order to intercept the authorization calls then use the domain name to go to our database and grab the extra data. I implemented my own store, but none of the methods seem to be called. How do I intercept when the app authorized the window user so that I can go to our database and grab what I need to put in the user object?
Here's my Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddIdentity<MyUser, IdentityRole>()
.AddUserStore<MyUserStore>()
.AddRoleStore<MyRoleStore>()
.AddDefaultTokenProviders();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc();
}
What I did was deleting the basic authentication from MVC and added my AuthenticationHandler which extends the AuthenticationService because I don't want to reinvent every method from IAuthenticationService so:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddIdentity<MyUser, IdentityRole>()
.AddUserStore<MyUserStore>()
.AddRoleStore<MyRoleStore>()
.AddDefaultTokenProviders();
services.Remove(services.FirstOrDefault(x => x.ServiceType == typeof(IAuthenticationService)));
services.Add(new ServiceDescriptor(typeof(IAuthenticationService),typeof(AuthenticationHandler), ServiceLifetime.Scoped));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
And then
public class AuthenticationHandler : AuthenticationService
{
private readonly ILdapRepository _ldapRepository;
public AuthenticationHandler(ILdapRepository ldapRepository,
IAuthenticationSchemeProvider schemes, IAuthenticationHandlerProvider handlers,
IClaimsTransformation transform) : base(schemes, handlers, transform)
{
_ldapRepository = ldapRepository;
}
public async override Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
{
var idk = await base.AuthenticateAsync(context, scheme);
if (idk.Succeeded) {
var claims = _ldapRepository.LoadClaimsFromActiveDirectory(idk.Principal.Claims.FirstOrDefault(x => x.Type == CustomClaimTypes.Name)?.Value);
idk.Principal.AddIdentity(claims);
}
return idk;
}
}
LdapRepository is nothing else as the DirectoryEntry and DirectorySearcher for active directory class.
I hope this helps you.