diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/ConfigureJwtBearerOptions.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/ConfigureJwtBearerOptions.cs deleted file mode 100644 index e6c80bbd1..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/ConfigureJwtBearerOptions.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Options; - -namespace DPoPApi; - -public class ConfigureJwtBearerOptions : IPostConfigureOptions -{ - private readonly string _configScheme; - - public ConfigureJwtBearerOptions(string configScheme) => _configScheme = configScheme; - - public void PostConfigure(string name, JwtBearerOptions options) - { - if (_configScheme == name) - { - if (options.EventsType != null && !typeof(DPoPJwtBearerEvents).IsAssignableFrom(options.EventsType)) - { - throw new Exception("EventsType on JwtBearerOptions must derive from DPoPJwtBearerEvents to work with the DPoP support."); - } - if (options.Events != null && !typeof(DPoPJwtBearerEvents).IsAssignableFrom(options.Events.GetType())) - { - throw new Exception("Events on JwtBearerOptions must derive from DPoPJwtBearerEvents to work with the DPoP support."); - } - - if (options.Events == null && options.EventsType == null) - { - options.EventsType = typeof(DPoPJwtBearerEvents); - } - } - } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPExtensions.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPExtensions.cs deleted file mode 100644 index 74704eabc..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPExtensions.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Text.Json; -using Duende.IdentityModel; -using Microsoft.AspNetCore.Authentication; -using Microsoft.IdentityModel.Tokens; - -namespace DPoPApi; - -/// -/// Extensions methods for DPoP -/// -internal static class DPoPExtensions -{ - private const string DPoPPrefix = OidcConstants.AuthenticationSchemes.AuthorizationHeaderDPoP + " "; - - public static bool IsDPoPAuthorizationScheme(this HttpRequest request) - { - var authz = request.Headers.Authorization.FirstOrDefault(); - return authz?.StartsWith(DPoPPrefix, System.StringComparison.Ordinal) == true; - } - - public static bool TryGetDPoPAccessToken(this HttpRequest request, out string token) - { - token = null; - - var authz = request.Headers.Authorization.FirstOrDefault(); - if (authz?.StartsWith(DPoPPrefix, System.StringComparison.Ordinal) == true) - { - token = authz[DPoPPrefix.Length..].Trim(); - return true; - } - return false; - } - - public static string GetAuthorizationScheme(this HttpRequest request) => request.Headers.Authorization.FirstOrDefault()?.Split(' ', System.StringSplitOptions.RemoveEmptyEntries)[0]; - - public static string GetDPoPProofToken(this HttpRequest request) => request.Headers[OidcConstants.HttpHeaders.DPoP].FirstOrDefault(); - - public static string GetDPoPNonce(this AuthenticationProperties props) - { - if (props.Items.ContainsKey("DPoP-Nonce")) - { - return props.Items["DPoP-Nonce"] as string; - } - return null; - } - public static void SetDPoPNonce(this AuthenticationProperties props, string nonce) => props.Items["DPoP-Nonce"] = nonce; - - /// - /// Create the value of a thumbprint-based cnf claim - /// - public static string CreateThumbprintCnf(this JsonWebKey jwk) - { - var jkt = jwk.CreateThumbprint(); - var values = new Dictionary - { - { JwtClaimTypes.ConfirmationMethods.JwkThumbprint, jkt } - }; - return JsonSerializer.Serialize(values); - } - - /// - /// Create the value of a thumbprint - /// - public static string CreateThumbprint(this JsonWebKey jwk) - { - var jkt = Base64Url.Encode(jwk.ComputeJwkThumbprint()); - return jkt; - } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPJwtBearerEvents.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPJwtBearerEvents.cs deleted file mode 100644 index 8a91cdb50..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPJwtBearerEvents.cs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Text; -using Duende.IdentityModel; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Headers; -using static Duende.IdentityModel.OidcConstants; - -namespace DPoPApi; - -public class DPoPJwtBearerEvents : JwtBearerEvents -{ - private readonly IOptionsMonitor _optionsMonitor; - private readonly DPoPProofValidator _validator; - - public DPoPJwtBearerEvents(IOptionsMonitor optionsMonitor, DPoPProofValidator validator) - { - _optionsMonitor = optionsMonitor; - _validator = validator; - } - - public override Task MessageReceived(MessageReceivedContext context) - { - var dpopOptions = _optionsMonitor.Get(context.Scheme.Name); - - if (context.HttpContext.Request.TryGetDPoPAccessToken(out var token)) - { - context.Token = token; - } - else if (dpopOptions.Mode == DPoPMode.DPoPOnly) - { - // this rejects the attempt for this handler, - // since we don't want to attempt Bearer given the Mode - context.NoResult(); - } - - return Task.CompletedTask; - } - - public override async Task TokenValidated(TokenValidatedContext context) - { - var dpopOptions = _optionsMonitor.Get(context.Scheme.Name); - - if (context.HttpContext.Request.TryGetDPoPAccessToken(out var at)) - { - var proofToken = context.HttpContext.Request.GetDPoPProofToken(); - var result = await _validator.ValidateAsync(new DPoPProofValidatonContext - { - Scheme = context.Scheme.Name, - ProofToken = proofToken, - AccessToken = at, - Method = context.HttpContext.Request.Method, - Url = context.HttpContext.Request.Scheme + "://" + context.HttpContext.Request.Host + context.HttpContext.Request.PathBase + context.HttpContext.Request.Path - }); - - if (result.IsError) - { - // fails the result - context.Fail(result.ErrorDescription ?? result.Error); - - // we need to stash these values away so they are available later when the Challenge method is called later - context.HttpContext.Items["DPoP-Error"] = result.Error; - if (!string.IsNullOrWhiteSpace(result.ErrorDescription)) - { - context.HttpContext.Items["DPoP-ErrorDescription"] = result.ErrorDescription; - } - if (!string.IsNullOrWhiteSpace(result.ServerIssuedNonce)) - { - context.HttpContext.Items["DPoP-Nonce"] = result.ServerIssuedNonce; - } - } - } - else if (dpopOptions.Mode == DPoPMode.DPoPAndBearer) - { - // if the scheme used was not DPoP, then it was Bearer - // and if a access token was presented with a cnf, then the - // client should have sent it as DPoP, so we fail the request - if (context.Principal.HasClaim(x => x.Type == JwtClaimTypes.Confirmation)) - { - context.HttpContext.Items["Bearer-ErrorDescription"] = "Must use DPoP when using an access token with a 'cnf' claim"; - context.Fail("Must use DPoP when using an access token with a 'cnf' claim"); - } - } - } - - public override Task Challenge(JwtBearerChallengeContext context) - { - var dpopOptions = _optionsMonitor.Get(context.Scheme.Name); - - if (dpopOptions.Mode == DPoPMode.DPoPOnly) - { - // if we are using DPoP only, then we don't need/want the default - // JwtBearerHandler to add its WWW-Authenticate response header - // so we have to set the status code ourselves - context.Response.StatusCode = 401; - context.HandleResponse(); - } - else if (context.HttpContext.Items.ContainsKey("Bearer-ErrorDescription")) - { - var description = context.HttpContext.Items["Bearer-ErrorDescription"] as string; - context.ErrorDescription = description; - } - - if (context.HttpContext.Request.IsDPoPAuthorizationScheme()) - { - // if we are challening due to dpop, then don't allow bearer www-auth to emit an error - context.Error = null; - } - - // now we always want to add our WWW-Authenticate for DPoP - // For example: - // WWW-Authenticate: DPoP error="invalid_dpop_proof", error_description="Invalid 'iat' value." - var sb = new StringBuilder(); - sb.Append(OidcConstants.AuthenticationSchemes.AuthorizationHeaderDPoP); - - if (context.HttpContext.Items.ContainsKey("DPoP-Error")) - { - var error = context.HttpContext.Items["DPoP-Error"] as string; - sb.Append(" error=\""); - sb.Append(error); - sb.Append('\"'); - - if (context.HttpContext.Items.ContainsKey("DPoP-ErrorDescription")) - { - var description = context.HttpContext.Items["DPoP-ErrorDescription"] as string; - - sb.Append(", error_description=\""); - sb.Append(description); - sb.Append('\"'); - } - } - - context.Response.Headers.Append(HeaderNames.WWWAuthenticate, sb.ToString()); - - - if (context.HttpContext.Items.ContainsKey("DPoP-Nonce")) - { - var nonce = context.HttpContext.Items["DPoP-Nonce"] as string; - context.Response.Headers[HttpHeaders.DPoPNonce] = nonce; - } - else - { - var nonce = context.Properties.GetDPoPNonce(); - if (nonce != null) - { - context.Response.Headers[HttpHeaders.DPoPNonce] = nonce; - } - } - - return Task.CompletedTask; - } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPMode.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPMode.cs deleted file mode 100644 index 1cbd93c77..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPMode.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -namespace DPoPApi; - -public enum DPoPMode -{ - /// - /// Only DPoP tokens will be accepted - /// - DPoPOnly, - /// - /// Both DPoP and Bearer tokens will be accepted - /// - DPoPAndBearer -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPOptions.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPOptions.cs deleted file mode 100644 index 698f7fd9f..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPOptions.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -namespace DPoPApi; - -public class DPoPOptions -{ - public DPoPMode Mode { get; set; } = DPoPMode.DPoPOnly; - - public TimeSpan ProofTokenValidityDuration { get; set; } = TimeSpan.FromSeconds(1); - public TimeSpan ClientClockSkew { get; set; } = TimeSpan.FromMinutes(0); - public TimeSpan ServerClockSkew { get; set; } = TimeSpan.FromMinutes(5); - - public bool ValidateIat { get; set; } = true; - public bool ValidateNonce { get; set; } = false; -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonContext.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonContext.cs deleted file mode 100644 index f2d46e01c..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonContext.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -namespace DPoPApi; - -public class DPoPProofValidatonContext -{ - /// - /// The ASP.NET Core authentication scheme triggering the validation - /// - public string Scheme { get; set; } - - /// - /// The HTTP URL to validate - /// - public string Url { get; set; } - - /// - /// The HTTP method to validate - /// - public string Method { get; set; } - - /// - /// The DPoP proof token to validate - /// - public string ProofToken { get; set; } - - /// - /// The access token - /// - public string AccessToken { get; set; } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonResult.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonResult.cs deleted file mode 100644 index a3d467f9b..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidatonResult.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -namespace DPoPApi; - -public class DPoPProofValidatonResult -{ - public static DPoPProofValidatonResult Success = new DPoPProofValidatonResult { IsError = false }; - - /// - /// Indicates if the result was successful or not - /// - public bool IsError { get; set; } - - /// - /// The error code for the validation result - /// - public string Error { get; set; } - - /// - /// The error description code for the validation result - /// - public string ErrorDescription { get; set; } - - /// - /// The serialized JWK from the validated DPoP proof token. - /// - public string JsonWebKey { get; set; } - - /// - /// The JWK thumbprint from the validated DPoP proof token. - /// - public string JsonWebKeyThumbprint { get; set; } - - /// - /// The cnf value for the DPoP proof token - /// - public string Confirmation { get; set; } - - /// - /// The payload value of the DPoP proof token. - /// - public IDictionary Payload { get; internal set; } - - /// - /// The jti value read from the payload. - /// - public string TokenId { get; set; } - - /// - /// The ath value read from the payload. - /// - public string AccessTokenHash { get; set; } - - /// - /// The nonce value read from the payload. - /// - public string Nonce { get; set; } - - /// - /// The iat value read from the payload. - /// - public long? IssuedAt { get; set; } - - /// - /// The nonce value issued by the server. - /// - public string ServerIssuedNonce { get; set; } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidator.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidator.cs deleted file mode 100644 index 7efdaa3cb..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPProofValidator.cs +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography; -using System.Text; -using System.Text.Json; -using Duende.IdentityModel; -using Microsoft.AspNetCore.DataProtection; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.JsonWebTokens; -using Microsoft.IdentityModel.Tokens; - -namespace DPoPApi; - -public class DPoPProofValidator -{ - private const string ReplayCachePurpose = "DPoPJwtBearerEvents-DPoPReplay-jti-"; - private const string DataProtectorPurpose = "DPoPJwtBearerEvents-DPoPProofValidation-nonce"; - - public readonly static IEnumerable SupportedDPoPSigningAlgorithms = new[] - { - SecurityAlgorithms.RsaSha256, - SecurityAlgorithms.RsaSha384, - SecurityAlgorithms.RsaSha512, - - SecurityAlgorithms.RsaSsaPssSha256, - SecurityAlgorithms.RsaSsaPssSha384, - SecurityAlgorithms.RsaSsaPssSha512, - - SecurityAlgorithms.EcdsaSha256, - SecurityAlgorithms.EcdsaSha384, - SecurityAlgorithms.EcdsaSha512 - }; - - protected readonly IOptionsMonitor OptionsMonitor; - protected readonly IDataProtector DataProtector; - protected readonly IReplayCache ReplayCache; - protected readonly ILogger Logger; - - public DPoPProofValidator(IOptionsMonitor optionsMonitor, IDataProtectionProvider dataProtectionProvider, IReplayCache replayCache, ILogger logger) - { - OptionsMonitor = optionsMonitor; - DataProtector = dataProtectionProvider.CreateProtector(DataProtectorPurpose); - ReplayCache = replayCache; - Logger = logger; - } - - /// - public async Task ValidateAsync(DPoPProofValidatonContext context) - { - var result = new DPoPProofValidatonResult() { IsError = false }; - - try - { - if (string.IsNullOrEmpty(context?.ProofToken)) - { - result.IsError = true; - result.ErrorDescription = "Missing DPoP proof value."; - return result; - } - - await ValidateHeaderAsync(context, result); - if (result.IsError) - { - Logger.LogDebug("Failed to validate DPoP header"); - return result; - } - - await ValidateSignatureAsync(context, result); - if (result.IsError) - { - Logger.LogDebug("Failed to validate DPoP signature"); - return result; - } - - await ValidatePayloadAsync(context, result); - if (result.IsError) - { - Logger.LogDebug("Failed to validate DPoP payload"); - return result; - } - - Logger.LogDebug("Successfully validated DPoP proof token with thumbprint: {jkt}", result.JsonWebKeyThumbprint); - result.IsError = false; - } - finally - { - if (result.IsError && string.IsNullOrWhiteSpace(result.Error)) - { - result.Error = OidcConstants.TokenErrors.InvalidDPoPProof; - } - } - - return result; - } - - /// - /// Validates the header. - /// - protected virtual Task ValidateHeaderAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - JsonWebToken token; - - try - { - var handler = new JsonWebTokenHandler(); - token = handler.ReadJsonWebToken(context.ProofToken); - } - catch (Exception ex) - { - Logger.LogDebug("Error parsing DPoP token: {error}", ex.Message); - result.IsError = true; - result.ErrorDescription = "Malformed DPoP token."; - return Task.CompletedTask; - } - - if (!token.TryGetHeaderValue(JwtClaimTypes.TokenType, out var typ) || typ != JwtClaimTypes.JwtTypes.DPoPProofToken) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'typ' value."; - return Task.CompletedTask; - } - - if (!token.TryGetHeaderValue(JwtClaimTypes.Algorithm, out var alg) || !SupportedDPoPSigningAlgorithms.Contains(alg)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'alg' value."; - return Task.CompletedTask; - } - - if (!token.TryGetHeaderValue(JwtClaimTypes.JsonWebKey, out var jwkValues)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'jwk' value."; - return Task.CompletedTask; - } - - var jwkJson = JsonSerializer.Serialize(jwkValues); - - JsonWebKey jwk; - try - { - jwk = new JsonWebKey(jwkJson); - } - catch (Exception ex) - { - Logger.LogDebug("Error parsing DPoP jwk value: {error}", ex.Message); - result.IsError = true; - result.ErrorDescription = "Invalid 'jwk' value."; - return Task.CompletedTask; - } - - if (jwk.HasPrivateKey) - { - result.IsError = true; - result.ErrorDescription = "'jwk' value contains a private key."; - return Task.CompletedTask; - } - - result.JsonWebKey = jwkJson; - result.JsonWebKeyThumbprint = jwk.CreateThumbprint(); - result.Confirmation = jwk.CreateThumbprintCnf(); - - return Task.CompletedTask; - } - - /// - /// Validates the signature. - /// - protected virtual async Task ValidateSignatureAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - TokenValidationResult tokenValidationResult; - - try - { - var key = new JsonWebKey(result.JsonWebKey); - var tvp = new TokenValidationParameters - { - ValidateAudience = false, - ValidateIssuer = false, - ValidateLifetime = false, - IssuerSigningKey = key, - }; - - var handler = new JsonWebTokenHandler(); - tokenValidationResult = await handler.ValidateTokenAsync(context.ProofToken, tvp); - } - catch (Exception ex) - { - Logger.LogDebug("Error parsing DPoP token: {error}", ex.Message); - result.IsError = true; - result.ErrorDescription = "Invalid signature on DPoP token."; - return; - } - - if (tokenValidationResult.Exception != null) - { - Logger.LogDebug("Error parsing DPoP token: {error}", tokenValidationResult.Exception.Message); - result.IsError = true; - result.ErrorDescription = "Invalid signature on DPoP token."; - return; - } - - result.Payload = tokenValidationResult.Claims; - } - - /// - /// Validates the payload. - /// - protected virtual async Task ValidatePayloadAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - if (result.Payload.TryGetValue(JwtClaimTypes.DPoPAccessTokenHash, out var ath)) - { - result.AccessTokenHash = ath as string; - } - - if (string.IsNullOrEmpty(result.AccessTokenHash)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'ath' value."; - return; - } - - using (var sha = SHA256.Create()) - { - var bytes = Encoding.UTF8.GetBytes(context.AccessToken); - var hash = sha.ComputeHash(bytes); - - var accessTokenHash = Base64Url.Encode(hash); - if (accessTokenHash != result.AccessTokenHash) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'ath' value."; - return; - } - } - - if (result.Payload.TryGetValue(JwtClaimTypes.JwtId, out var jti)) - { - result.TokenId = jti as string; - } - - if (string.IsNullOrEmpty(result.TokenId)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'jti' value."; - return; - } - - if (!result.Payload.TryGetValue(JwtClaimTypes.DPoPHttpMethod, out var htm) || !context.Method.Equals(htm)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'htm' value."; - return; - } - - if (!result.Payload.TryGetValue(JwtClaimTypes.DPoPHttpUrl, out var htu) || !context.Url.Equals(htu)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'htu' value."; - return; - } - - if (result.Payload.TryGetValue(JwtClaimTypes.IssuedAt, out var iat)) - { - if (iat is int) - { - result.IssuedAt = (int)iat; - } - if (iat is long) - { - result.IssuedAt = (long)iat; - } - } - - if (!result.IssuedAt.HasValue) - { - result.IsError = true; - result.ErrorDescription = "Missing 'iat' value."; - return; - } - - if (result.Payload.TryGetValue(JwtClaimTypes.Nonce, out var nonce)) - { - result.Nonce = nonce as string; - } - - await ValidateFreshnessAsync(context, result); - if (result.IsError) - { - Logger.LogDebug("Failed to validate DPoP token freshness"); - return; - } - - // we do replay at the end so we only add to the reply cache if everything else is ok - await ValidateReplayAsync(context, result); - if (result.IsError) - { - Logger.LogDebug("Detected replay of DPoP token"); - return; - } - } - - /// - /// Validates is the token has been replayed. - /// - protected virtual async Task ValidateReplayAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - var dpopOptions = OptionsMonitor.Get(context.Scheme); - - if (await ReplayCache.ExistsAsync(ReplayCachePurpose, result.TokenId)) - { - result.IsError = true; - result.ErrorDescription = "Detected DPoP proof token replay."; - return; - } - - // get largest skew based on how client's freshness is validated - var validateIat = dpopOptions.ValidateIat; - var validateNonce = dpopOptions.ValidateNonce; - var skew = TimeSpan.Zero; - if (validateIat && dpopOptions.ClientClockSkew > skew) - { - skew = dpopOptions.ClientClockSkew; - } - if (validateNonce && dpopOptions.ServerClockSkew > skew) - { - skew = dpopOptions.ServerClockSkew; - } - - // we do x2 here because clock might be might be before or after, so we're making cache duration - // longer than the likelyhood of proof token expiration, which is done before replay - skew *= 2; - var cacheDuration = dpopOptions.ProofTokenValidityDuration + skew; - - Logger.LogDebug("Adding proof token with jti {jti} to replay cache for duration {cacheDuration}", result.TokenId, cacheDuration); - - await ReplayCache.AddAsync(ReplayCachePurpose, result.TokenId, DateTimeOffset.UtcNow.Add(cacheDuration)); - } - - /// - /// Validates the freshness. - /// - protected virtual async Task ValidateFreshnessAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - var dpopOptions = OptionsMonitor.Get(context.Scheme); - - var validateIat = dpopOptions.ValidateIat; - if (validateIat) - { - await ValidateIatAsync(context, result); - if (result.IsError) - { - return; - } - } - - var validateNonce = dpopOptions.ValidateNonce; - if (validateNonce) - { - await ValidateNonceAsync(context, result); - if (result.IsError) - { - return; - } - } - } - - /// - /// Validates the freshness of the iat value. - /// - protected virtual Task ValidateIatAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - var dpopOptions = OptionsMonitor.Get(context.Scheme); - - if (IsExpired(context, result, dpopOptions.ClientClockSkew, result.IssuedAt.Value)) - { - result.IsError = true; - result.ErrorDescription = "Invalid 'iat' value."; - return Task.CompletedTask; - } - - return Task.CompletedTask; - } - - /// - /// Validates the freshness of the nonce value. - /// - protected virtual async Task ValidateNonceAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - if (string.IsNullOrWhiteSpace(result.Nonce)) - { - result.IsError = true; - result.Error = OidcConstants.TokenErrors.UseDPoPNonce; - result.ErrorDescription = "Missing 'nonce' value."; - result.ServerIssuedNonce = CreateNonce(context, result); - return; - } - - var time = await GetUnixTimeFromNonceAsync(context, result); - if (time <= 0) - { - Logger.LogDebug("Invalid time value read from the 'nonce' value"); - - result.IsError = true; - result.ErrorDescription = "Invalid 'nonce' value."; - result.ServerIssuedNonce = CreateNonce(context, result); - return; - } - - var dpopOptions = OptionsMonitor.Get(context.Scheme); - - if (IsExpired(context, result, dpopOptions.ServerClockSkew, time)) - { - Logger.LogDebug("DPoP 'nonce' expiration failed. It's possible that the server farm clocks might not be closely synchronized, so consider setting the ServerClockSkew on the DPoPOptions on the IdentityServerOptions."); - - result.IsError = true; - result.ErrorDescription = "Invalid 'nonce' value."; - result.ServerIssuedNonce = CreateNonce(context, result); - return; - } - } - - /// - /// Creates a nonce value to return to the client. - /// - /// - protected virtual string CreateNonce(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - return DataProtector.Protect(now.ToString()); - } - - /// - /// Reads the time the nonce was created. - /// - /// - protected virtual ValueTask GetUnixTimeFromNonceAsync(DPoPProofValidatonContext context, DPoPProofValidatonResult result) - { - try - { - var value = DataProtector.Unprotect(result.Nonce); - if (long.TryParse(value, out var iat)) - { - return ValueTask.FromResult(iat); - } - } - catch (Exception ex) - { - Logger.LogDebug("Error parsing DPoP 'nonce' value: {error}", ex.ToString()); - } - - return ValueTask.FromResult(0); - } - - /// - /// Validates the expiration of the DPoP proof. - /// Returns true if the time is beyond the allowed limits, false otherwise. - /// - protected virtual bool IsExpired(DPoPProofValidatonContext context, DPoPProofValidatonResult result, TimeSpan clockSkew, long issuedAtTime) - { - var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - var start = now + (int)clockSkew.TotalSeconds; - if (start < issuedAtTime) - { - var diff = issuedAtTime - now; - Logger.LogDebug("Expiration check failed. Creation time was too far in the future. The time being checked was {iat}, and clock is now {now}. The time difference is {diff}", issuedAtTime, now, diff); - return true; - } - - var dpopOptions = OptionsMonitor.Get(context.Scheme); - var expiration = issuedAtTime + (int)dpopOptions.ProofTokenValidityDuration.TotalSeconds; - var end = now - (int)clockSkew.TotalSeconds; - if (expiration < end) - { - var diff = now - expiration; - Logger.LogDebug("Expiration check failed. Expiration has already happened. The expiration was at {exp}, and clock is now {now}. The time difference is {diff}", expiration, now, diff); - return true; - } - - return false; - } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPServiceCollectionExtensions.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPServiceCollectionExtensions.cs deleted file mode 100644 index e86d084a8..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DPoPServiceCollectionExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Options; - -namespace DPoPApi; - -internal static class DPoPServiceCollectionExtensions -{ - public static IServiceCollection ConfigureDPoPTokensForScheme(this IServiceCollection services, string scheme) - { - services.AddOptions(); - - services.AddTransient(); - services.AddTransient(); - services.AddDistributedMemoryCache(); - services.AddTransient(); - - services.AddSingleton>(new ConfigureJwtBearerOptions(scheme)); - - - return services; - } - - public static IServiceCollection ConfigureDPoPTokensForScheme(this IServiceCollection services, string scheme, Action configure) - { - services.Configure(scheme, configure); - return services.ConfigureDPoPTokensForScheme(scheme); - } -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/DefaultReplayCache.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/DefaultReplayCache.cs deleted file mode 100644 index 21bc217e1..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/DefaultReplayCache.cs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.Extensions.Caching.Distributed; - -namespace DPoPApi; - -/// -/// Default implementation of the replay cache using IDistributedCache -/// -public class DefaultReplayCache : IReplayCache -{ - private const string Prefix = nameof(DefaultReplayCache) + "-"; - - private readonly IDistributedCache _cache; - - /// - /// ctor - /// - /// - public DefaultReplayCache(IDistributedCache cache) => _cache = cache; - - /// - public async Task AddAsync(string purpose, string handle, DateTimeOffset expiration) - { - var options = new DistributedCacheEntryOptions - { - AbsoluteExpiration = expiration - }; - - await _cache.SetAsync(Prefix + purpose + handle, new byte[] { }, options); - } - - /// - public async Task ExistsAsync(string purpose, string handle) => (await _cache.GetAsync(Prefix + purpose + handle, default)) != null; -} diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoP/IReplayCache.cs b/identity-server/clients/src/APIs/DPoPApi/DPoP/IReplayCache.cs deleted file mode 100644 index 0f574629b..000000000 --- a/identity-server/clients/src/APIs/DPoPApi/DPoP/IReplayCache.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -namespace DPoPApi; - -public interface IReplayCache -{ - /// - /// Adds a handle to the cache - /// - /// - /// - /// - /// - Task AddAsync(string purpose, string handle, DateTimeOffset expiration); - - - /// - /// Checks if a cached handle exists - /// - /// - /// - /// - Task ExistsAsync(string purpose, string handle); -} diff --git a/identity-server/clients/src/ConsoleResourceIndicators/Program.cs b/identity-server/clients/src/ConsoleResourceIndicators/Program.cs index c3e54c5a2..ac736a9e1 100644 --- a/identity-server/clients/src/ConsoleResourceIndicators/Program.cs +++ b/identity-server/clients/src/ConsoleResourceIndicators/Program.cs @@ -1,10 +1,10 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using Clients; using ConsoleResourceIndicators; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityModel.OidcClient; using Microsoft.Extensions.Hosting; @@ -103,8 +103,8 @@ async Task FrontChannel(string scope, IEnumerable resource) Console.WriteLine(); Console.WriteLine("Standard access token:"); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(header)).PrettyPrintJson()); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(payload)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)).PrettyPrintJson()); if (result.RefreshToken == null) { @@ -155,8 +155,8 @@ async Task Refresh(string refreshToken, string resource) var header = parts[0]; var payload = parts[1]; - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(header)).PrettyPrintJson()); - Console.WriteLine(Encoding.UTF8.GetString(Base64Url.Decode(payload)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)).PrettyPrintJson()); + Console.WriteLine(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)).PrettyPrintJson()); } internal class Test diff --git a/identity-server/clients/src/Constants/TokenResponseExtensions.cs b/identity-server/clients/src/Constants/TokenResponseExtensions.cs index 453bbae46..c36d85f14 100644 --- a/identity-server/clients/src/Constants/TokenResponseExtensions.cs +++ b/identity-server/clients/src/Constants/TokenResponseExtensions.cs @@ -1,9 +1,9 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; namespace Clients; @@ -25,8 +25,8 @@ public static class TokenResponseExtensions var header = parts[0]; var payload = parts[1]; - Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.Decode(header)))); - Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.Decode(payload)))); + Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(header)))); + Console.WriteLine(PrettyPrintJson(Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)))); } } else diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/_references.js b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/_references.js deleted file mode 100644 index b6fe9d626..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/_references.js +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// -/// -/// -/// -/// diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/css/site.min.css b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/css/site.min.css deleted file mode 100644 index 3beb45f52..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/css/site.min.css +++ /dev/null @@ -1 +0,0 @@ -body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}@media screen and (max-width:767px){.carousel-caption{display:none}} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner1.svg b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner1.svg deleted file mode 100644 index 1ab32b60b..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner1.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner2.svg b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner2.svg deleted file mode 100644 index 9679c604d..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner3.svg b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner3.svg deleted file mode 100644 index 9be2c2503..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner3.svg +++ /dev/null @@ -1 +0,0 @@ -banner3b \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner4.svg b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner4.svg deleted file mode 100644 index 38b3d7cd1..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/images/banner4.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/js/site.min.js b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/js/site.min.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/.bower.json b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/.bower.json deleted file mode 100644 index e37d6cab3..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/.bower.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "bootstrap", - "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", - "keywords": [ - "css", - "js", - "less", - "mobile-first", - "responsive", - "front-end", - "framework", - "web" - ], - "homepage": "http://getbootstrap.com", - "license": "MIT", - "moduleType": "globals", - "main": [ - "less/bootstrap.less", - "dist/js/bootstrap.js" - ], - "ignore": [ - "/.*", - "_config.yml", - "CNAME", - "composer.json", - "CONTRIBUTING.md", - "docs", - "js/tests", - "test-infra" - ], - "dependencies": { - "jquery": "1.9.1 - 2" - }, - "version": "3.3.6", - "_release": "3.3.6", - "_resolution": { - "type": "version", - "tag": "v3.3.6", - "commit": "81df608a40bf0629a1dc08e584849bb1e43e0b7a" - }, - "_source": "git://github.com/twbs/bootstrap.git", - "_target": "3.3.6", - "_originalSource": "bootstrap" -} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css deleted file mode 100644 index ebe57fbf6..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css +++ /dev/null @@ -1,587 +0,0 @@ -/*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ -.btn-default, -.btn-primary, -.btn-success, -.btn-info, -.btn-warning, -.btn-danger { - text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); -} -.btn-default:active, -.btn-primary:active, -.btn-success:active, -.btn-info:active, -.btn-warning:active, -.btn-danger:active, -.btn-default.active, -.btn-primary.active, -.btn-success.active, -.btn-info.active, -.btn-warning.active, -.btn-danger.active { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -} -.btn-default.disabled, -.btn-primary.disabled, -.btn-success.disabled, -.btn-info.disabled, -.btn-warning.disabled, -.btn-danger.disabled, -.btn-default[disabled], -.btn-primary[disabled], -.btn-success[disabled], -.btn-info[disabled], -.btn-warning[disabled], -.btn-danger[disabled], -fieldset[disabled] .btn-default, -fieldset[disabled] .btn-primary, -fieldset[disabled] .btn-success, -fieldset[disabled] .btn-info, -fieldset[disabled] .btn-warning, -fieldset[disabled] .btn-danger { - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-default .badge, -.btn-primary .badge, -.btn-success .badge, -.btn-info .badge, -.btn-warning .badge, -.btn-danger .badge { - text-shadow: none; -} -.btn:active, -.btn.active { - background-image: none; -} -.btn-default { - text-shadow: 0 1px 0 #fff; - background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); - background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); - background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #dbdbdb; - border-color: #ccc; -} -.btn-default:hover, -.btn-default:focus { - background-color: #e0e0e0; - background-position: 0 -15px; -} -.btn-default:active, -.btn-default.active { - background-color: #e0e0e0; - border-color: #dbdbdb; -} -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #e0e0e0; - background-image: none; -} -.btn-primary { - background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); - background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #245580; -} -.btn-primary:hover, -.btn-primary:focus { - background-color: #265a88; - background-position: 0 -15px; -} -.btn-primary:active, -.btn-primary.active { - background-color: #265a88; - border-color: #245580; -} -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #265a88; - background-image: none; -} -.btn-success { - background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); - background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); - background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #3e8f3e; -} -.btn-success:hover, -.btn-success:focus { - background-color: #419641; - background-position: 0 -15px; -} -.btn-success:active, -.btn-success.active { - background-color: #419641; - border-color: #3e8f3e; -} -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #419641; - background-image: none; -} -.btn-info { - background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); - background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); - background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #28a4c9; -} -.btn-info:hover, -.btn-info:focus { - background-color: #2aabd2; - background-position: 0 -15px; -} -.btn-info:active, -.btn-info.active { - background-color: #2aabd2; - border-color: #28a4c9; -} -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #2aabd2; - background-image: none; -} -.btn-warning { - background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); - background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); - background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #e38d13; -} -.btn-warning:hover, -.btn-warning:focus { - background-color: #eb9316; - background-position: 0 -15px; -} -.btn-warning:active, -.btn-warning.active { - background-color: #eb9316; - border-color: #e38d13; -} -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #eb9316; - background-image: none; -} -.btn-danger { - background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); - background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); - background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-color: #b92c28; -} -.btn-danger:hover, -.btn-danger:focus { - background-color: #c12e2a; - background-position: 0 -15px; -} -.btn-danger:active, -.btn-danger.active { - background-color: #c12e2a; - border-color: #b92c28; -} -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #c12e2a; - background-image: none; -} -.thumbnail, -.img-thumbnail { - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); - box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -} -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - background-color: #e8e8e8; - background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); - background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); - background-repeat: repeat-x; -} -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - background-color: #2e6da4; - background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); - background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); - background-repeat: repeat-x; -} -.navbar-default { - background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); - background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); - background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .active > a { - background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); - background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); - background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); - background-repeat: repeat-x; - -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); - box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); -} -.navbar-brand, -.navbar-nav > li > a { - text-shadow: 0 1px 0 rgba(255, 255, 255, .25); -} -.navbar-inverse { - background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); - background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); - background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - background-repeat: repeat-x; - border-radius: 4px; -} -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .active > a { - background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); - background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); - background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); - background-repeat: repeat-x; - -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); - box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); -} -.navbar-inverse .navbar-brand, -.navbar-inverse .navbar-nav > li > a { - text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); -} -.navbar-static-top, -.navbar-fixed-top, -.navbar-fixed-bottom { - border-radius: 0; -} -@media (max-width: 767px) { - .navbar .navbar-nav .open .dropdown-menu > .active > a, - .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #fff; - background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); - background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); - background-repeat: repeat-x; - } -} -.alert { - text-shadow: 0 1px 0 rgba(255, 255, 255, .2); - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); -} -.alert-success { - background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); - background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); - background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); - background-repeat: repeat-x; - border-color: #b2dba1; -} -.alert-info { - background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); - background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); - background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); - background-repeat: repeat-x; - border-color: #9acfea; -} -.alert-warning { - background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); - background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); - background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); - background-repeat: repeat-x; - border-color: #f5e79e; -} -.alert-danger { - background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); - background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); - background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); - background-repeat: repeat-x; - border-color: #dca7a7; -} -.progress { - background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); - background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); - background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar { - background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); - background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar-success { - background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); - background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); - background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar-info { - background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); - background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); - background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar-warning { - background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); - background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); - background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar-danger { - background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); - background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); - background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); - background-repeat: repeat-x; -} -.progress-bar-striped { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.list-group { - border-radius: 4px; - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); - box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -} -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - text-shadow: 0 -1px 0 #286090; - background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); - background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); - background-repeat: repeat-x; - border-color: #2b669a; -} -.list-group-item.active .badge, -.list-group-item.active:hover .badge, -.list-group-item.active:focus .badge { - text-shadow: none; -} -.panel { - -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); - box-shadow: 0 1px 2px rgba(0, 0, 0, .05); -} -.panel-default > .panel-heading { - background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); - background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); - background-repeat: repeat-x; -} -.panel-primary > .panel-heading { - background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); - background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); - background-repeat: repeat-x; -} -.panel-success > .panel-heading { - background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); - background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); - background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); - background-repeat: repeat-x; -} -.panel-info > .panel-heading { - background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); - background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); - background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); - background-repeat: repeat-x; -} -.panel-warning > .panel-heading { - background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); - background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); - background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); - background-repeat: repeat-x; -} -.panel-danger > .panel-heading { - background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); - background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); - background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); - background-repeat: repeat-x; -} -.well { - background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); - background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); - background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); - background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); - background-repeat: repeat-x; - border-color: #dcdcdc; - -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); -} -/*# sourceMappingURL=bootstrap-theme.css.map */ diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css.map b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css.map deleted file mode 100644 index 21e19101e..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAAA;;;;GAIG;ACeH;;;;;;EAME,yCAAA;EC2CA,4FAAA;EACQ,oFAAA;CFvDT;ACgBC;;;;;;;;;;;;ECsCA,yDAAA;EACQ,iDAAA;CFxCT;ACMC;;;;;;;;;;;;;;;;;;ECiCA,yBAAA;EACQ,iBAAA;CFnBT;AC/BD;;;;;;EAuBI,kBAAA;CDgBH;ACyBC;;EAEE,uBAAA;CDvBH;AC4BD;EErEI,sEAAA;EACA,iEAAA;EACA,2FAAA;EAAA,oEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;EAuC2C,0BAAA;EAA2B,mBAAA;CDjBvE;ACpBC;;EAEE,0BAAA;EACA,6BAAA;CDsBH;ACnBC;;EAEE,0BAAA;EACA,sBAAA;CDqBH;ACfG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6BL;ACbD;EEtEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8DD;AC5DC;;EAEE,0BAAA;EACA,6BAAA;CD8DH;AC3DC;;EAEE,0BAAA;EACA,sBAAA;CD6DH;ACvDG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqEL;ACpDD;EEvEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsGD;ACpGC;;EAEE,0BAAA;EACA,6BAAA;CDsGH;ACnGC;;EAEE,0BAAA;EACA,sBAAA;CDqGH;AC/FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6GL;AC3FD;EExEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ID;AC5IC;;EAEE,0BAAA;EACA,6BAAA;CD8IH;AC3IC;;EAEE,0BAAA;EACA,sBAAA;CD6IH;ACvIG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqJL;AClID;EEzEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsLD;ACpLC;;EAEE,0BAAA;EACA,6BAAA;CDsLH;ACnLC;;EAEE,0BAAA;EACA,sBAAA;CDqLH;AC/KG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6LL;ACzKD;EE1EI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ND;AC5NC;;EAEE,0BAAA;EACA,6BAAA;CD8NH;AC3NC;;EAEE,0BAAA;EACA,sBAAA;CD6NH;ACvNG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqOL;AC1MD;;EClCE,mDAAA;EACQ,2CAAA;CFgPT;ACrMD;;EE3FI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF0FF,0BAAA;CD2MD;ACzMD;;;EEhGI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFgGF,0BAAA;CD+MD;ACtMD;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EH+HA,mBAAA;ECjEA,4FAAA;EACQ,oFAAA;CF8QT;ACjND;;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,yDAAA;EACQ,iDAAA;CFwRT;AC9MD;;EAEE,+CAAA;CDgND;AC5MD;EEhII,sEAAA;EACA,iEAAA;EACA,2FAAA;EAAA,oEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EHkJA,mBAAA;CDkND;ACrND;;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,wDAAA;EACQ,gDAAA;CF+ST;AC/ND;;EAYI,0CAAA;CDuNH;AClND;;;EAGE,iBAAA;CDoND;AC/LD;EAfI;;;IAGE,YAAA;IE7JF,yEAAA;IACA,oEAAA;IACA,8FAAA;IAAA,uEAAA;IACA,4BAAA;IACA,uHAAA;GH+WD;CACF;AC3MD;EACE,8CAAA;EC3HA,2FAAA;EACQ,mFAAA;CFyUT;ACnMD;EEtLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+MD;AC1MD;EEvLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuND;ACjND;EExLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+ND;ACxND;EEzLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuOD;ACxND;EEjMI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH4ZH;ACrND;EE3MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHmaH;AC3ND;EE5MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH0aH;ACjOD;EE7MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHibH;ACvOD;EE9MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHwbH;AC7OD;EE/MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH+bH;AChPD;EElLI,8MAAA;EACA,yMAAA;EACA,sMAAA;CHqaH;AC5OD;EACE,mBAAA;EC9KA,mDAAA;EACQ,2CAAA;CF6ZT;AC7OD;;;EAGE,8BAAA;EEnOE,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFiOF,sBAAA;CDmPD;ACxPD;;;EAQI,kBAAA;CDqPH;AC3OD;ECnME,kDAAA;EACQ,0CAAA;CFibT;ACrOD;EE5PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHoeH;AC3OD;EE7PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH2eH;ACjPD;EE9PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHkfH;ACvPD;EE/PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHyfH;AC7PD;EEhQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHggBH;ACnQD;EEjQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHugBH;ACnQD;EExQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFsQF,sBAAA;EC3NA,0FAAA;EACQ,kFAAA;CFqeT","file":"bootstrap-theme.css","sourcesContent":["/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css deleted file mode 100644 index dc95d8e4e..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css +++ /dev/null @@ -1,6 +0,0 @@ -/*! - * Bootstrap v3.3.6 (http://getbootstrap.com) - * Copyright 2011-2015 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -/*# sourceMappingURL=bootstrap-theme.min.css.map */ \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css.map b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css.map deleted file mode 100644 index 2c6b65afc..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/css/bootstrap-theme.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA"} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a4953f..000000000 Binary files a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.svg b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 94fb5490a..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc609..000000000 Binary files a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 9e612858f..000000000 Binary files a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b54c..000000000 Binary files a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 and /dev/null differ diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/js/npm.js b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/js/npm.js deleted file mode 100644 index bf6aa8060..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/bootstrap/dist/js/npm.js +++ /dev/null @@ -1,13 +0,0 @@ -// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. -require('../../js/transition.js') -require('../../js/alert.js') -require('../../js/button.js') -require('../../js/carousel.js') -require('../../js/collapse.js') -require('../../js/dropdown.js') -require('../../js/modal.js') -require('../../js/tooltip.js') -require('../../js/popover.js') -require('../../js/scrollspy.js') -require('../../js/tab.js') -require('../../js/affix.js') \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation-unobtrusive/.bower.json b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation-unobtrusive/.bower.json deleted file mode 100644 index ccf48121d..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation-unobtrusive/.bower.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "jquery-validation-unobtrusive", - "version": "3.2.6", - "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", - "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", - "main": [ - "jquery.validate.unobtrusive.js" - ], - "ignore": [ - "**/.*", - "*.json", - "*.md", - "*.txt", - "gulpfile.js" - ], - "keywords": [ - "jquery", - "asp.net", - "mvc", - "validation", - "unobtrusive" - ], - "authors": [ - "Microsoft" - ], - "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", - "repository": { - "type": "git", - "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" - }, - "dependencies": { - "jquery-validation": ">=1.8", - "jquery": ">=1.8" - }, - "_release": "3.2.6", - "_resolution": { - "type": "version", - "tag": "v3.2.6", - "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" - }, - "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", - "_target": "3.2.6", - "_originalSource": "jquery-validation-unobtrusive" -} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation/.bower.json b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation/.bower.json deleted file mode 100644 index cab34a4a6..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery-validation/.bower.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "jquery-validation", - "homepage": "http://jqueryvalidation.org/", - "repository": { - "type": "git", - "url": "git://github.com/jzaefferer/jquery-validation.git" - }, - "authors": [ - "Jörn Zaefferer " - ], - "description": "Form validation made easy", - "main": "dist/jquery.validate.js", - "keywords": [ - "forms", - "validation", - "validate" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "demo", - "lib" - ], - "dependencies": { - "jquery": ">= 1.7.2" - }, - "version": "1.14.0", - "_release": "1.14.0", - "_resolution": { - "type": "version", - "tag": "1.14.0", - "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" - }, - "_source": "git://github.com/jzaefferer/jquery-validation.git", - "_target": ">=1.8", - "_originalSource": "jquery-validation" -} \ No newline at end of file diff --git a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery/.bower.json b/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery/.bower.json deleted file mode 100644 index 419488b5b..000000000 --- a/identity-server/clients/src/MvcHybridBackChannel/wwwroot/lib/jquery/.bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "jquery", - "main": "dist/jquery.js", - "license": "MIT", - "ignore": [ - "package.json" - ], - "keywords": [ - "jquery", - "javascript", - "browser", - "library" - ], - "homepage": "https://github.com/jquery/jquery-dist", - "version": "2.2.0", - "_release": "2.2.0", - "_resolution": { - "type": "version", - "tag": "2.2.0", - "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" - }, - "_source": "git://github.com/jquery/jquery-dist.git", - "_target": "2.2.0", - "_originalSource": "jquery" -} \ No newline at end of file diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Data/ApplicationDbContext.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Data/ApplicationDbContext.cs deleted file mode 100644 index 00cd3c7e2..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Data/ApplicationDbContext.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace IdentityServerHost.Data; - -public class ApplicationDbContext : IdentityDbContext -{ - public ApplicationDbContext(DbContextOptions options) - : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder builder) => base.OnModelCreating(builder);// Customize the ASP.NET Identity model and override the defaults if needed.// For example, you can rename the ASP.NET Identity table names and more.// Add your customizations after calling base.OnModelCreating(builder); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/GlobalSuppressions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Host.AspNetIdentity10.csproj b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Host.AspNetIdentity10.csproj deleted file mode 100644 index e652ce050..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Host.AspNetIdentity10.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - net10.0 - IdentityServerHost - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/HostingExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/HostingExtensions.cs deleted file mode 100644 index 1023ca2df..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/HostingExtensions.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using IdentityServerHost.Data; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddDbContext(options => - options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); - - builder.Services.AddIdentity(opt => - { - { - opt.Password.RequireDigit = false; - opt.Password.RequireLowercase = false; - opt.Password.RequireUppercase = false; - opt.Password.RequireNonAlphanumeric = false; - opt.Password.RequireUppercase = false; - opt.Password.RequiredLength = 3; // Too short for production, but allows bob/bob - } - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityConstants.ApplicationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/IdentityServerExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/IdentityServerExtensions.cs deleted file mode 100644 index fd7c56e7d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/IdentityServerExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.UI.AspNetIdentity.Models; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - builder.Services.AddIdentityServer(opt => - { - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - opt.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - } - ) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - .AddInMemoryClients(TestClients.Get()) - .AddAspNetIdentity(); - - return builder; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Program.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Properties/launchSettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/appsettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity10/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity10/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Data/ApplicationDbContext.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Data/ApplicationDbContext.cs deleted file mode 100644 index 00cd3c7e2..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Data/ApplicationDbContext.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace IdentityServerHost.Data; - -public class ApplicationDbContext : IdentityDbContext -{ - public ApplicationDbContext(DbContextOptions options) - : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder builder) => base.OnModelCreating(builder);// Customize the ASP.NET Identity model and override the defaults if needed.// For example, you can rename the ASP.NET Identity table names and more.// Add your customizations after calling base.OnModelCreating(builder); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/GlobalSuppressions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Host.AspNetIdentity8.csproj b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Host.AspNetIdentity8.csproj deleted file mode 100644 index e43b35913..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Host.AspNetIdentity8.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - net8.0 - IdentityServerHost - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/HostingExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/HostingExtensions.cs deleted file mode 100644 index 08a5cf6d6..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/HostingExtensions.cs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using IdentityServerHost.Data; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddDbContext(options => - options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); - - builder.Services.AddIdentity(opt => - { - opt.Password.RequireDigit = false; - opt.Password.RequireLowercase = false; - opt.Password.RequireUppercase = false; - opt.Password.RequireNonAlphanumeric = false; - opt.Password.RequireUppercase = false; - opt.Password.RequiredLength = 3; // Too short for production, but allows bob/bob - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityConstants.ApplicationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/IdentityServerExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/IdentityServerExtensions.cs deleted file mode 100644 index fd7c56e7d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/IdentityServerExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.UI.AspNetIdentity.Models; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - builder.Services.AddIdentityServer(opt => - { - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - opt.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - } - ) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - .AddInMemoryClients(TestClients.Get()) - .AddAspNetIdentity(); - - return builder; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Program.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Properties/launchSettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/appsettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity8/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity8/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Data/ApplicationDbContext.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Data/ApplicationDbContext.cs deleted file mode 100644 index 00cd3c7e2..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Data/ApplicationDbContext.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace IdentityServerHost.Data; - -public class ApplicationDbContext : IdentityDbContext -{ - public ApplicationDbContext(DbContextOptions options) - : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder builder) => base.OnModelCreating(builder);// Customize the ASP.NET Identity model and override the defaults if needed.// For example, you can rename the ASP.NET Identity table names and more.// Add your customizations after calling base.OnModelCreating(builder); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/GlobalSuppressions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Host.AspNetIdentity9.csproj b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Host.AspNetIdentity9.csproj deleted file mode 100644 index b80404e9e..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Host.AspNetIdentity9.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - net9.0 - IdentityServerHost - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/HostingExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/HostingExtensions.cs deleted file mode 100644 index 1023ca2df..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/HostingExtensions.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.AspNetIdentity.Models; -using IdentityServerHost.Data; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddDbContext(options => - options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); - - builder.Services.AddIdentity(opt => - { - { - opt.Password.RequireDigit = false; - opt.Password.RequireLowercase = false; - opt.Password.RequireUppercase = false; - opt.Password.RequireNonAlphanumeric = false; - opt.Password.RequireUppercase = false; - opt.Password.RequiredLength = 3; // Too short for production, but allows bob/bob - } - }) - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityConstants.ApplicationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityConstants.ApplicationScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/IdentityServerExtensions.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/IdentityServerExtensions.cs deleted file mode 100644 index fd7c56e7d..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/IdentityServerExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.UI.AspNetIdentity.Models; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - builder.Services.AddIdentityServer(opt => - { - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - opt.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - } - ) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - .AddInMemoryClients(TestClients.Get()) - .AddAspNetIdentity(); - - return builder; - } -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Program.cs b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Properties/launchSettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/appsettings.json b/identity-server/hosts/AspNetIdentity/AspNetIdentity9/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/AspNetIdentity/AspNetIdentity9/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/Directory.Build.props b/identity-server/hosts/Directory.Build.props deleted file mode 100644 index 00b5bb369..000000000 --- a/identity-server/hosts/Directory.Build.props +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - true - - diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/GlobalSuppressions.cs b/identity-server/hosts/EntityFramework/EntityFramework10/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/Host.EntityFramework10.csproj b/identity-server/hosts/EntityFramework/EntityFramework10/Host.EntityFramework10.csproj deleted file mode 100644 index b1a355ee4..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/Host.EntityFramework10.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - net10.0 - IdentityServerHost - enable - all - true - enable - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/HostingExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework10/HostingExtensions.cs deleted file mode 100644 index 4c02e202e..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/HostingExtensions.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.ApiScopes; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.IdentityScopes; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer (Configuration)", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - app.MapDynamicClientRegistration() - .AllowAnonymous(); - - return app; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/IdentityServerExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework10/IdentityServerExtensions.cs deleted file mode 100644 index 7a9459be7..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/IdentityServerExtensions.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Configuration.EntityFramework; -using Duende.IdentityServer.Configuration.RequestProcessing; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); - - builder.Services.AddIdentityServer(options => - { - options.Authentication.CoordinateClientLifetimesWithUserSession = true; - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - options.ServerSideSessions.RemoveExpiredSessions = true; - options.ServerSideSessions.ExpiredSessionsTriggerBackchannelLogout = true; - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - - // Imported options - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddTestUsers(TestUsers.Users) - // this adds the config data from DB (clients, resources, CORS) - .AddConfigurationStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - }) - // this adds the operational data from DB (codes, tokens, consents) - .AddOperationalStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - - // this enables automatic token cleanup. this is optional. - options.EnableTokenCleanup = true; - options.RemoveConsumedTokens = true; - }) - .AddAppAuthRedirectUriValidator() - .AddServerSideSessions() - - // this is something you will want in production to reduce load on and requests to the DB - //.AddConfigurationStoreCache() - - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddLicenseSummary(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddClientConfigurationStore(); - - builder.Services.AddTransient(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expects keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/LocalApiController.cs b/identity-server/hosts/EntityFramework/EntityFramework10/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/Program.cs b/identity-server/hosts/EntityFramework/EntityFramework10/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/Properties/launchSettings.json b/identity-server/hosts/EntityFramework/EntityFramework10/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/TestOperationalStoreNotification.cs b/identity-server/hosts/EntityFramework/EntityFramework10/TestOperationalStoreNotification.cs deleted file mode 100644 index b54240ef8..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/TestOperationalStoreNotification.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -#pragma warning disable CA1303 // Do not pass literals as localized parameters - -using Duende.IdentityServer.EntityFramework; -using Duende.IdentityServer.EntityFramework.Entities; - -namespace IdentityServerHost; - -public class TestOperationalStoreNotification : IOperationalStoreNotification -{ - public TestOperationalStoreNotification() => Console.WriteLine("ctor"); - - public Task PersistedGrantsRemovedAsync(IEnumerable persistedGrants, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(persistedGrants); - foreach (var grant in persistedGrants) - { - Console.WriteLine("cleaned: " + grant.Type); - } - return Task.CompletedTask; - } - - public Task DeviceCodesRemovedAsync(IEnumerable deviceCodes, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(deviceCodes); - foreach (var deviceCode in deviceCodes) - { - Console.WriteLine("cleaned device code"); - } - return Task.CompletedTask; - } - - public Task ServerSideSessionsRemovedAsync(IEnumerable userSessions, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(userSessions); - foreach (var session in userSessions) - { - Console.WriteLine("cleaned user session"); - } - return Task.CompletedTask; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework10/appsettings.json b/identity-server/hosts/EntityFramework/EntityFramework10/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework10/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/GlobalSuppressions.cs b/identity-server/hosts/EntityFramework/EntityFramework8/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/Host.EntityFramework8.csproj b/identity-server/hosts/EntityFramework/EntityFramework8/Host.EntityFramework8.csproj deleted file mode 100644 index 38950018b..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/Host.EntityFramework8.csproj +++ /dev/null @@ -1,36 +0,0 @@ - - - net8.0 - IdentityServerHost - enable - all - true - enable - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/HostingExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework8/HostingExtensions.cs deleted file mode 100644 index 4c02e202e..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/HostingExtensions.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.ApiScopes; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.IdentityScopes; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer (Configuration)", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - app.MapDynamicClientRegistration() - .AllowAnonymous(); - - return app; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/IdentityServerExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework8/IdentityServerExtensions.cs deleted file mode 100644 index 7a9459be7..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/IdentityServerExtensions.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Configuration.EntityFramework; -using Duende.IdentityServer.Configuration.RequestProcessing; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); - - builder.Services.AddIdentityServer(options => - { - options.Authentication.CoordinateClientLifetimesWithUserSession = true; - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - options.ServerSideSessions.RemoveExpiredSessions = true; - options.ServerSideSessions.ExpiredSessionsTriggerBackchannelLogout = true; - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - - // Imported options - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddTestUsers(TestUsers.Users) - // this adds the config data from DB (clients, resources, CORS) - .AddConfigurationStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - }) - // this adds the operational data from DB (codes, tokens, consents) - .AddOperationalStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - - // this enables automatic token cleanup. this is optional. - options.EnableTokenCleanup = true; - options.RemoveConsumedTokens = true; - }) - .AddAppAuthRedirectUriValidator() - .AddServerSideSessions() - - // this is something you will want in production to reduce load on and requests to the DB - //.AddConfigurationStoreCache() - - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddLicenseSummary(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddClientConfigurationStore(); - - builder.Services.AddTransient(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expects keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/LocalApiController.cs b/identity-server/hosts/EntityFramework/EntityFramework8/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/Program.cs b/identity-server/hosts/EntityFramework/EntityFramework8/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/Properties/launchSettings.json b/identity-server/hosts/EntityFramework/EntityFramework8/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/TestOperationalStoreNotification.cs b/identity-server/hosts/EntityFramework/EntityFramework8/TestOperationalStoreNotification.cs deleted file mode 100644 index b54240ef8..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/TestOperationalStoreNotification.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -#pragma warning disable CA1303 // Do not pass literals as localized parameters - -using Duende.IdentityServer.EntityFramework; -using Duende.IdentityServer.EntityFramework.Entities; - -namespace IdentityServerHost; - -public class TestOperationalStoreNotification : IOperationalStoreNotification -{ - public TestOperationalStoreNotification() => Console.WriteLine("ctor"); - - public Task PersistedGrantsRemovedAsync(IEnumerable persistedGrants, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(persistedGrants); - foreach (var grant in persistedGrants) - { - Console.WriteLine("cleaned: " + grant.Type); - } - return Task.CompletedTask; - } - - public Task DeviceCodesRemovedAsync(IEnumerable deviceCodes, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(deviceCodes); - foreach (var deviceCode in deviceCodes) - { - Console.WriteLine("cleaned device code"); - } - return Task.CompletedTask; - } - - public Task ServerSideSessionsRemovedAsync(IEnumerable userSessions, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(userSessions); - foreach (var session in userSessions) - { - Console.WriteLine("cleaned user session"); - } - return Task.CompletedTask; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework8/appsettings.json b/identity-server/hosts/EntityFramework/EntityFramework8/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework8/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/GlobalSuppressions.cs b/identity-server/hosts/EntityFramework/EntityFramework9/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/Host.EntityFramework9.csproj b/identity-server/hosts/EntityFramework/EntityFramework9/Host.EntityFramework9.csproj deleted file mode 100644 index 216a2eb7c..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/Host.EntityFramework9.csproj +++ /dev/null @@ -1,37 +0,0 @@ - - - - net9.0 - IdentityServerHost - enable - all - true - enable - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/HostingExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework9/HostingExtensions.cs deleted file mode 100644 index 4c02e202e..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/HostingExtensions.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.ApiScopes; -using Duende.IdentityServer.UI.EntityFramework.Pages.Admin.IdentityScopes; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddRazorPages() - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - builder.Services.AddTransient(); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer (Configuration)", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - app.MapDynamicClientRegistration() - .AllowAnonymous(); - - return app; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/IdentityServerExtensions.cs b/identity-server/hosts/EntityFramework/EntityFramework9/IdentityServerExtensions.cs deleted file mode 100644 index 7a9459be7..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/IdentityServerExtensions.cs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Configuration.EntityFramework; -using Duende.IdentityServer.Configuration.RequestProcessing; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.EntityFrameworkCore; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); - - builder.Services.AddIdentityServer(options => - { - options.Authentication.CoordinateClientLifetimesWithUserSession = true; - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - options.ServerSideSessions.RemoveExpiredSessions = true; - options.ServerSideSessions.ExpiredSessionsTriggerBackchannelLogout = true; - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - - // Imported options - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddTestUsers(TestUsers.Users) - // this adds the config data from DB (clients, resources, CORS) - .AddConfigurationStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - }) - // this adds the operational data from DB (codes, tokens, consents) - .AddOperationalStore(options => - { - options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString); - - // this enables automatic token cleanup. this is optional. - options.EnableTokenCleanup = true; - options.RemoveConsumedTokens = true; - }) - .AddAppAuthRedirectUriValidator() - .AddServerSideSessions() - - // this is something you will want in production to reduce load on and requests to the DB - //.AddConfigurationStoreCache() - - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddLicenseSummary(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddClientConfigurationStore(); - - builder.Services.AddTransient(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expects keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/LocalApiController.cs b/identity-server/hosts/EntityFramework/EntityFramework9/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/Program.cs b/identity-server/hosts/EntityFramework/EntityFramework9/Program.cs deleted file mode 100644 index 9cb7b8982..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/Program.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Serilog; - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/Properties/launchSettings.json b/identity-server/hosts/EntityFramework/EntityFramework9/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/TestOperationalStoreNotification.cs b/identity-server/hosts/EntityFramework/EntityFramework9/TestOperationalStoreNotification.cs deleted file mode 100644 index b54240ef8..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/TestOperationalStoreNotification.cs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -#pragma warning disable CA1303 // Do not pass literals as localized parameters - -using Duende.IdentityServer.EntityFramework; -using Duende.IdentityServer.EntityFramework.Entities; - -namespace IdentityServerHost; - -public class TestOperationalStoreNotification : IOperationalStoreNotification -{ - public TestOperationalStoreNotification() => Console.WriteLine("ctor"); - - public Task PersistedGrantsRemovedAsync(IEnumerable persistedGrants, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(persistedGrants); - foreach (var grant in persistedGrants) - { - Console.WriteLine("cleaned: " + grant.Type); - } - return Task.CompletedTask; - } - - public Task DeviceCodesRemovedAsync(IEnumerable deviceCodes, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(deviceCodes); - foreach (var deviceCode in deviceCodes) - { - Console.WriteLine("cleaned device code"); - } - return Task.CompletedTask; - } - - public Task ServerSideSessionsRemovedAsync(IEnumerable userSessions, CancellationToken cancellationToken = default) - { - ArgumentNullException.ThrowIfNull(userSessions); - foreach (var session in userSessions) - { - Console.WriteLine("cleaned user session"); - } - return Task.CompletedTask; - } -} diff --git a/identity-server/hosts/EntityFramework/EntityFramework9/appsettings.json b/identity-server/hosts/EntityFramework/EntityFramework9/appsettings.json deleted file mode 100644 index 7f07c90aa..000000000 --- a/identity-server/hosts/EntityFramework/EntityFramework9/appsettings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "ConnectionStrings": { - "DefaultConnection": "" - } -} diff --git a/identity-server/hosts/Main/Main10/GlobalSuppressions.cs b/identity-server/hosts/Main/Main10/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/Main/Main10/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/Main/Main10/Host.Main10.csproj b/identity-server/hosts/Main/Main10/Host.Main10.csproj deleted file mode 100644 index a6af39bfe..000000000 --- a/identity-server/hosts/Main/Main10/Host.Main10.csproj +++ /dev/null @@ -1,192 +0,0 @@ - - - - net10.0 - InProcess - IdentityServerHost - e60c119c-8b86-4016-9d44-80e25948dbba - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Index.nb-NO.resx - - - True - True - LoggedOut.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - LoggedOut.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/identity-server/hosts/Main/Main10/HostingExtensions.cs b/identity-server/hosts/Main/Main10/HostingExtensions.cs deleted file mode 100644 index 7435c6324..000000000 --- a/identity-server/hosts/Main/Main10/HostingExtensions.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); - - builder.Services.Configure(options => - { - var supportedCultures = new[] - { - new CultureInfo("en-US"), - new CultureInfo("nb-NO") - }; - - options.SupportedCultures = supportedCultures; - options.SupportedUICultures = supportedCultures; - options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture(supportedCultures[0]); - }); - - builder.Services.AddRazorPages() - .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix) - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - - var locOptions = app.Services.GetRequiredService>(); - app.UseRequestLocalization(locOptions.Value); - - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/Main/Main10/IdentityServerExtensions.cs b/identity-server/hosts/Main/Main10/IdentityServerExtensions.cs deleted file mode 100644 index e9108e231..000000000 --- a/identity-server/hosts/Main/Main10/IdentityServerExtensions.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var identityServer = builder.Services.AddIdentityServer(options => - { - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddServerSideSessions() - .AddInMemoryClients([.. TestClients.Get()]) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddTestUsers(TestUsers.Users) - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddInMemoryOidcProviders( - [ - new Duende.IdentityServer.Models.OidcProvider - { - Scheme = "dynamicprovider-idsvr", - DisplayName = "IdentityServer (via Dynamic Providers)", - Authority = "https://demo.duendesoftware.com", - ClientId = "login", - ResponseType = "id_token", - Scope = "openid profile" - } - ]) - .AddLicenseSummary(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddInMemoryClientConfigurationStore(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expect keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/Main/Main10/LocalApiController.cs b/identity-server/hosts/Main/Main10/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/Main/Main10/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/Main/Main10/Program.cs b/identity-server/hosts/Main/Main10/Program.cs deleted file mode 100644 index 5b2d726e6..000000000 --- a/identity-server/hosts/Main/Main10/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Resources; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Microsoft.Extensions.Localization; -using Serilog; - -// Note: This is necessary for localization to work correctly since our root namespace does -// not match the assembly name. -[assembly: RootNamespace("IdentityServerHost")] -[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/Main/Main10/Properties/launchSettings.json b/identity-server/hosts/Main/Main10/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/Main/Main10/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs deleted file mode 100644 index fa541fb5d..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Login { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Login.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Login { - get { - return ResourceManager.GetString("Login", resourceCulture); - } - } - - internal static string Choose_how_to_login { - get { - return ResourceManager.GetString("Choose how to login", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.resx b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.resx deleted file mode 100644 index 319ab80dd..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Login/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Inn - - - Velg hvordan du vil logge inn - - diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs deleted file mode 100644 index db8feea3f..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.resx b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.resx deleted file mode 100644 index 70269e763..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/Index.nb-NO.resx +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs deleted file mode 100644 index 0ec5aa390..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class LoggedOut_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal LoggedOut_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.LoggedOut_nb_NO", typeof(LoggedOut_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - - internal static string You_are_now_logged_out { - get { - return ResourceManager.GetString("You are now logged out", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx b/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx deleted file mode 100644 index 51e8edf5d..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - - Du er nå logget ut - - diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs deleted file mode 100644 index 0d2856b54..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Home.Error { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Home.Error.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Error { - get { - return ResourceManager.GetString("Error", resourceCulture); - } - } - - internal static string Sorry__there_was_an_error { - get { - return ResourceManager.GetString("Sorry, there was an error", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.resx b/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.resx deleted file mode 100644 index e7e89c2de..000000000 --- a/identity-server/hosts/Main/Main10/Resources/Pages/Home/Error/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Feil - - - Beklage, det oppsto en feil - - diff --git a/identity-server/hosts/Main/Main10/appsettings.json b/identity-server/hosts/Main/Main10/appsettings.json deleted file mode 100644 index a10ef13f6..000000000 --- a/identity-server/hosts/Main/Main10/appsettings.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "Serilog": { - "MinimumLevel": { - "Default": "Debug", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "Microsoft.AspNetCore.Authentication": "Debug", - "System": "Warning" - } - } - }, - - "ApiScopes": [ - { - "Name": "IdentityServerApi" - }, - { - "Name": "resource1.scope1" - }, - { - "Name": "resource2.scope1" - }, - { - "Name": "scope3" - }, - { - "Name": "shared.scope" - }, - { - "Name": "transaction", - "DisplayName": "Transaction", - "Description": "A transaction" - } - ], - - "ApiResources": [ - { - "Name": "resource1", - "DisplayName": "Resource #1", - - "Scopes": [ - "resource1.scope1", - "shared.scope" - ] - }, - { - "Name": "resource2", - "DisplayName": "Resource #2", - - "UserClaims": [ - "name", - "email" - ], - - "Scopes": [ - "resource2.scope1", - "shared.scope" - ] - } - ], - - "Clients": [ - { - "ClientId": "machine_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "client_credentials" ], - "AllowedScopes": [ "resource1.scope1", "resource1.scope2" ], - "Properties": { "foo": "bar" }, - "Claims": [ - { - "type": "c1", - "value": "c1value" - }, - { - "type": "c2", - "value": "c2value" - } - ] - }, - { - "ClientId": "interactive_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "authorization_code", "client_credentials" ], - "AllowedScopes": [ "openid", "profile", "resource1.scope1", "resource1.scope2" ] - } - ] -} diff --git a/identity-server/hosts/Main/Main8/GlobalSuppressions.cs b/identity-server/hosts/Main/Main8/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/Main/Main8/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/Main/Main8/Host.Main8.csproj b/identity-server/hosts/Main/Main8/Host.Main8.csproj deleted file mode 100644 index d55b71317..000000000 --- a/identity-server/hosts/Main/Main8/Host.Main8.csproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - net8.0 - InProcess - IdentityServerHost - e60c119c-8b86-4016-9d44-80e25948dbba - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Index.nb-NO.resx - - - True - True - LoggedOut.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - - - - true - PreserveNewest - - - - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - LoggedOut.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - diff --git a/identity-server/hosts/Main/Main8/HostingExtensions.cs b/identity-server/hosts/Main/Main8/HostingExtensions.cs deleted file mode 100644 index 7435c6324..000000000 --- a/identity-server/hosts/Main/Main8/HostingExtensions.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); - - builder.Services.Configure(options => - { - var supportedCultures = new[] - { - new CultureInfo("en-US"), - new CultureInfo("nb-NO") - }; - - options.SupportedCultures = supportedCultures; - options.SupportedUICultures = supportedCultures; - options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture(supportedCultures[0]); - }); - - builder.Services.AddRazorPages() - .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix) - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - - var locOptions = app.Services.GetRequiredService>(); - app.UseRequestLocalization(locOptions.Value); - - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/Main/Main8/IdentityServerExtensions.cs b/identity-server/hosts/Main/Main8/IdentityServerExtensions.cs deleted file mode 100644 index e9108e231..000000000 --- a/identity-server/hosts/Main/Main8/IdentityServerExtensions.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var identityServer = builder.Services.AddIdentityServer(options => - { - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddServerSideSessions() - .AddInMemoryClients([.. TestClients.Get()]) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddTestUsers(TestUsers.Users) - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddInMemoryOidcProviders( - [ - new Duende.IdentityServer.Models.OidcProvider - { - Scheme = "dynamicprovider-idsvr", - DisplayName = "IdentityServer (via Dynamic Providers)", - Authority = "https://demo.duendesoftware.com", - ClientId = "login", - ResponseType = "id_token", - Scope = "openid profile" - } - ]) - .AddLicenseSummary(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddInMemoryClientConfigurationStore(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expect keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/Main/Main8/LocalApiController.cs b/identity-server/hosts/Main/Main8/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/Main/Main8/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/Main/Main8/Program.cs b/identity-server/hosts/Main/Main8/Program.cs deleted file mode 100644 index 5b2d726e6..000000000 --- a/identity-server/hosts/Main/Main8/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Resources; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Microsoft.Extensions.Localization; -using Serilog; - -// Note: This is necessary for localization to work correctly since our root namespace does -// not match the assembly name. -[assembly: RootNamespace("IdentityServerHost")] -[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/Main/Main8/Properties/launchSettings.json b/identity-server/hosts/Main/Main8/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/Main/Main8/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs deleted file mode 100644 index fa541fb5d..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Login { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Login.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Login { - get { - return ResourceManager.GetString("Login", resourceCulture); - } - } - - internal static string Choose_how_to_login { - get { - return ResourceManager.GetString("Choose how to login", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.resx b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.resx deleted file mode 100644 index 319ab80dd..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Login/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Inn - - - Velg hvordan du vil logge inn - - diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs deleted file mode 100644 index db8feea3f..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.resx b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.resx deleted file mode 100644 index 70269e763..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/Index.nb-NO.resx +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs deleted file mode 100644 index 0ec5aa390..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class LoggedOut_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal LoggedOut_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.LoggedOut_nb_NO", typeof(LoggedOut_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - - internal static string You_are_now_logged_out { - get { - return ResourceManager.GetString("You are now logged out", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx b/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx deleted file mode 100644 index 51e8edf5d..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - - Du er nå logget ut - - diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs deleted file mode 100644 index 0d2856b54..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Home.Error { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Home.Error.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Error { - get { - return ResourceManager.GetString("Error", resourceCulture); - } - } - - internal static string Sorry__there_was_an_error { - get { - return ResourceManager.GetString("Sorry, there was an error", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.resx b/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.resx deleted file mode 100644 index e7e89c2de..000000000 --- a/identity-server/hosts/Main/Main8/Resources/Pages/Home/Error/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Feil - - - Beklage, det oppsto en feil - - diff --git a/identity-server/hosts/Main/Main8/appsettings.json b/identity-server/hosts/Main/Main8/appsettings.json deleted file mode 100644 index a10ef13f6..000000000 --- a/identity-server/hosts/Main/Main8/appsettings.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "Serilog": { - "MinimumLevel": { - "Default": "Debug", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "Microsoft.AspNetCore.Authentication": "Debug", - "System": "Warning" - } - } - }, - - "ApiScopes": [ - { - "Name": "IdentityServerApi" - }, - { - "Name": "resource1.scope1" - }, - { - "Name": "resource2.scope1" - }, - { - "Name": "scope3" - }, - { - "Name": "shared.scope" - }, - { - "Name": "transaction", - "DisplayName": "Transaction", - "Description": "A transaction" - } - ], - - "ApiResources": [ - { - "Name": "resource1", - "DisplayName": "Resource #1", - - "Scopes": [ - "resource1.scope1", - "shared.scope" - ] - }, - { - "Name": "resource2", - "DisplayName": "Resource #2", - - "UserClaims": [ - "name", - "email" - ], - - "Scopes": [ - "resource2.scope1", - "shared.scope" - ] - } - ], - - "Clients": [ - { - "ClientId": "machine_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "client_credentials" ], - "AllowedScopes": [ "resource1.scope1", "resource1.scope2" ], - "Properties": { "foo": "bar" }, - "Claims": [ - { - "type": "c1", - "value": "c1value" - }, - { - "type": "c2", - "value": "c2value" - } - ] - }, - { - "ClientId": "interactive_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "authorization_code", "client_credentials" ], - "AllowedScopes": [ "openid", "profile", "resource1.scope1", "resource1.scope2" ] - } - ] -} diff --git a/identity-server/hosts/Main/Main9/GlobalSuppressions.cs b/identity-server/hosts/Main/Main9/GlobalSuppressions.cs deleted file mode 100644 index fa2f3948d..000000000 --- a/identity-server/hosts/Main/Main9/GlobalSuppressions.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -// shared -[assembly: SuppressMessage("Design", "CA1031:Do not catch general exception types", Justification = "Main catches and logs all exceptions by design")] -[assembly: SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Resources is only used for initialization, so there is little chance of confusion", Scope = "type", Target = "~T:IdentityServerHost.Configuration.Resources")] -[assembly: SuppressMessage("Maintainability", "CA1515:Consider making public types internal", Justification = "Maybe we'll do this someday, but right now it seems a dull chore", Scope = "module")] diff --git a/identity-server/hosts/Main/Main9/Host.Main9.csproj b/identity-server/hosts/Main/Main9/Host.Main9.csproj deleted file mode 100644 index afbdeb188..000000000 --- a/identity-server/hosts/Main/Main9/Host.Main9.csproj +++ /dev/null @@ -1,82 +0,0 @@ - - - - net9.0 - InProcess - IdentityServerHost - e60c119c-8b86-4016-9d44-80e25948dbba - enable - all - - - - - - - - - - - - - - - - - - - - - - - - - - - True - True - Index.nb-NO.resx - - - True - True - LoggedOut.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - True - True - Index.nb-NO.resx - - - - - - true - PreserveNewest - - - - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - LoggedOut.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - ResXFileCodeGenerator - Index.nb-NO.Designer.cs - - - diff --git a/identity-server/hosts/Main/Main9/HostingExtensions.cs b/identity-server/hosts/Main/Main9/HostingExtensions.cs deleted file mode 100644 index 7435c6324..000000000 --- a/identity-server/hosts/Main/Main9/HostingExtensions.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Security.Claims; -using Duende.IdentityServer; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Duende.IdentityServer.UI; -using Microsoft.AspNetCore.Mvc.Razor; -using Microsoft.AspNetCore.Mvc.RazorPages; -using Microsoft.AspNetCore.Server.Kestrel.Core; -using Microsoft.AspNetCore.Server.Kestrel.Https; -using Microsoft.Extensions.Options; -using Microsoft.IdentityModel.Tokens; -using Serilog; - -namespace IdentityServerHost; - -internal static class HostingExtensions -{ - internal static WebApplication ConfigureServices(this WebApplicationBuilder builder) - { - builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); - - builder.Services.Configure(options => - { - var supportedCultures = new[] - { - new CultureInfo("en-US"), - new CultureInfo("nb-NO") - }; - - options.SupportedCultures = supportedCultures; - options.SupportedUICultures = supportedCultures; - options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture(supportedCultures[0]); - }); - - builder.Services.AddRazorPages() - .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix) - .AddRazorRuntimeCompilation(); - - builder.Services.AddControllers(); - builder.Services.AddHealthChecks() - .AddCheck("DiscoveryHealthCheck") - .AddCheck("DiscoveryKeysHealthCheck"); - - // cookie policy to deal with temporary browser incompatibilities - builder.Services.AddSameSiteCookiePolicy(); - - builder.ConfigureIdentityServer(); - builder.AddExternalIdentityProviders(); - - builder.AddAdminFeatures(); - - builder.Services.AddLocalApiAuthentication(principal => - { - principal.Identities.First().AddClaim(new Claim("additional_claim", "additional_value")); - - return Task.FromResult(principal); - }); - - builder.Services.Configure(kestrelOptions => - { - kestrelOptions.ConfigureHttpsDefaults(https => - { - https.ClientCertificateMode = ClientCertificateMode.AllowCertificate; - https.AllowAnyClientCertificate(); // Needed for the "ephemeral" mtls client - }); - }); - - builder.AddIdentityServerUI(); - - return builder.Build(); - } - - private static void AddAdminFeatures(this WebApplicationBuilder builder) - { - builder.Services.AddAuthorization(options => - options.AddPolicy("admin", - policy => policy.RequireClaim("sub", "1")) - ); - - builder.Services.Configure(options => - options.Conventions.AuthorizeFolder("/Admin", "admin")); - } - - private static void AddExternalIdentityProviders(this WebApplicationBuilder builder) - { - // configures the OpenIdConnect handlers to persist the state parameter into the server-side IDistributedCache. - builder.Services.AddOidcStateDataFormatterCache("aad", "demoidsrv"); - - builder.Services.AddAuthentication() - .AddOpenIdConnect("Google", "Google", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.ForwardSignOut = IdentityServerConstants.DefaultCookieAuthenticationScheme; - - options.Authority = "https://accounts.google.com/"; - options.ClientId = "708996912208-9m4dkjb5hscn7cjrn5u0r4tbgkbj1fko.apps.googleusercontent.com"; - - options.CallbackPath = "/signin-google"; - options.Scope.Add("email"); - options.MapInboundClaims = false; - }) - .AddOpenIdConnect("demoidsrv", "IdentityServer", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://demo.duendesoftware.com"; - options.ClientId = "login"; - options.ResponseType = "id_token"; - options.SaveTokens = true; - options.CallbackPath = "/signin-idsrv"; - options.SignedOutCallbackPath = "/signout-callback-idsrv"; - options.RemoteSignOutPath = "/signout-idsrv"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }) - .AddOpenIdConnect("aad", "Azure AD", options => - { - options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; - options.SignOutScheme = IdentityServerConstants.SignoutScheme; - - options.Authority = "https://login.windows.net/4ca9cb4c-5e5f-4be9-b700-c532992a3705"; - options.ClientId = "96e3c53e-01cb-4244-b658-a42164cb67a9"; - options.ResponseType = "id_token"; - options.CallbackPath = "/signin-aad"; - options.SignedOutCallbackPath = "/signout-callback-aad"; - options.RemoteSignOutPath = "/signout-aad"; - options.MapInboundClaims = false; - - options.TokenValidationParameters = new TokenValidationParameters - { - NameClaimType = "name", - RoleClaimType = "role" - }; - }); - } - - internal static WebApplication ConfigurePipeline(this WebApplication app) - { - app.UseSerilogRequestLogging(); - - app.UseCookiePolicy(); - - app.UseDeveloperExceptionPage(); - app.UseStaticFiles(); - - app.UseRouting(); - - var locOptions = app.Services.GetRequiredService>(); - app.UseRequestLocalization(locOptions.Value); - - app.UseIdentityServer(); - app.UseAuthorization(); - - // health checks - app.MapHealthChecks("/health"); - - // local API endpoints - app.MapControllers() - .RequireAuthorization(IdentityServerConstants.LocalApi.PolicyName); - - // UI - app.MapRazorPages() - .RequireAuthorization(); - - return app; - } -} diff --git a/identity-server/hosts/Main/Main9/IdentityServerExtensions.cs b/identity-server/hosts/Main/Main9/IdentityServerExtensions.cs deleted file mode 100644 index e9108e231..000000000 --- a/identity-server/hosts/Main/Main9/IdentityServerExtensions.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Security.Cryptography.X509Certificates; -using Duende.IdentityModel; -using Duende.IdentityServer; -using Duende.IdentityServer.Configuration; -using Duende.IdentityServer.Hosts.Shared.Configuration; -using Duende.IdentityServer.Hosts.Shared.Customization; -using Microsoft.AspNetCore.Authentication.Certificate; -using Microsoft.IdentityModel.Tokens; - -namespace IdentityServerHost; - -internal static class IdentityServerExtensions -{ - internal static WebApplicationBuilder ConfigureIdentityServer(this WebApplicationBuilder builder) - { - var identityServer = builder.Services.AddIdentityServer(options => - { - options.Events.RaiseSuccessEvents = true; - options.Events.RaiseFailureEvents = true; - options.Events.RaiseErrorEvents = true; - options.Events.RaiseInformationEvents = true; - - options.EmitScopesAsSpaceDelimitedStringInJwt = true; - options.Endpoints.EnableJwtRequestUri = true; - - options.ServerSideSessions.UserDisplayNameClaimType = JwtClaimTypes.Name; - - options.UserInteraction.CreateAccountUrl = "/Account/Create"; - - options.Endpoints.EnablePushedAuthorizationEndpoint = true; - options.PushedAuthorization.AllowUnregisteredPushedRedirectUris = true; - - options.KeyManagement.SigningAlgorithms.Add(new SigningAlgorithmOptions - { - Name = "RS256", - UseX509Certificate = true - }); - - // In load-balanced environments, synchronization delay is important. - // In development, we're never load balanced and can skip it to start up faster. - if (builder.Environment.IsDevelopment()) - { - options.KeyManagement.InitializationSynchronizationDelay = TimeSpan.Zero; - } - - options.MutualTls.Enabled = true; - - options.Diagnostics.ChunkSize = 1024 * 1000 - 32; // 1 MB minus some formatting space; - }) - .AddServerSideSessions() - .AddInMemoryClients([.. TestClients.Get()]) - .AddInMemoryIdentityResources(TestResources.IdentityResources) - .AddInMemoryApiResources(TestResources.ApiResources) - .AddInMemoryApiScopes(TestResources.ApiScopes) - //.AddStaticSigningCredential() - .AddExtensionGrantValidator() - .AddExtensionGrantValidator() - .AddJwtBearerClientAuthentication() - .AddAppAuthRedirectUriValidator() - .AddTestUsers(TestUsers.Users) - .AddProfileService() - .AddCustomTokenRequestValidator() - .AddScopeParser() - .AddMutualTlsSecretValidators() - .AddInMemoryOidcProviders( - [ - new Duende.IdentityServer.Models.OidcProvider - { - Scheme = "dynamicprovider-idsvr", - DisplayName = "IdentityServer (via Dynamic Providers)", - Authority = "https://demo.duendesoftware.com", - ClientId = "login", - ResponseType = "id_token", - Scope = "openid profile" - } - ]) - .AddLicenseSummary(); - - builder.Services.AddIdentityServerConfiguration(opt => { }) - .AddInMemoryClientConfigurationStore(); - - builder.Services.AddDistributedMemoryCache(); - - builder.Services.AddAuthentication().AddCertificate(certificateOptions => - { - // We must allow self-signed certificates for the "ephemeral" case - certificateOptions.AllowedCertificateTypes = CertificateTypes.Chained | CertificateTypes.SelfSigned; - certificateOptions.RevocationMode = X509RevocationMode.NoCheck; - }); - - return builder; - } - - // To use static signing credentials, create keys and add it to the certificate store. - // This shows how to create both rsa and ec keys, in case you had clients that were configured to use different algorithms - // You can create keys for dev use with the mkcert util: - // mkcert -pkcs12 identityserver.test.rsa - // mkcert -pkcs12 -ecdsa identityserver.test.ecdsa - // Then import the keys into the certificate manager. This code expect keys in the personal store of the current user. - private static IIdentityServerBuilder AddStaticSigningCredential(this IIdentityServerBuilder builder) - { - var store = new X509Store(StoreName.My, StoreLocation.CurrentUser); - try - { - store.Open(OpenFlags.ReadOnly); - - var rsaCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.rsa", true) - .Single(); - builder.AddSigningCredential(rsaCert, "RS256"); - builder.AddSigningCredential(rsaCert, "PS256"); - - var ecCert = store.Certificates - .Find(X509FindType.FindBySubjectName, "identityserver.test.ecdsa", true) - .Single(); - var key = new ECDsaSecurityKey(ecCert.GetECDsaPrivateKey()) - { - KeyId = CryptoRandom.CreateUniqueId(16, CryptoRandom.OutputFormat.Hex) - }; - builder.AddSigningCredential(key, IdentityServerConstants.ECDsaSigningAlgorithm.ES256); - } - finally - { - store.Close(); - } - - return builder; - } -} diff --git a/identity-server/hosts/Main/Main9/LocalApiController.cs b/identity-server/hosts/Main/Main9/LocalApiController.cs deleted file mode 100644 index d50b17aa2..000000000 --- a/identity-server/hosts/Main/Main9/LocalApiController.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Microsoft.AspNetCore.Mvc; - -namespace IdentityServerHost; - -[Route("localApi")] -public class LocalApiController : ControllerBase -{ - public IActionResult Get() - { - var claims = from c in User.Claims select new { c.Type, c.Value }; - return new JsonResult(claims); - } -} diff --git a/identity-server/hosts/Main/Main9/Program.cs b/identity-server/hosts/Main/Main9/Program.cs deleted file mode 100644 index 5b2d726e6..000000000 --- a/identity-server/hosts/Main/Main9/Program.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using System.Globalization; -using System.Resources; -using System.Text; -using Duende.IdentityServer.Licensing; -using IdentityServerHost; -using Microsoft.Extensions.Localization; -using Serilog; - -// Note: This is necessary for localization to work correctly since our root namespace does -// not match the assembly name. -[assembly: RootNamespace("IdentityServerHost")] -[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] - -SerilogDefaults.Bootstrap(); - -try -{ - var builder = WebApplication.CreateBuilder(args); - - Console.Title = builder.Environment.ApplicationName; - Log.Information("{EnvironmentApplicationName} Starting up", builder.Environment.ApplicationName); - - builder.ConfigureSerilogDefaults(); - builder.AddServiceDefaults() - .AddOpenTelemetryMeters(Duende.IdentityServer.UI.Pages.Telemetry.ServiceName); - - var app = builder - .ConfigureServices() - .ConfigurePipeline(); - - if (app.Environment.IsDevelopment()) - { - app.Lifetime.ApplicationStopping.Register(() => - { - var usage = app.Services.GetRequiredService(); - Console.Write(Summary(usage)); - }); - } - - app.Run(); -} -catch (Exception ex) when (ex is not HostAbortedException) -{ - Log.Fatal(ex, "Unhandled exception"); -} -finally -{ - Log.Information("Shut down complete"); - Log.CloseAndFlush(); -} - -static string Summary(LicenseUsageSummary usage) -{ - var sb = new StringBuilder(); - sb.AppendLine("IdentityServer Usage Summary:"); - sb.AppendLine(CultureInfo.InvariantCulture, $" License: {usage.LicenseEdition}"); - var features = usage.FeaturesUsed.Count > 0 ? string.Join(", ", usage.FeaturesUsed) : "None"; - sb.AppendLine(CultureInfo.InvariantCulture, $" Business and Enterprise Edition Features Used: {features}"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.ClientsUsed.Count} Client Id(s) Used"); - sb.AppendLine(CultureInfo.InvariantCulture, $" {usage.IssuersUsed.Count} Issuer(s) Used"); - - return sb.ToString(); -} diff --git a/identity-server/hosts/Main/Main9/Properties/launchSettings.json b/identity-server/hosts/Main/Main9/Properties/launchSettings.json deleted file mode 100644 index ad529fa7f..000000000 --- a/identity-server/hosts/Main/Main9/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "Host": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001" - } - } -} \ No newline at end of file diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs deleted file mode 100644 index fa541fb5d..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Login { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Login.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Login { - get { - return ResourceManager.GetString("Login", resourceCulture); - } - } - - internal static string Choose_how_to_login { - get { - return ResourceManager.GetString("Choose how to login", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.resx b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.resx deleted file mode 100644 index 319ab80dd..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Login/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Inn - - - Velg hvordan du vil logge inn - - diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs deleted file mode 100644 index db8feea3f..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,54 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.resx b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.resx deleted file mode 100644 index 70269e763..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/Index.nb-NO.resx +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs deleted file mode 100644 index 0ec5aa390..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Account.Logout { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class LoggedOut_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal LoggedOut_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Account.Logout.LoggedOut_nb_NO", typeof(LoggedOut_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Logout { - get { - return ResourceManager.GetString("Logout", resourceCulture); - } - } - - internal static string You_are_now_logged_out { - get { - return ResourceManager.GetString("You are now logged out", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx b/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx deleted file mode 100644 index 51e8edf5d..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Account/Logout/LoggedOut.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Logg Ut - - - Du er nå logget ut - - diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs b/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs deleted file mode 100644 index 0d2856b54..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.Designer.cs +++ /dev/null @@ -1,60 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace IdentityServerHost.Resources.Pages.Home.Error { - using System; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Index_nb_NO { - - private static System.Resources.ResourceManager resourceMan; - - private static System.Globalization.CultureInfo resourceCulture; - - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Index_nb_NO() { - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Resources.ResourceManager ResourceManager { - get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("IdentityServerHost.Resources.Pages.Home.Error.Index_nb_NO", typeof(Index_nb_NO).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - internal static System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - internal static string Error { - get { - return ResourceManager.GetString("Error", resourceCulture); - } - } - - internal static string Sorry__there_was_an_error { - get { - return ResourceManager.GetString("Sorry, there was an error", resourceCulture); - } - } - } -} diff --git a/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.resx b/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.resx deleted file mode 100644 index e7e89c2de..000000000 --- a/identity-server/hosts/Main/Main9/Resources/Pages/Home/Error/Index.nb-NO.resx +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Feil - - - Beklage, det oppsto en feil - - diff --git a/identity-server/hosts/Main/Main9/appsettings.json b/identity-server/hosts/Main/Main9/appsettings.json deleted file mode 100644 index a10ef13f6..000000000 --- a/identity-server/hosts/Main/Main9/appsettings.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "Serilog": { - "MinimumLevel": { - "Default": "Debug", - "Override": { - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information", - "Microsoft.AspNetCore.Authentication": "Debug", - "System": "Warning" - } - } - }, - - "ApiScopes": [ - { - "Name": "IdentityServerApi" - }, - { - "Name": "resource1.scope1" - }, - { - "Name": "resource2.scope1" - }, - { - "Name": "scope3" - }, - { - "Name": "shared.scope" - }, - { - "Name": "transaction", - "DisplayName": "Transaction", - "Description": "A transaction" - } - ], - - "ApiResources": [ - { - "Name": "resource1", - "DisplayName": "Resource #1", - - "Scopes": [ - "resource1.scope1", - "shared.scope" - ] - }, - { - "Name": "resource2", - "DisplayName": "Resource #2", - - "UserClaims": [ - "name", - "email" - ], - - "Scopes": [ - "resource2.scope1", - "shared.scope" - ] - } - ], - - "Clients": [ - { - "ClientId": "machine_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "client_credentials" ], - "AllowedScopes": [ "resource1.scope1", "resource1.scope2" ], - "Properties": { "foo": "bar" }, - "Claims": [ - { - "type": "c1", - "value": "c1value" - }, - { - "type": "c2", - "value": "c2value" - } - ] - }, - { - "ClientId": "interactive_client", - "ClientSecrets": [ { "Value": "K7gNU3sdo+OL0wNhqoVWhr3g6s1xYv72ol/pe/Unols=" } ], - "AllowedGrantTypes": [ "authorization_code", "client_credentials" ], - "AllowedScopes": [ "openid", "profile", "resource1.scope1", "resource1.scope2" ] - } - ] -} diff --git a/identity-server/hosts/Shared/Host.Shared.csproj b/identity-server/hosts/Shared/Host.Shared.csproj index dee7a1949..724447fa3 100644 --- a/identity-server/hosts/Shared/Host.Shared.csproj +++ b/identity-server/hosts/Shared/Host.Shared.csproj @@ -5,6 +5,7 @@ enable enable Duende.IdentityServer.Hosts.Shared + false diff --git a/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj b/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj index c4badcf24..8286ca8bb 100644 --- a/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj +++ b/identity-server/hosts/UI/AspNetIdentity/UI.AspNetIdentity.csproj @@ -7,6 +7,7 @@ true Duende.IdentityServer.UI.AspNetIdentity true + false diff --git a/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj b/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj index 64c46b889..90af3cddc 100644 --- a/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj +++ b/identity-server/hosts/UI/EntityFramework/UI.EntityFramework.csproj @@ -7,6 +7,7 @@ true Duende.IdentityServer.UI.EntityFramework true + false diff --git a/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs b/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs index 2a160b3d6..6bab58ec3 100644 --- a/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs +++ b/identity-server/hosts/UI/Main/Pages/Diagnostics/ViewModel.cs @@ -1,9 +1,9 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace Duende.IdentityServer.UI.Pages.Diagnostics; @@ -18,7 +18,7 @@ public class ViewModel { if (encoded != null) { - var bytes = Base64Url.Decode(encoded); + var bytes = Base64Url.DecodeFromChars(encoded); var value = Encoding.UTF8.GetString(bytes); Clients = JsonSerializer.Deserialize(value) ?? Enumerable.Empty(); return; diff --git a/identity-server/hosts/UI/Main/UI.Main.csproj b/identity-server/hosts/UI/Main/UI.Main.csproj index b396d5c26..14622405b 100644 --- a/identity-server/hosts/UI/Main/UI.Main.csproj +++ b/identity-server/hosts/UI/Main/UI.Main.csproj @@ -8,6 +8,7 @@ Duende.IdentityServer.UI true true + false diff --git a/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs b/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs index 1447992d6..e2161f753 100644 --- a/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs +++ b/identity-server/src/IdentityServer/Configuration/CryptoHelper.cs @@ -4,6 +4,7 @@ #nullable enable +using System.Buffers.Text; using System.Globalization; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; @@ -75,7 +76,7 @@ public static class CryptoHelper var leftPart = new byte[size]; Array.Copy(hash, leftPart, size); - return Base64Url.Encode(leftPart); + return Base64Url.EncodeToString(leftPart); } /// diff --git a/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DiscoveryOptions.cs b/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DiscoveryOptions.cs index 59f2fa5d5..b5e42c838 100644 --- a/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DiscoveryOptions.cs +++ b/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DiscoveryOptions.cs @@ -62,11 +62,26 @@ public class DiscoveryOptions /// public bool ShowTokenEndpointAuthenticationMethods { get; set; } = true; + /// + /// Show revocation endpoint authentication methods + /// + public bool ShowRevocationEndpointAuthenticationMethods { get; set; } = true; + + /// + /// Show introspection endpoint authentication methods + /// + public bool ShowIntrospectionEndpointAuthenticationMethods { get; set; } = true; + /// /// Turns relative paths that start with ~/ into absolute paths /// public bool ExpandRelativePathsInCustomEntries { get; set; } = true; + /// + /// Options for how the dynamic client registration endpoint is shown in the discovery document + /// + public DynamicClientRegistrationDiscoveryOptions DynamicClientRegistration { get; set; } = new DynamicClientRegistrationDiscoveryOptions(); + /// /// Sets the maxage value of the cache control header (in seconds) of the HTTP response. This gives clients a hint how often they should refresh their cached copy of the discovery document. If set to 0 no-cache headers will be set. Defaults to null, which does not set the header. /// diff --git a/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DynamicClientRegistrationDiscoveryOptions.cs b/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DynamicClientRegistrationDiscoveryOptions.cs new file mode 100644 index 000000000..abe516c4e --- /dev/null +++ b/identity-server/src/IdentityServer/Configuration/DependencyInjection/Options/DynamicClientRegistrationDiscoveryOptions.cs @@ -0,0 +1,42 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +#nullable enable +namespace Duende.IdentityServer.Configuration; + +public enum RegistrationEndpointMode +{ + /// + /// Will not show a registration endpoint in the discovery document + /// + None, + + /// + /// Will use the static URL from + /// + Static, + + /// + /// Will infer the URL dynamically based on the host + /// + Inferred +} + +public class DynamicClientRegistrationDiscoveryOptions +{ + /// + /// Gets or sets the type of the registration endpoint + /// + /// + /// The type of the registration endpoint. + /// + public RegistrationEndpointMode RegistrationEndpointMode { get; set; } = RegistrationEndpointMode.None; + + /// + /// Gets or sets the custom registration endpoint + /// + /// + /// The URL of the authorization endpoint to use in the discovery document if is set to . + /// + public Uri? StaticRegistrationEndpoint { get; set; } +} diff --git a/identity-server/src/IdentityServer/Configuration/IdentityServerApplicationBuilderExtensions.cs b/identity-server/src/IdentityServer/Configuration/IdentityServerApplicationBuilderExtensions.cs index f204ceb25..54a369998 100644 --- a/identity-server/src/IdentityServer/Configuration/IdentityServerApplicationBuilderExtensions.cs +++ b/identity-server/src/IdentityServer/Configuration/IdentityServerApplicationBuilderExtensions.cs @@ -215,6 +215,12 @@ public static class IdentityServerApplicationBuilderExtensions { throw new InvalidOperationException("CorsPolicyName is not configured"); } + + if (options.Discovery.DynamicClientRegistration.RegistrationEndpointMode == RegistrationEndpointMode.Static + && options.Discovery.DynamicClientRegistration.StaticRegistrationEndpoint == null) + { + throw new InvalidOperationException("DynamicClientRegistration.CustomRegistrationEndpoint must be set when using static registration endpoint type."); + } } internal static object? TestService(IServiceProvider serviceProvider, Type service, ILogger logger, string? message = null, bool doThrow = true) diff --git a/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs b/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs index f9a90be67..1cd60d896 100644 --- a/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/AuthenticationPropertiesExtensions.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; -using Duende.IdentityModel; using Microsoft.AspNetCore.Authentication; namespace Duende.IdentityServer.Extensions; @@ -91,7 +91,7 @@ public static class AuthenticationPropertiesExtensions { if (value.IsPresent()) { - var bytes = Base64Url.Decode(value); + var bytes = Base64Url.DecodeFromChars(value); value = Encoding.UTF8.GetString(bytes); return ObjectSerializer.FromString(value); } @@ -105,7 +105,7 @@ public static class AuthenticationPropertiesExtensions { var value = ObjectSerializer.ToString(list); var bytes = Encoding.UTF8.GetBytes(value); - value = Base64Url.Encode(bytes); + value = Base64Url.EncodeToString(bytes); return value; } diff --git a/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs b/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs index 753d85f5b..f72e0b300 100644 --- a/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/JsonWebKeyExtensions.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; using Duende.IdentityModel; using Microsoft.IdentityModel.Tokens; @@ -30,7 +31,7 @@ internal static class JsonWebKeyExtensions /// public static string CreateThumbprint(this JsonWebKey jwk) { - var jkt = Base64Url.Encode(jwk.ComputeJwkThumbprint()); + var jkt = Base64Url.EncodeToString(jwk.ComputeJwkThumbprint()); return jkt; } } diff --git a/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs b/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs index c76d6d57a..852e3e496 100644 --- a/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/ValidatedAuthorizeRequestExtensions.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Globalization; using System.Security.Cryptography; @@ -159,7 +160,7 @@ public static class ValidatedAuthorizeRequestExtensions var bytes = Encoding.UTF8.GetBytes(clientId + origin + sessionId + salt); var hash = SHA256.HashData(bytes); - return Base64Url.Encode(hash) + "." + salt; + return Base64Url.EncodeToString(hash) + "." + salt; } private static NameValueCollection ToOptimizedRawValues(this ValidatedAuthorizeRequest request) diff --git a/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs b/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs index d0c4d424c..e06df5329 100644 --- a/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs +++ b/identity-server/src/IdentityServer/Extensions/X509CertificateExtensions.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text.Json; -using Duende.IdentityModel; namespace Duende.IdentityServer.Extensions; @@ -35,5 +35,5 @@ public static class X509CertificateExtensions /// Returns the SHA256 thumbprint of the certificate as a base64url encoded string /// /// - public static string GetSha256Thumbprint(this X509Certificate2 certificate) => Base64Url.Encode(certificate.GetCertHash(HashAlgorithmName.SHA256)); + public static string GetSha256Thumbprint(this X509Certificate2 certificate) => Base64Url.EncodeToString(certificate.GetCertHash(HashAlgorithmName.SHA256)); } diff --git a/identity-server/src/IdentityServer/IdentityServerConstants.cs b/identity-server/src/IdentityServer/IdentityServerConstants.cs index 7a6a32859..351711798 100644 --- a/identity-server/src/IdentityServer/IdentityServerConstants.cs +++ b/identity-server/src/IdentityServer/IdentityServerConstants.cs @@ -257,6 +257,7 @@ public static class IdentityServerConstants public const string DeviceAuthorization = ConnectPathPrefix + "/deviceauthorization"; public const string PushedAuthorization = ConnectPathPrefix + "/par"; public const string OAuthMetadata = ".well-known/oauth-authorization-server"; + public const string DynamicClientRegistration = ConnectPathPrefix + "/dcr"; public const string MtlsPathPrefix = ConnectPathPrefix + "/mtls"; diff --git a/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs b/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs index 247bc34f2..632a31d29 100644 --- a/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs +++ b/identity-server/src/IdentityServer/Models/Messages/ConsentRequest.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Security.Cryptography; using System.Text; @@ -89,7 +90,7 @@ public class ConsentRequest var bytes = Encoding.UTF8.GetBytes(value); var hash = SHA256.HashData(bytes); - return Base64Url.Encode(hash); + return Base64Url.EncodeToString(hash); } } } diff --git a/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs b/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs index 554bb545e..c43b1a7de 100644 --- a/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs +++ b/identity-server/src/IdentityServer/ResponseHandling/Default/DiscoveryResponseGenerator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Cryptography; using Duende.IdentityModel; using Duende.IdentityServer.Configuration; @@ -321,23 +322,24 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator entries.Add(OidcConstants.Discovery.ResponseModesSupported, Constants.SupportedResponseModes.ToArray()); } + var supportedAuthMethods = GetSupportedAuthMethods(); // misc if (Options.Discovery.ShowTokenEndpointAuthenticationMethods) { - var types = SecretParsers.GetAvailableAuthenticationMethods().ToList(); - if (Options.MutualTls.Enabled) - { - types.Add(OidcConstants.EndpointAuthenticationMethods.TlsClientAuth); - types.Add(OidcConstants.EndpointAuthenticationMethods.SelfSignedTlsClientAuth); - } - entries.Add(OidcConstants.Discovery.TokenEndpointAuthenticationMethodsSupported, types); + entries.Add(OidcConstants.Discovery.TokenEndpointAuthenticationMethodsSupported, supportedAuthMethods); + AddSigningAlgorithmsForEndpointIfNeeded(OidcConstants.Discovery.TokenEndpointAuthSigningAlgorithmsSupported, entries, supportedAuthMethods); + } - if (types.Contains(OidcConstants.EndpointAuthenticationMethods.PrivateKeyJwt) && - !IEnumerableExtensions.IsNullOrEmpty(Options.SupportedClientAssertionSigningAlgorithms)) - { - entries.Add(OidcConstants.Discovery.TokenEndpointAuthSigningAlgorithmsSupported, - Options.SupportedClientAssertionSigningAlgorithms); - } + if (Options.Discovery.ShowRevocationEndpointAuthenticationMethods) + { + entries.Add(OidcConstants.Discovery.RevocationEndpointAuthenticationMethodsSupported, supportedAuthMethods); + AddSigningAlgorithmsForEndpointIfNeeded(OidcConstants.Discovery.RevocationEndpointAuthSigningAlgorithmsSupported, entries, supportedAuthMethods); + } + + if (Options.Discovery.ShowIntrospectionEndpointAuthenticationMethods) + { + entries.Add(OidcConstants.Discovery.IntrospectionEndpointAuthenticationMethodsSupported, supportedAuthMethods); + AddSigningAlgorithmsForEndpointIfNeeded(OidcConstants.Discovery.IntrospectionEndpointAuthSigningAlgorithmsSupported, entries, supportedAuthMethods); } var signingCredentials = await Keys.GetAllSigningCredentialsAsync(); @@ -345,6 +347,16 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator { var signingAlgorithms = signingCredentials.Select(c => c.Algorithm).Distinct(); entries.Add(OidcConstants.Discovery.IdTokenSigningAlgorithmsSupported, signingAlgorithms); + + if (Options.Endpoints.EnableUserInfoEndpoint) + { + entries.Add(OidcConstants.Discovery.UserInfoSigningAlgorithmsSupported, signingAlgorithms); + } + + if (Options.Endpoints.EnableIntrospectionEndpoint) + { + entries.Add(OidcConstants.Discovery.IntrospectionSigningAlgorithmsSupported, signingAlgorithms); + } } entries.Add(OidcConstants.Discovery.SubjectTypesSupported, SubjectTypesSupported); @@ -383,6 +395,12 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator entries.Add(OidcConstants.Discovery.BackchannelTokenDeliveryModesSupported, new[] { OidcConstants.BackchannelTokenDeliveryModes.Poll }); entries.Add(OidcConstants.Discovery.BackchannelUserCodeParameterSupported, true); + + if (!IEnumerableExtensions.IsNullOrEmpty(Options.SupportedRequestObjectSigningAlgorithms)) + { + entries.Add(OidcConstants.Discovery.BackchannelAuthenticationRequestSigningAlgValuesSupported, + Options.SupportedRequestObjectSigningAlgorithms); + } } if (Options.Endpoints.EnableTokenEndpoint && @@ -391,6 +409,22 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator entries.Add(OidcConstants.Discovery.DPoPSigningAlgorithmsSupported, Options.DPoP.SupportedDPoPSigningAlgorithms); } + switch (Options.Discovery.DynamicClientRegistration.RegistrationEndpointMode) + { + case RegistrationEndpointMode.Static: + if (Options.Discovery.DynamicClientRegistration.StaticRegistrationEndpoint != null) + { + entries.Add(OidcConstants.Discovery.RegistrationEndpoint, Options.Discovery.DynamicClientRegistration.StaticRegistrationEndpoint.ToString()); + } + break; + case RegistrationEndpointMode.Inferred: + entries.Add(OidcConstants.Discovery.RegistrationEndpoint, baseUrl + ProtocolRoutePaths.DynamicClientRegistration); + break; + case RegistrationEndpointMode.None: + default: + break; + } + // custom entries if (!IEnumerableExtensions.IsNullOrEmpty(Options.Discovery.CustomEntries)) { @@ -435,13 +469,13 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator if (key.Key is X509SecurityKey x509Key) { var cert64 = Convert.ToBase64String(x509Key.Certificate.RawData); - var thumbprint = Base64Url.Encode(x509Key.Certificate.GetCertHash()); + var thumbprint = Base64Url.EncodeToString(x509Key.Certificate.GetCertHash()); if (x509Key.PublicKey is RSA rsa) { var parameters = rsa.ExportParameters(false); - var exponent = Base64Url.Encode(parameters.Exponent); - var modulus = Base64Url.Encode(parameters.Modulus); + var exponent = Base64Url.EncodeToString(parameters.Exponent); + var modulus = Base64Url.EncodeToString(parameters.Modulus); var rsaJsonWebKey = new Models.JsonWebKey { @@ -459,8 +493,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (x509Key.PublicKey is ECDsa ecdsa) { var parameters = ecdsa.ExportParameters(false); - var x = Base64Url.Encode(parameters.Q.X); - var y = Base64Url.Encode(parameters.Q.Y); + var x = Base64Url.EncodeToString(parameters.Q.X); + var y = Base64Url.EncodeToString(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { @@ -484,8 +518,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (key.Key is RsaSecurityKey rsaKey) { var parameters = rsaKey.Rsa?.ExportParameters(false) ?? rsaKey.Parameters; - var exponent = Base64Url.Encode(parameters.Exponent); - var modulus = Base64Url.Encode(parameters.Modulus); + var exponent = Base64Url.EncodeToString(parameters.Exponent); + var modulus = Base64Url.EncodeToString(parameters.Modulus); var webKey = new Models.JsonWebKey { @@ -502,8 +536,8 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator else if (key.Key is ECDsaSecurityKey ecdsaKey) { var parameters = ecdsaKey.ECDsa.ExportParameters(false); - var x = Base64Url.Encode(parameters.Q.X); - var y = Base64Url.Encode(parameters.Q.Y); + var x = Base64Url.EncodeToString(parameters.Q.X); + var y = Base64Url.EncodeToString(parameters.Q.Y); var ecdsaJsonWebKey = new Models.JsonWebKey { @@ -540,4 +574,24 @@ public class DiscoveryResponseGenerator : IDiscoveryResponseGenerator return webKeys; } + + private List GetSupportedAuthMethods() + { + var types = SecretParsers.GetAvailableAuthenticationMethods().ToList(); + if (Options.MutualTls.Enabled) + { + types.Add(OidcConstants.EndpointAuthenticationMethods.TlsClientAuth); + types.Add(OidcConstants.EndpointAuthenticationMethods.SelfSignedTlsClientAuth); + } + + return types; + } + + private void AddSigningAlgorithmsForEndpointIfNeeded(string key, Dictionary entries, IEnumerable supportedAuthMethods) + { + if (supportedAuthMethods.Contains(OidcConstants.EndpointAuthenticationMethods.PrivateKeyJwt) && !IEnumerableExtensions.IsNullOrEmpty(Options.SupportedClientAssertionSigningAlgorithms)) + { + entries.Add(key, Options.SupportedClientAssertionSigningAlgorithms); + } + } } diff --git a/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs b/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs index 321ef61c8..86e73b3b3 100644 --- a/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs +++ b/identity-server/src/IdentityServer/Stores/Default/ProtectedDataMessageStore.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; -using Duende.IdentityModel; using Duende.IdentityServer.Models; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Logging; @@ -50,7 +50,7 @@ public class ProtectedDataMessageStore : IMessageStore { try { - var bytes = Base64Url.Decode(value); + var bytes = Base64Url.DecodeFromChars(value); bytes = Protector.Unprotect(bytes); var json = Encoding.UTF8.GetString(bytes); result = ObjectSerializer.FromString>(json); @@ -76,7 +76,7 @@ public class ProtectedDataMessageStore : IMessageStore var json = ObjectSerializer.ToString(message); var bytes = Encoding.UTF8.GetBytes(json); bytes = Protector.Protect(bytes); - value = Base64Url.Encode(bytes); + value = Base64Url.EncodeToString(bytes); } catch (Exception ex) { diff --git a/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs b/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs index 451e98ef3..d51fb7fe1 100644 --- a/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/DefaultDPoPProofValidator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Globalization; using System.Security.Cryptography; using System.Text; @@ -302,7 +303,7 @@ public class DefaultDPoPProofValidator : IDPoPProofValidator var bytes = Encoding.UTF8.GetBytes(context.AccessToken); var hash = SHA256.HashData(bytes); - var accessTokenHash = Base64Url.Encode(hash); + var accessTokenHash = Base64Url.EncodeToString(hash); if (accessTokenHash != result.AccessTokenHash) { result.IsError = true; diff --git a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs index abd7c111f..a4b78bfa3 100644 --- a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Text; using Duende.IdentityModel; @@ -1231,7 +1232,7 @@ internal class TokenRequestValidator : ITokenRequestValidator var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return TimeConstantComparer.IsEqual(transformedCodeVerifier.Sha256(), codeChallenge); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs index 56de3fba3..c5cfdd5e0 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; @@ -223,7 +224,7 @@ public class ClientAssertionClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs index a913cbecb..35854ef2c 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; @@ -433,7 +434,7 @@ public class ClientCredentialsClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs index 83801d7a6..e157ef7e0 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Duende.IdentityServer.IntegrationTests.Common; @@ -275,7 +275,7 @@ public class CustomTokenResponseClients { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs index 0c6b2ff1b..24156783e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Text; @@ -588,7 +589,7 @@ public class ExtensionGrantClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs index ef492f51d..fd5b8f050 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Microsoft.AspNetCore.Hosting; @@ -268,7 +268,7 @@ public class ResourceOwnerClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs index 76875c33e..2a8eb18a7 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Clients.Setup; using Duende.IdentityServer.IntegrationTests.Common; @@ -204,7 +204,7 @@ public class UserInfoEndpointClient { var token = response.AccessToken.Split('.').Skip(1).Take(1).First(); var dictionary = JsonSerializer.Deserialize>( - Encoding.UTF8.GetString(Base64Url.Decode(token))); + Encoding.UTF8.GetString(Base64Url.DecodeFromChars(token))); return dictionary; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs index 5cd7fddbe..f22f5a3ee 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text; using Duende.IdentityModel; @@ -528,7 +529,7 @@ public class PkceTests { var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return transformedCodeVerifier; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs index 4b7935de0..45aa4494b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. using System.Text.Json; +using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.Configuration; using Duende.IdentityServer.Endpoints.Results; @@ -77,8 +78,99 @@ public class DiscoveryEndpointTests algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); } + [Fact] + [Trait("Category", Category)] + public async Task UserInfo_signing_algorithms_supported_should_match_signing_key() + { + var key = CryptoHelper.CreateECDsaSecurityKey(JsonWebKeyECTypes.P256); + var expectedAlgorithm = SecurityAlgorithms.EcdsaSha256; + var pipeline = new IdentityServerPipeline(); + pipeline.OnPostConfigureServices += services => + { + // add key to standard RSA key + services.AddIdentityServerBuilder() + .AddSigningCredential(key, expectedAlgorithm); + }; + pipeline.Initialize(); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + var algorithmsSupported = result.UserInfoSigningAlgorithmsSupported; + + algorithmsSupported.Count().ShouldBe(2); + algorithmsSupported.ShouldContain(SecurityAlgorithms.RsaSha256); + algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); + } + + [Fact] + [Trait("Category", Category)] + public async Task UserInfo_signing_algorithms_supported_should_not_be_present_if_userinfo_endpoint_disabled() + { + var key = CryptoHelper.CreateECDsaSecurityKey(JsonWebKeyECTypes.P256); + var expectedAlgorithm = SecurityAlgorithms.EcdsaSha256; + + var pipeline = new IdentityServerPipeline(); + pipeline.OnPostConfigureServices += services => + { + // add key to standard RSA key + services.AddIdentityServerBuilder() + .AddSigningCredential(key, expectedAlgorithm); + }; + pipeline.Initialize(); + pipeline.Options.Endpoints.EnableUserInfoEndpoint = false; + + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + result.UserInfoSigningAlgorithmsSupported.ShouldBeEmpty(); + } + + [Fact] + [Trait("Category", Category)] + public async Task Introspection_signing_algorithms_supported_should_match_signing_key() + { + var key = CryptoHelper.CreateECDsaSecurityKey(JsonWebKeyECTypes.P256); + var expectedAlgorithm = SecurityAlgorithms.EcdsaSha256; + + var pipeline = new IdentityServerPipeline(); + pipeline.OnPostConfigureServices += services => + { + // add key to standard RSA key + services.AddIdentityServerBuilder() + .AddSigningCredential(key, expectedAlgorithm); + }; + pipeline.Initialize(); + + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + var algorithmsSupported = result.IntrospectionSigningAlgorithmsSupported; + + algorithmsSupported.Count().ShouldBe(2); + algorithmsSupported.ShouldContain(SecurityAlgorithms.RsaSha256); + algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); + } + + [Fact] + [Trait("Category", Category)] + public async Task Introspection_signing_algorithms_supported_should_not_be_present_if_introspection_endpoint_disabled() + { + var key = CryptoHelper.CreateECDsaSecurityKey(JsonWebKeyECTypes.P256); + var expectedAlgorithm = SecurityAlgorithms.EcdsaSha256; + + var pipeline = new IdentityServerPipeline(); + pipeline.OnPostConfigureServices += services => + { + // add key to standard RSA key + services.AddIdentityServerBuilder() + .AddSigningCredential(key, expectedAlgorithm); + }; + pipeline.Initialize(); + pipeline.Options.Endpoints.EnableIntrospectionEndpoint = false; + + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + result.IntrospectionSigningAlgorithmsSupported.ShouldBeEmpty(); + } [Fact] [Trait("Category", Category)] @@ -216,7 +308,6 @@ public class DiscoveryEndpointTests result.Issuer.ShouldBe("https://грант.рф"); } - [Fact] [Trait("Category", Category)] public async Task prompt_values_supported_should_contain_defaults() @@ -376,6 +467,51 @@ public class DiscoveryEndpointTests var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); result.MtlsEndpointAliases.PushedAuthorizationRequestEndpoint.ShouldNotBeNull(); } + + [Fact] + [Trait("Category", Category)] + public async Task registration_endpoint_should_be_custom_when_static_type_and_custom_endpoint_set() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.Discovery.DynamicClientRegistration.RegistrationEndpointMode = RegistrationEndpointMode.Static; + pipeline.Options.Discovery.DynamicClientRegistration.StaticRegistrationEndpoint = new Uri("https://custom.example.com/register"); + + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + data.ShouldContainKey(OidcConstants.Discovery.RegistrationEndpoint); + data[OidcConstants.Discovery.RegistrationEndpoint].GetString().ShouldBe("https://custom.example.com/register"); + } + + [Fact] + [Trait("Category", Category)] + public async Task registration_endpoint_should_be_default_when_dynamic_type() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.Discovery.DynamicClientRegistration.RegistrationEndpointMode = RegistrationEndpointMode.Inferred; + + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + data.ShouldContainKey(OidcConstants.Discovery.RegistrationEndpoint); + data[OidcConstants.Discovery.RegistrationEndpoint].GetString().ShouldBe("https://server/connect/dcr"); + } + + [Fact] + [Trait("Category", Category)] + public async Task registration_endpoint_should_not_be_present_when_none_type() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.Discovery.DynamicClientRegistration.RegistrationEndpointMode = RegistrationEndpointMode.None; + + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + data.ShouldNotContainKey(OidcConstants.Discovery.RegistrationEndpoint); + } } class DiscoCustomizaztion : IHttpResponseWriter diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTestsBase.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTestsBase.cs new file mode 100644 index 000000000..0ada0e07f --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTestsBase.cs @@ -0,0 +1,26 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using Duende.IdentityServer.IntegrationTests.Common; +using Microsoft.Extensions.DependencyInjection; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public abstract class DiscoveryEndpointTestsBase +{ + protected static IdentityServerPipeline CreatePipelineWithJwtBearer() + { + var pipeline = new IdentityServerPipeline(); + pipeline.OnPostConfigureServices += svcs => + svcs.AddIdentityServerBuilder().AddJwtBearerClientAuthentication(); + pipeline.Initialize(); + return pipeline; + } + + public static IEnumerable NullOrEmptySupportedAlgorithms() => + new List + { + new object[] { Enumerable.Empty() }, + new object[] { null } + }; +} diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_methods_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_methods_supported.cs new file mode 100644 index 000000000..b69ad9748 --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_methods_supported.cs @@ -0,0 +1,74 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using Duende.IdentityModel; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpointTests_introspection_endpoint_auth_methods_supported : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - introspection_endpoint_auth_methods_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_methods_supported_should_default_to_basic_auth_and_post_body() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.IntrospectionEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(2); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + } + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_methods_supported_should_include_tls_client_and_self_signed_tls_client_when_mtls_is_enabled() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = true; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.IntrospectionEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(4); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.TlsClientAuth); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.SelfSignedTlsClientAuth); + } + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_methods_supported_should_include_private_key_jwt_when_jwt_bearer_is_enabled() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.IntrospectionEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(3); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PrivateKeyJwt); + } +} + diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_signing_algs_supported.cs new file mode 100644 index 000000000..b7f51421c --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_introspection_endpoint_auth_signing_algs_supported.cs @@ -0,0 +1,105 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Text.Json; +using Duende.IdentityModel; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; +using Microsoft.IdentityModel.Tokens; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpointTests_introspection_endpoint_auth_signing_algs_supported : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - introspection_endpoint_auth_signing_alg_values_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_signing_alg_values_supported_should_match_configuration() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = + [ + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256 + ]; + pipeline.Options.Discovery.ShowIntrospectionEndpointAuthenticationMethods = true; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var algorithmsSupported = disco.IntrospectionEndpointAuthenticationSigningAlgorithmsSupported; + + algorithmsSupported.Count().ShouldBe(2); + algorithmsSupported.ShouldContain(SecurityAlgorithms.RsaSsaPssSha256); + algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); + } + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_signing_alg_values_supported_should_default_to_rs_ps_es() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Options.Discovery.ShowIntrospectionEndpointAuthenticationMethods = true; + + var result = + await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration"); + + result.IsError.ShouldBeFalse(); + var algorithmsSupported = result.IntrospectionEndpointAuthenticationSigningAlgorithmsSupported; + + algorithmsSupported.ShouldBe([ + SecurityAlgorithms.RsaSha256, + SecurityAlgorithms.RsaSha384, + SecurityAlgorithms.RsaSha512, + SecurityAlgorithms.RsaSsaPssSha384, + SecurityAlgorithms.RsaSsaPssSha512, + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256, + SecurityAlgorithms.EcdsaSha384, + SecurityAlgorithms.EcdsaSha512, + ], ignoreOrder: true); + } + + [Fact] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_signing_alg_values_supported_should_not_be_present_if_private_key_jwt_is_not_configured() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = [SecurityAlgorithms.RsaSha256]; + pipeline.Options.Discovery.ShowIntrospectionEndpointAuthenticationMethods = true; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + // Verify assumptions + disco.IsError.ShouldBeFalse(); + disco.IntrospectionEndpointAuthenticationMethodsSupported.ShouldNotContain("private_key_jwt"); + disco.IntrospectionEndpointAuthenticationMethodsSupported.ShouldNotContain("client_secret_jwt"); + + // Assert that we got no signing algs. + disco.IntrospectionEndpointAuthenticationSigningAlgorithmsSupported.ShouldBeEmpty(); + } + + [Theory] + [MemberData(nameof(NullOrEmptySupportedAlgorithms))] + [Trait("Category", Category)] + public async Task introspection_endpoint_auth_signing_alg_values_supported_should_not_be_present_if_option_is_null_or_empty( + ICollection algorithms) + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = algorithms; + pipeline.Options.Discovery.ShowIntrospectionEndpointAuthenticationMethods = true; + + var result = await pipeline.BackChannelClient + .GetAsync("https://server/.well-known/openid-configuration"); + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + + data.ShouldNotContainKey(OidcConstants.Discovery.IntrospectionEndpointAuthSigningAlgorithmsSupported); + } +} + diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_methods_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_methods_supported.cs new file mode 100644 index 000000000..a0beddaa9 --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_methods_supported.cs @@ -0,0 +1,73 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using Duende.IdentityModel; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpointTests_revocation_endpoint_auth_methods_supported : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - revocation_endpoint_auth_methods_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_methods_supported_should_default_to_basic_auth_and_post_body() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.RevocationEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(2); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + } + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_methods_supported_should_include_tls_client_and_self_signed_tls_client_when_mtls_is_enabled() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = true; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.RevocationEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(4); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.TlsClientAuth); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.SelfSignedTlsClientAuth); + } + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_methods_supported_should_include_private_key_jwt_when_jwt_bearer_is_enabled() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.RevocationEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(3); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PrivateKeyJwt); + } +} diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_signing_algs_supported.cs new file mode 100644 index 000000000..1bfc34f75 --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_revocation_endpoint_auth_signing_algs_supported.cs @@ -0,0 +1,98 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Text.Json; +using Duende.IdentityModel; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; +using Microsoft.IdentityModel.Tokens; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpointTests_revocation_endpoint_auth_signing_algs_supported : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - revocation_endpoint_auth_signing_alg_values_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_signing_alg_values_supported_should_match_configuration() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = + [ + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256 + ]; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var algorithmsSupported = disco.RevocationEndpointAuthenticationSigningAlgorithmsSupported; + + algorithmsSupported.Count().ShouldBe(2); + algorithmsSupported.ShouldContain(SecurityAlgorithms.RsaSsaPssSha256); + algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); + } + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_signing_alg_values_supported_should_default_to_rs_ps_es() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Initialize(); + + var result = + await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration"); + + result.IsError.ShouldBeFalse(); + var algorithmsSupported = result.RevocationEndpointAuthenticationSigningAlgorithmsSupported; + + algorithmsSupported.ShouldBe([ + SecurityAlgorithms.RsaSha256, + SecurityAlgorithms.RsaSha384, + SecurityAlgorithms.RsaSha512, + SecurityAlgorithms.RsaSsaPssSha384, + SecurityAlgorithms.RsaSsaPssSha512, + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256, + SecurityAlgorithms.EcdsaSha384, + SecurityAlgorithms.EcdsaSha512, + ], ignoreOrder: true); + } + + [Fact] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_signing_alg_values_supported_should_not_be_present_if_private_key_jwt_is_not_configured() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = [SecurityAlgorithms.RsaSha256]; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + + disco.IsError.ShouldBeFalse(); + disco.RevocationEndpointAuthenticationMethodsSupported.ShouldNotContain("private_key_jwt"); + disco.RevocationEndpointAuthenticationMethodsSupported.ShouldNotContain("client_secret_jwt"); + disco.RevocationEndpointAuthenticationSigningAlgorithmsSupported.ShouldBeEmpty(); + } + + [Theory] + [MemberData(nameof(NullOrEmptySupportedAlgorithms))] + [Trait("Category", Category)] + public async Task revocation_endpoint_auth_signing_alg_values_supported_should_not_be_present_if_option_is_null_or_empty( + ICollection algorithms) + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Options.SupportedClientAssertionSigningAlgorithms = algorithms; + + var result = await pipeline.BackChannelClient + .GetAsync("https://server/.well-known/openid-configuration"); + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + + data.ShouldNotContainKey(OidcConstants.Discovery.RevocationEndpointAuthSigningAlgorithmsSupported); + } +} diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_methods_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_methods_supported.cs new file mode 100644 index 000000000..b9d8ae09b --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_methods_supported.cs @@ -0,0 +1,74 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using Duende.IdentityModel; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpointTests_token_endpoint_auth_methods_supported : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - token_endpoint_auth_methods_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task token_endpoint_auth_methods_supported_should_default_to_basic_auth_and_post_body() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.TokenEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(2); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + } + + [Fact] + [Trait("Category", Category)] + public async Task token_endpoint_auth_methods_supported_should_include_tls_client_and_self_signed_tls_client_when_mtls_is_enabled() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = true; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.TokenEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(4); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.TlsClientAuth); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.SelfSignedTlsClientAuth); + } + + [Fact] + [Trait("Category", Category)] + public async Task token_endpoint_auth_methods_supported_should_include_private_key_jwt_when_jwt_bearer_is_enabled() + { + var pipeline = CreatePipelineWithJwtBearer(); + pipeline.Initialize(); + pipeline.Options.MutualTls.Enabled = false; + + var disco = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + disco.IsError.ShouldBeFalse(); + + var authMethodsSupported = disco.TokenEndpointAuthenticationMethodsSupported; + + authMethodsSupported.Count().ShouldBe(3); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.BasicAuthentication); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PostBody); + authMethodsSupported.ShouldContain(OidcConstants.EndpointAuthenticationMethods.PrivateKeyJwt); + } +} + diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs index d844bd205..09fc74342 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs @@ -5,12 +5,11 @@ using System.Text.Json; using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Common; -using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; -public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_supported +public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_supported : DiscoveryEndpointTestsBase { private const string Category = "Discovery endpoint - token_endpoint_auth_signing_alg_values_supported"; @@ -18,10 +17,7 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo [Trait("Category", Category)] public async Task token_endpoint_auth_signing_alg_values_supported_should_match_configuration() { - var pipeline = new IdentityServerPipeline(); - pipeline.OnPostConfigureServices += svcs => - svcs.AddIdentityServerBuilder().AddJwtBearerClientAuthentication(); - pipeline.Initialize(); + var pipeline = CreatePipelineWithJwtBearer(); pipeline.Options.SupportedClientAssertionSigningAlgorithms = [ SecurityAlgorithms.RsaSsaPssSha256, @@ -43,10 +39,7 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo [Trait("Category", Category)] public async Task token_endpoint_auth_signing_alg_values_supported_should_default_to_rs_ps_es() { - var pipeline = new IdentityServerPipeline(); - pipeline.OnPostConfigureServices += svcs => - svcs.AddIdentityServerBuilder().AddJwtBearerClientAuthentication(); - pipeline.Initialize(); + var pipeline = CreatePipelineWithJwtBearer(); var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( @@ -95,10 +88,7 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo public async Task token_endpoint_auth_signing_alg_values_supported_should_not_be_present_if_option_is_null_or_empty( ICollection algorithms) { - var pipeline = new IdentityServerPipeline(); - pipeline.OnPostConfigureServices += svcs => - svcs.AddIdentityServerBuilder().AddJwtBearerClientAuthentication(); - pipeline.Initialize(); + var pipeline = CreatePipelineWithJwtBearer(); pipeline.Options.SupportedClientAssertionSigningAlgorithms = algorithms; var result = await pipeline.BackChannelClient @@ -108,11 +98,4 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo data.ShouldNotContainKey(OidcConstants.Discovery.TokenEndpointAuthSigningAlgorithmsSupported); } - - public static IEnumerable NullOrEmptySupportedAlgorithms() => - new List - { - new object[] { Enumerable.Empty() }, - new object[] { null } - }; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_backchannel_authentication_request_object_auth_signing_algs_supported_Tests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_backchannel_authentication_request_object_auth_signing_algs_supported_Tests.cs new file mode 100644 index 000000000..b9932d0c8 --- /dev/null +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_backchannel_authentication_request_object_auth_signing_algs_supported_Tests.cs @@ -0,0 +1,101 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Text.Json; +using Duende.IdentityModel.Client; +using Duende.IdentityServer.IntegrationTests.Common; +using Microsoft.IdentityModel.Tokens; + +namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; + +public class DiscoveryEndpoint_backchannel_authentication_request_object_auth_signing_algs_supported_Tests : DiscoveryEndpointTestsBase +{ + private const string Category = "Discovery endpoint - backchannel_authentication_request_signing_alg_values_supported"; + + [Fact] + [Trait("Category", Category)] + public async Task backchannel_authentication_request_signing_alg_values_supported_should_match_configuration() + { + var pipeline = new IdentityServerPipeline(); + + pipeline.Initialize(); + pipeline.Options.SupportedRequestObjectSigningAlgorithms = + [ + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256 + ]; + + var result = + await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration"); + + var algorithmsSupported = result.BackchannelAuthenticationRequestSigningAlgValuesSupported; + + algorithmsSupported.Count().ShouldBe(2); + algorithmsSupported.ShouldContain(SecurityAlgorithms.RsaSsaPssSha256); + algorithmsSupported.ShouldContain(SecurityAlgorithms.EcdsaSha256); + } + + [Theory] + [MemberData(nameof(NullOrEmptySupportedAlgorithms))] + [Trait("Category", Category)] + public async Task backchannel_authentication_request_signing_alg_values_supported_should_not_be_present_if_option_is_null_or_empty( + ICollection algorithms) + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.SupportedRequestObjectSigningAlgorithms = algorithms; + + var result = await pipeline.BackChannelClient + .GetAsync("https://server/.well-known/openid-configuration"); + + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + + data.ShouldNotContainKey("backchannel_authentication_request_signing_alg_values_supported"); + } + + [Fact] + [Trait("Category", Category)] + public async Task + backchannel_authentication_request_signing_alg_values_supported_should_be_present_if_ciba_is_disabled() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + pipeline.Options.Endpoints.EnableBackchannelAuthenticationEndpoint = false; + + var result = await pipeline.BackChannelClient + .GetAsync("https://server/.well-known/openid-configuration"); + + var json = await result.Content.ReadAsStringAsync(); + var data = JsonSerializer.Deserialize>(json); + + data.ShouldNotContainKey("backchannel_authentication_request_signing_alg_values_supported"); + } + + [Fact] + [Trait("Category", Category)] + public async Task backchannel_authentication_request_signing_alg_values_supported_should_default_to_rs_ps_es() + { + var pipeline = new IdentityServerPipeline(); + pipeline.Initialize(); + + var result = + await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration"); + + var algorithmsSupported = result.BackchannelAuthenticationRequestSigningAlgValuesSupported; + + algorithmsSupported.ShouldBe([ + SecurityAlgorithms.RsaSha256, + SecurityAlgorithms.RsaSha384, + SecurityAlgorithms.RsaSha512, + SecurityAlgorithms.RsaSsaPssSha384, + SecurityAlgorithms.RsaSsaPssSha512, + SecurityAlgorithms.RsaSsaPssSha256, + SecurityAlgorithms.EcdsaSha256, + SecurityAlgorithms.EcdsaSha384, + SecurityAlgorithms.EcdsaSha512, + ], ignoreOrder: true); + } +} diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs index 8d44552b7..afcdce094 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs @@ -8,7 +8,7 @@ using Microsoft.IdentityModel.Tokens; namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; -public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests +public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests : DiscoveryEndpointTestsBase { private const string Category = "Discovery endpoint - request_object_signing_algs_supported"; @@ -77,11 +77,4 @@ public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests SecurityAlgorithms.EcdsaSha512, ], ignoreOrder: true); } - - public static IEnumerable NullOrEmptySupportedAlgorithms() => - new List - { - new object[] { Enumerable.Empty() }, - new object[] { null } - }; } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs index 25ea0df75..42b2f9133 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Globalization; using System.Net; using System.Security.Claims; @@ -581,7 +582,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[1]); + var bytes = Base64Url.DecodeFromChars(parts[1]); var json = Encoding.UTF8.GetString(bytes); var payload = JsonSerializer.Deserialize>(json); @@ -629,7 +630,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[0]); + var bytes = Base64Url.DecodeFromChars(parts[0]); var json = Encoding.UTF8.GetString(bytes); var header = JsonSerializer.Deserialize>(json); @@ -669,7 +670,7 @@ public class EndSessionTests var parts = token.Split('.'); parts.Length.ShouldBe(3); - var bytes = Base64Url.Decode(parts[0]); + var bytes = Base64Url.DecodeFromChars(parts[0]); var json = Encoding.UTF8.GetString(bytes); var header = JsonSerializer.Deserialize>(json); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs index 940f18fe8..c96235752 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; @@ -97,7 +97,7 @@ public class RefreshTokenTests tokenResult1.AccessToken.ShouldNotBeNull(); - var payload1 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult1.AccessToken.Split('.')[1])); + var payload1 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult1.AccessToken.Split('.')[1])); var sid1 = payload1.TryGetValue("sid").GetString(); sid1.ShouldBe(_mockPipeline.GetSessionCookie().Value); @@ -114,7 +114,7 @@ public class RefreshTokenTests tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); - var payload2 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult2.AccessToken.Split('.')[1])); + var payload2 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult2.AccessToken.Split('.')[1])); var sid2 = payload2.TryGetValue("sid").GetString(); sid1.ShouldBe(sid2); } @@ -155,7 +155,7 @@ public class RefreshTokenTests tokenResult1.AccessToken.ShouldNotBeNull(); - var payload1 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult1.AccessToken.Split('.')[1])); + var payload1 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult1.AccessToken.Split('.')[1])); var sid1 = payload1.TryGetValue("sid").GetString(); sid1.ShouldBe(_mockPipeline.GetSessionCookie().Value); @@ -172,7 +172,7 @@ public class RefreshTokenTests tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); - var payload2 = JsonSerializer.Deserialize(Base64Url.Decode(tokenResult2.AccessToken.Split('.')[1])); + var payload2 = JsonSerializer.Deserialize(Base64Url.DecodeFromChars(tokenResult2.AccessToken.Split('.')[1])); var sid2 = payload2.TryGetValue("sid").GetString(); sid1.ShouldBe(sid2); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs index 290e7ba65..84130fc52 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; @@ -64,7 +64,7 @@ public class CustomClaimsServiceTests var accessToken = result.AccessToken; var payload = accessToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["foo"].GetString().ShouldBe("foo1"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs index b5c3869c8..1b662ad82 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs @@ -2,11 +2,11 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Net; using System.Security.Claims; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityServer.IntegrationTests.Common; using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; @@ -73,7 +73,7 @@ public class CustomProfileServiceTests authorization.IdentityToken.ShouldNotBeNull(); var payload = authorization.IdentityToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["foo"].GetString().ShouldBe("bar"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs index c4cd24e17..a8ff3cf5b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityModel.Client; using Duende.IdentityServer.Configuration; using Duende.IdentityServer.IntegrationTests.Common; @@ -63,7 +63,7 @@ public class CustomTokenCreationServiceTests var accessToken = result.AccessToken; var payload = accessToken.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var obj = JsonSerializer.Deserialize>(json); obj["aud"].ToStringList().ShouldContain("custom1"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs index 5ee8c133f..34550eff9 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Net.Http.Headers; @@ -212,11 +213,11 @@ public class LocalApiAuthenticationTests if (!string.IsNullOrWhiteSpace(accessToken)) { - // ath: hash of the access token. The value MUST be the result of a base64url encoding + // ath: hash of the access token. The value MUST be the result of a base64url encoding // the SHA-256 hash of the ASCII encoding of the associated access token's value. using var sha256 = SHA256.Create(); var hash = sha256.ComputeHash(Encoding.ASCII.GetBytes(accessToken)); - var ath = Base64Url.Encode(hash); + var ath = Base64Url.EncodeToString(hash); payload.Add(JwtClaimTypes.DPoPAccessTokenHash, ath); } @@ -293,7 +294,7 @@ public class LocalApiAuthenticationTests // so it should fail. var newKey = GenerateJwk(); var newJwk = new Microsoft.IdentityModel.Tokens.JsonWebKey(newKey); - var newJkt = Base64Url.Encode(newJwk.ComputeJwkThumbprint()); + var newJkt = Base64Url.EncodeToString(newJwk.ComputeJwkThumbprint()); var proofToken = CreateProofToken("GET", "https://server/api", at, jwkString: newKey); req.Headers.Add("DPoP", proofToken); @@ -328,7 +329,7 @@ public class LocalApiAuthenticationTests // so it should fail. var newKey = GenerateJwk(); var newJwk = new Microsoft.IdentityModel.Tokens.JsonWebKey(newKey); - var newJkt = Base64Url.Encode(newJwk.ComputeJwkThumbprint()); + var newJkt = Base64Url.EncodeToString(newJwk.ComputeJwkThumbprint()); var proofToken = CreateProofToken("GET", "https://server/api", at, jwkString: newKey); req.Headers.Add("DPoP", proofToken); diff --git a/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs b/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs index af2e6104b..3bf04ed56 100644 --- a/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Services/Default/DefaultBackChannelLogoutServiceTests.cs @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Text.Json; -using Duende.IdentityModel; using Duende.IdentityServer; using Duende.IdentityServer.Configuration; using Duende.IdentityServer.Services; @@ -62,7 +62,7 @@ public class DefaultBackChannelLogoutServiceTests }); - var payload = JsonSerializer.Deserialize>(Base64Url.Decode(rawToken.Split('.')[1])); + var payload = JsonSerializer.Deserialize>(Base64Url.DecodeFromChars(rawToken.Split('.')[1])); payload["iss"].GetString().ShouldBe(expected); } } diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs b/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs index 19bba6035..caeeb5b3d 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/DPoPProofValidatorTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Security.Claims; using System.Security.Cryptography; using System.Text; @@ -168,7 +169,7 @@ public class DPoPProofValidatorTests using var sha = SHA256.Create(); var bytes = Encoding.UTF8.GetBytes(_context.AccessToken); var hash = sha.ComputeHash(bytes); - return Base64Url.Encode(hash); + return Base64Url.EncodeToString(hash); } [Fact] diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs b/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs index 949a38d5e..ca9f0bc18 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/IdentityTokenValidation.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.IdentityModel.Tokens.Jwt; using System.Text; using System.Text.Json; @@ -93,7 +94,7 @@ public class IdentityTokenValidation // check that the custom aud was ignored var payload = jwt.Split('.')[1]; - var json = Encoding.UTF8.GetString(Base64Url.Decode(payload)); + var json = Encoding.UTF8.GetString(Base64Url.DecodeFromChars(payload)); var values = JsonSerializer.Deserialize>(json); values["aud"].GetString().ShouldBe("roclient"); } diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs b/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs index be005306a..19ee332ed 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/TokenRequest Validation/TokenRequestValidation_PKCE.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Buffers.Text; using System.Collections.Specialized; using System.Text; using Duende.IdentityModel; @@ -316,7 +317,7 @@ public class TokenRequestValidation_PKCE { var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); - var transformedCodeVerifier = Base64Url.Encode(hashedBytes); + var transformedCodeVerifier = Base64Url.EncodeToString(hashedBytes); return transformedCodeVerifier; } diff --git a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj index fe2a6dc09..5942a9e3a 100644 --- a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj +++ b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj @@ -7,6 +7,7 @@ Duende.Xunit.Playwright true false + false