/// <summary> /// Adds OpenID Connect middleware and configuration for using UAA or Pivotal SSO for user authentication /// </summary> /// <param name="builder">Your <see cref="AuthenticationBuilder"/></param> /// <param name="authenticationScheme">An identifier for this authentication mechanism. Default value is <see cref="CloudFoundryDefaults.DisplayName"/></param> /// <param name="displayName">Sets a display name for this auth scheme. Defaults to <see cref="CloudFoundryDefaults.DisplayName"/></param> /// <param name="config">Your application configuration. Be sure to include the <see cref="CloudFoundryConfigurationProvider"/></param> /// <returns><see cref="AuthenticationBuilder"/> configured to use OpenID Connect with UAA or Pivotal SSO</returns> public static AuthenticationBuilder AddCloudFoundryOpenIdConnect(this AuthenticationBuilder builder, string authenticationScheme, string displayName, IConfiguration config) { builder.AddOpenIdConnect(authenticationScheme, displayName, options => { var cloudFoundryOptions = new CloudFoundryOpenIdConnectOptions(); var securitySection = config.GetSection(CloudFoundryDefaults.SECURITY_CLIENT_SECTION_PREFIX); securitySection.Bind(cloudFoundryOptions); var info = config.GetSingletonServiceInfo <SsoServiceInfo>(); CloudFoundryOpenIdConnectConfigurer.Configure(info, options, cloudFoundryOptions); }); return(builder); }
/// <summary> /// Maps service info credentials and 'security:oauth2:client' info onto OpenIdConnectOptions /// </summary> /// <param name="si">Service info credentials parsed from VCAP_SERVICES</param> /// <param name="oidcOptions">OpenId Connect options to be configured</param> /// <param name="cfOptions">Cloud Foundry-related OpenId Connect configuration options</param> internal static void Configure(SsoServiceInfo si, OpenIdConnectOptions oidcOptions, CloudFoundryOpenIdConnectOptions cfOptions) { if (oidcOptions == null || cfOptions == null) { return; } if (si != null) { oidcOptions.Authority = si.AuthDomain; oidcOptions.ClientId = si.ClientId; oidcOptions.ClientSecret = si.ClientSecret; } else { oidcOptions.Authority = cfOptions.Authority; oidcOptions.ClientId = cfOptions.ClientId; oidcOptions.ClientSecret = cfOptions.ClientSecret; } oidcOptions.AuthenticationMethod = cfOptions.AuthenticationMethod; oidcOptions.BackchannelHttpHandler = CloudFoundryHelper.GetBackChannelHandler(cfOptions.ValidateCertificates); oidcOptions.CallbackPath = cfOptions.CallbackPath; oidcOptions.ClaimsIssuer = cfOptions.ClaimsIssuer; oidcOptions.ResponseType = cfOptions.ResponseType; oidcOptions.SaveTokens = cfOptions.SaveTokens; oidcOptions.SignInScheme = cfOptions.SignInScheme; // remove profile scope oidcOptions.Scope.Clear(); oidcOptions.Scope.Add("openid"); // add other scopes if (!string.IsNullOrEmpty(cfOptions.AdditionalScopes)) { foreach (var s in cfOptions.AdditionalScopes.Split(' ')) { if (!oidcOptions.Scope.Contains(s)) { oidcOptions.Scope.Add(s); } } } oidcOptions.TokenValidationParameters = CloudFoundryHelper.GetTokenValidationParameters( cfOptions.TokenValidationParameters, oidcOptions.Authority + CloudFoundryDefaults.JwtTokenUri, oidcOptions.BackchannelHttpHandler, cfOptions.ValidateCertificates, cfOptions.BaseOptions(oidcOptions.ClientId)); // the ClaimsIdentity is built off the id_token, but scopes are returned in the access_token. Copy them as claims oidcOptions.Events.OnTokenValidated = MapScopesToClaims; }
/// <summary> /// Maps service info credentials and 'security:oauth2:client' info onto OpenIdConnectOptions /// </summary> /// <param name="si">Service info credentials parsed from VCAP_SERVICES</param> /// <param name="oidcOptions">OpenId Connect options to be configured</param> /// <param name="cfOptions">Cloud Foundry-related OpenId Connect configuration options</param> internal static void Configure(SsoServiceInfo si, OpenIdConnectOptions oidcOptions, CloudFoundryOpenIdConnectOptions cfOptions) { if (oidcOptions == null || cfOptions == null) { return; } if (si != null) { oidcOptions.Authority = si.AuthDomain; oidcOptions.ClientId = si.ClientId; oidcOptions.ClientSecret = si.ClientSecret; } else { oidcOptions.Authority = cfOptions.Authority; oidcOptions.ClientId = cfOptions.ClientId; oidcOptions.ClientSecret = cfOptions.ClientSecret; } oidcOptions.AuthenticationMethod = cfOptions.AuthenticationMethod; oidcOptions.BackchannelHttpHandler = CloudFoundryHelper.GetBackChannelHandler(cfOptions.ValidateCertificates); oidcOptions.CallbackPath = cfOptions.CallbackPath; oidcOptions.ClaimsIssuer = cfOptions.ClaimsIssuer; oidcOptions.ResponseType = cfOptions.ResponseType; oidcOptions.SaveTokens = cfOptions.SaveTokens; oidcOptions.SignInScheme = cfOptions.SignInScheme; // remove profile scope oidcOptions.Scope.Clear(); oidcOptions.Scope.Add("openid"); // add other scopes if (!string.IsNullOrEmpty(cfOptions.AdditionalScopes)) { foreach (var s in cfOptions.AdditionalScopes.Split(' ')) { if (!oidcOptions.Scope.Contains(s)) { oidcOptions.Scope.Add(s); } } } // http://irisclasson.com/2018/09/18/asp-net-core-openidconnect-why-is-the-claimsprincipal-name-null/ oidcOptions.TokenValidationParameters.NameClaimType = cfOptions.TokenValidationParameters.NameClaimType; // main objective here is to set the IssuerSigningKeyResolver to work around an issue parsing the N value of the signing key in FullFramework oidcOptions.TokenValidationParameters = CloudFoundryHelper.GetTokenValidationParameters(oidcOptions.TokenValidationParameters, oidcOptions.Authority + CloudFoundryDefaults.JwtTokenUri, oidcOptions.BackchannelHttpHandler, cfOptions.ValidateCertificates, cfOptions.BaseOptions(oidcOptions.ClientId)); oidcOptions.TokenValidationParameters.ValidateAudience = cfOptions.TokenValidationParameters.ValidateAudience; oidcOptions.TokenValidationParameters.ValidateLifetime = cfOptions.TokenValidationParameters.ValidateLifetime; // the ClaimsIdentity is built off the id_token, but scopes are returned in the access_token. Copy them as claims oidcOptions.Events.OnTokenValidated = MapScopesToClaims; }