/// <summary> /// Get an access token from the issuer. /// </summary> /// <param name="issuer">The issuer.</param> /// <param name="scope">The scope to request.</param> /// <returns>The token response.</returns> public async Task <TokenResponse> GetAccessTokenAsync(string issuer, string scope) { // Use a signed JWT as client credentials. var payload = new JwtPayload(); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iss, _oidcModel.ClientId)); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Sub, _oidcModel.ClientId)); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Aud, _oidcModel.Audience)); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(DateTime.UtcNow).ToString())); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Nbf, EpochTime.GetIntDate(DateTime.UtcNow.AddSeconds(-5)).ToString())); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Exp, EpochTime.GetIntDate(DateTime.UtcNow.AddMinutes(5)).ToString())); var bytes = CryptoRandom.CreateRandomKey(32); var jti = Base64Url.Encode(bytes); payload.AddClaim(new Claim(JwtRegisteredClaimNames.Jti, jti)); var handler = new JwtSecurityTokenHandler(); var rsaKey = _rsaKeyService.GetKey(); var jwt = handler.WriteToken(new JwtSecurityToken(new JwtHeader(new SigningCredentials(rsaKey, SecurityAlgorithms.RsaSha512)), payload)); var httpClient = _httpClientFactory.CreateClient(); return(await httpClient.RequestClientCredentialsTokenWithJwtAsync( new JwtClientCredentialsTokenRequest { Address = _oidcModel.AccessTokenUrl, ClientId = _oidcModel.ClientId, Jwt = jwt, Scope = scope })); }
public void ConfigureServices(IServiceCollection services) { services.AddDbContext <IdentityDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity <IdentityUser, Role>() .AddEntityFrameworkStores <IdentityDbContext>() .AddDefaultTokenProviders(); services.AddMvc().SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1); var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }) .AddInMemoryIdentityResources(Configuration.GetSection("IdentityResources").Get <List <IdentityResource> >()) .AddInMemoryApiResources(Configuration.GetSection("ApiResources").Get <List <ApiResource> >()) .AddInMemoryClients(Configuration.GetSection("IdentityServer:Clients")) .AddAspNetIdentity <IdentityUser>() .AddOperationalStore(options => { options.RedisConnectionString = Configuration.GetConnectionString("RedisConnection"); }); var rsa = new RsaKeyService(Configuration["SigningCredentialFilePath"], TimeSpan.FromDays(30)); services.AddTransient(provider => rsa); builder.AddSigningCredential(rsa.GetKey()); services.AddAuthentication() .AddGoogle("Google", options => { var googleAuth = Configuration.GetSection("GoogleAuth"); options.ClientId = googleAuth["Id"]; options.ClientSecret = googleAuth["Secret"]; }); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { _identityConfig = Config.GetIdentityResources(); _apiConfig = Config.GetApiResources(Configuration); _clientConfig = Config.GetClients(Configuration); _publicOrigin = Config.GetPublicOrigin(Configuration); _cookieExpiration = Config.GetCookieExpirationByMinute(Configuration); var encConnStrMySql = Configuration.GetConnectionString("MySqlConnection(Azure)"); var connStrMySql = AesCryptoUtil.Decrypt(encConnStrMySql); Log.Information($"Connection String: {connStrMySql}"); services.AddDbContext <ApplicationDbContext>(option => option.UseMySQL(connStrMySql)); services.AddIdentity <ApplicationUser, IdentityRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddCors(options => { options.AddPolicy(EmpWebOrigins, corsBuilder => { corsBuilder .AllowAnyHeader() // .WithHeaders(HeaderNames.AccessControlAllowHeaders, "Content-Type") // .AllowAnyOrigin() .WithOrigins( _clientConfig.First().AllowedCorsOrigins.ToArray() ) .AllowAnyMethod() // .WithMethods("GET", "PUT", "POST", "DELETE") .AllowCredentials(); }); }); services.AddMvc(); services.AddTransient <IProfileService, CustomProfileService>(); var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; options.Authentication.CheckSessionCookieName = "IDS4_EMP.Sts"; options.PublicOrigin = _publicOrigin; }) .AddInMemoryIdentityResources(_identityConfig) .AddInMemoryApiResources(_apiConfig) .AddInMemoryClients(_clientConfig) .AddAspNetIdentity <ApplicationUser>() .AddProfileService <CustomProfileService>(); services.ConfigureApplicationCookie(options => { // To prevent Refresh Access Token overriding cookie refreshe, subtract 1 minute options.ExpireTimeSpan = TimeSpan.FromMinutes(_cookieExpiration - 1); options.SlidingExpiration = true; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; }); if (_env.IsDevelopment()) { // builder.AddDeveloperSigningCredential(); var rsa = new RsaKeyService(_env, TimeSpan.FromDays(30), Configuration); services.AddSingleton <RsaKeyService>(provider => rsa); builder.AddSigningCredential(rsa.GetKey()); } else { var rsa = new RsaKeyService(_env, TimeSpan.FromDays(30), Configuration); services.AddSingleton <RsaKeyService>(provider => rsa); builder.AddSigningCredential(rsa.GetKey()); // services.AddIdentityServer(...).AddSigningCredential(new X509Certificate2(bytes, "password") // builder.AddSigningCredential(new X509Certificate2(bytes, "password"); } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var rsa = new RsaKeyService(_env, TimeSpan.FromDays(30)); services.AddSingleton(provider => rsa); services.AddDbContext <ApplicationDbContext>(options => options.UseInMemoryDatabase( Configuration.GetConnectionString("DefaultConnection"))); var connection = Configuration["ConnectionStrings:DefaultConnection"]; services.AddDbContext <ContextDb>(options => options.UseSqlServer(connection)); services.AddDatabaseDeveloperPageExceptionFilter(); services.AddDefaultIdentity <IdentityUser>(options => options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+/ ") .AddEntityFrameworkStores <ApplicationDbContext>(); services.AddControllersWithViews(); services.AddIdentityServer() .AddInMemoryIdentityResources(IdentityServerConfig.IdentityResources) .AddInMemoryApiScopes(IdentityServerConfig.ApiScopes) .AddInMemoryClients(IdentityServerConfig.Clients) .AddSigningCredential(rsa.GetKey(), RsaSigningAlgorithm.RS256); services .AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultChallengeScheme = "oidc"; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { options.LoginPath = new PathString("/Identity/Account/ExternalLogin"); }) .AddOpenIdConnect("oidc", options => { options.SignInScheme = IdentityConstants.ExternalScheme; options.SaveTokens = true; options.ClientId = Configuration["OpenIdConfig:ClientId"]; options.Authority = Configuration["OpenIdConfig:Issuer"]; // The Platform MUST send the id_token via the OAuth 2 Form Post // See https://www.imsglobal.org/spec/security/v1p0/#successful-authentication options.ResponseType = OpenIdConnectResponseType.IdToken; // See http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html options.ResponseMode = OpenIdConnectResponseMode.FormPost; options.Prompt = OpenIdConnectPrompt.None; options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet; options.DisableTelemetry = true; options.Configuration = new OpenIdConnectConfiguration { AuthorizationEndpoint = Configuration["OpenIdConfig:AuthorizationEndpoint"], TokenEndpoint = Configuration["OpenIdConfig:TokenEndpoint"], Issuer = Configuration["OpenIdConfig:Issuer"], JwksUri = Configuration["OpenIdConfig:JwksUri"] }; options.CallbackPath = new PathString("/LtiTool"); options.Scope.Clear(); options.Scope.Add(OpenIdConnectScope.OpenId); options.Events = new OpenIdConnectEvents { //OnRemoteFailure = HandleOnRemoteFailure, // Authenticate the request starting at step 5 in the OpenId Implicit Flow // See https://www.imsglobal.org/spec/security/v1p0/#platform-originating-messages // See https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowSteps OnRedirectToIdentityProvider = context => { if (context.Properties.Items.TryGetValue(nameof(OidcModel.LoginHint), out var login_hint)) { context.ProtocolMessage.LoginHint = login_hint; } if (context.Properties.Items.TryGetValue(nameof(OidcModel.LtiMessageHint), out var lti_message_hint)) { context.ProtocolMessage.SetParameter("lti_message_hint", lti_message_hint); } if (context.Properties.Items.TryGetValue(nameof(OidcModel.ClientId), out var clientId)) { context.ProtocolMessage.ClientId = clientId; } context.ProtocolMessage.Prompt = OpenIdConnectPrompt.None; if (context.Properties.Items.Count < 4) { context.Response.Redirect("Home/Index"); } return(Task.CompletedTask); }, }; // Using the options.TokenValidationParameters, validate four things: // // 1. The Issuer Identifier for the Platform MUST exactly match the value of the iss // (Issuer) Claim (therefore the Tool MUST previously have been made aware of this // identifier. // 2. The Tool MUST Validate the signature of the ID Token according to JSON Web Signature // RFC 7515, Section 5; using the Public Key for the Platform which collected offline. // 3. The Tool MUST validate that the aud (audience) Claim contains its client_id value // registered as an audience with the Issuer identified by the iss (Issuer) Claim. The // aud (audience) Claim MAY contain an array with more than one element. The Tool MUST // reject the ID Token if it does not list the client_id as a valid audience, or if it // contains additional audiences not trusted by the Tool. // 4. The current time MUST be before the time represented by the exp Claim; options.TokenValidationParameters = new TokenValidationParameters { ValidateTokenReplay = true, ValidateAudience = true, ValidateIssuer = true, RequireSignedTokens = true, ValidateIssuerSigningKey = true, ValidAudience = Configuration["OpenIdConfig:ClientId"], ValidIssuer = Configuration["OpenIdConfig:Issuer"], ValidateLifetime = true, IssuerSigningKeyResolver = (token, securityToken, kid, validationParameters) => { var keySetJson = new WebClient().DownloadString(Configuration["OpenIdConfig:JwksUri"]); var keySet = JsonConvert.DeserializeObject <JsonWebKeySet>(keySetJson); var key = keySet.Keys.SingleOrDefault(k => k.Kid == kid); return(new List <JsonWebKey> { key }); }, ClockSkew = TimeSpan.FromMinutes(5.0) }; }); services.AddSingleton(Configuration.GetSection("OpenIdConfig").Get <OidcModel>()); // Make AccessTokenService available for dependency injection. services.AddTransient <AccessTokenService>(); }
public void ConfigureServices(IServiceCollection services) { //IdentityModelEventSource.ShowPII = true; // Better Identity stacktraces and messages. (Insecure) services.AddDatabaseDeveloperPageExceptionFilter(); services.AddControllersWithViews(); services.AddDbContext <ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity <ApplicationUser, IdentityRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders(); var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html options.EmitStaticAudienceClaim = true; options.IssuerUri = Configuration["Identity:IssuerUri"]; }) .AddConfigurationStore(options => // this adds the config data from DB (clients, resources) { options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) // this adds the operational data from DB (codes, tokens, consents) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), sql => sql.MigrationsAssembly(migrationsAssembly)); options.EnableTokenCleanup = true; // this enables automatic token cleanup. this is optional. options.TokenCleanupInterval = 30; }) .AddAspNetIdentity <ApplicationUser>() .AddProfileService <ProfileService>(); if (Environment.IsDevelopment()) { builder.AddDeveloperSigningCredential(); } else { var rsa = new RsaKeyService(Environment, TimeSpan.FromDays(30)); services.AddTransient <RsaKeyService>(provider => rsa); builder.AddSigningCredential(rsa.GetKey(), IdentityServerConstants.RsaSigningAlgorithm.RS512); } services.AddAuthentication() .AddGoogle(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; // register your IdentityServer with Google at https://console.developers.google.com // enable the Google+ API // set the redirect URI to http://identity:5000/signin-google options.ClientId = Configuration["Identity:Google:ClientId"]; options.ClientSecret = Configuration["Identity:Google:ClientSecret"]; }); services.AddSendGrid(options => // Use whatever email provider you want to. I use SendGrid, because it has a basic free plan to get started with. { options.ApiKey = Configuration["SendGridApiKey"]; }); services.AddTransient <IEmailService, EmailService>(); }