DiscoveryCache is from the Duende.IdentityModel package
// Copyright (c) Duende Software. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using Duende.IdentityModel.Internal;
namespace Duende.IdentityModel.Client;
/// <summary>
/// Helper for caching discovery documents.
/// </summary>
public class DiscoveryCache : IDiscoveryCache
{
private DateTime _nextReload = DateTime.MinValue;
private AsyncLazy<DiscoveryDocumentResponse>? _lazyResponse;
private readonly DiscoveryPolicy _policy;
private readonly Func<HttpMessageInvoker> _getHttpClient;
private readonly string _authority;
/// <summary>
/// Initialize instance of DiscoveryCache with passed authority.
/// </summary>
/// <param name="authority">Base address or discovery document endpoint.</param>
/// <param name="policy">The policy.</param>
public DiscoveryCache(string authority, DiscoveryPolicy? policy = null)
{
_authority = authority;
_policy = policy ?? new DiscoveryPolicy();
_getHttpClient = () => new HttpClient();
}
/// <summary>
/// Initialize instance of DiscoveryCache with passed authority.
/// </summary>
/// <param name="authority">Base address or discovery document endpoint.</param>
/// <param name="httpClientFunc">The HTTP client function.</param>
/// <param name="policy">The policy.</param>
public DiscoveryCache(string authority, Func<HttpMessageInvoker> httpClientFunc, DiscoveryPolicy? policy = null)
{
_authority = authority;
_policy = policy ?? new DiscoveryPolicy();
_getHttpClient = httpClientFunc ?? throw new ArgumentNullException(nameof(httpClientFunc));
}
/// <summary>
/// Frequency to refresh discovery document. Defaults to 24 hours.
/// </summary>
public TimeSpan CacheDuration { get; set; } = TimeSpan.FromHours(24);
/// <summary>
/// Get the DiscoveryResponse either from cache or from discovery endpoint.
/// </summary>
/// <returns></returns>
public Task<DiscoveryDocumentResponse> GetAsync()
{
if (_nextReload <= DateTime.UtcNow)
{
Refresh();
}
return _lazyResponse!.Value;
}
/// <summary>
/// Marks the discovery document as stale and will trigger a request to the discovery endpoint on the next request to get the DiscoveryResponse.
/// </summary>
public void Refresh()
{
_lazyResponse = new AsyncLazy<DiscoveryDocumentResponse>(GetResponseAsync);
}
private async Task<DiscoveryDocumentResponse> GetResponseAsync()
{
var result = await _getHttpClient().GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
{
Address = _authority,
Policy = _policy
}).ConfigureAwait();
if (result.IsError)
{
Refresh();
_nextReload = DateTime.MinValue;
}
else
{
_nextReload = DateTime.UtcNow.Add(CacheDuration);
}
return result;
}
}
I have no idea what has changed but it's giving the Error retrieving discovery document: Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize.
It was working yesterday and now it's not.
Don't know what I did but just redeployed and it worked
Updated authserver initialization
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto | ForwardedHeaders.XForwardedFor,
// Optionally, set KnownProxies or KnownNetworks if needed for security
});
app.Use(async (context, next) =>
{
context.Request.Scheme = "https";
await next();
});
Updated ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: "{{ .Release.Name }}-{{ .Chart.Name }}"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"
nginx.ingress.kubernetes.io/proxy-buffers-number: "8"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
nginx.ingress.kubernetes.io/enable-real-ip: "true"
nginx.ingress.kubernetes.io/proxy-real-ip-cidr: "0.0.0.0/0"
cert-manager.io/cluster-issuer: "letsencrypt"
The above changes didn't solve the problem
[13:23:05 INF] Request starting HTTP/1.1 POST http://cloverleafcms-dev-apps-token/api/token - application/json 661
[13:23:05 INF] Executing endpoint 'TokenService.Tokens.TokenController.GetAccessToken (CloverleafCMS.TokenService)'
[13:23:05 INF] Route matched with {area = "token", action = "GetAccessToken", controller = "Token", page = ""}. Executing controller action with signature System.Threading.Tasks.Task`1[TokenService.Tokens.TokenResponseDto] GetAccessToken(TokenService.Tokens.TokenRequestDto) on controller TokenService.Tokens.TokenController (CloverleafCMS.TokenService).
Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize
[13:23:06 WRN] ---------- RemoteServiceErrorInfo ----------
{
"code": null,
"message": "Error retrieving discovery document: Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize",
"details": null,
"data": {},
"validationErrors": null
}
[13:23:06 WRN] Error retrieving discovery document: Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize
Volo.Abp.UserFriendlyException: Error retrieving discovery document: Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize
at CloverleafCMS.TokenService.TokenService.TokenAppService.GetAccessToken(String Tenant, String clientId, String clientSecret, String userName, String password, String[] scopes) in D:\CodeRepositories\CloverleafCMS-Microservices-Abp\services\token\CloverleafCMS.TokenService\Tokens\TokenAppService.cs:line 39
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.GlobalFeatures.GlobalFeatureInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Validation.ValidationInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Auditing.AuditingInterceptor.ProceedByLoggingAsync(IAbpMethodInvocation invocation, AbpAuditingOptions options, IAuditingHelper auditingHelper, IAuditLogScope auditLogScope)
at Volo.Abp.Auditing.AuditingInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
at TokenService.Tokens.TokenController.GetAccessToken(TokenRequestDto input) in D:\CodeRepositories\CloverleafCMS-Microservices-Abp\services\token\CloverleafCMS.TokenService\Controllers\TokenController.cs:line 25
at lambda_method2378(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
[13:23:06 INF] Executing ObjectResult, writing value of type 'Volo.Abp.Http.RemoteServiceErrorResponse'.
[13:23:06 INF] Executed action TokenService.Tokens.TokenController.GetAccessToken (CloverleafCMS.TokenService) in 984.4926ms
[13:23:06 INF] Executed endpoint 'TokenService.Tokens.TokenController.GetAccessToken (CloverleafCMS.TokenService)'
[13:23:06 INF] Request finished HTTP/1.1 POST http://cloverleafcms-dev-apps-token/api/token - 403 null application/json; charset=utf-8 1042.2538ms
Following is the code in the token app service
using Duende.IdentityModel.Client;
using Volo.Abp;
using TokenService.Tokens;
using Volo.Abp.Application.Services;
namespace CloverleafCMS.TokenService.TokenService;
public class TokenAppService : ApplicationService, ITokenAppService
{
private readonly IConfiguration _configuration;
public TokenAppService(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task<TokenResponseDto> GetAccessToken(
string? Tenant,
string clientId,
string clientSecret,
string userName,
string password,
string[] scopes
)
{
Check.NotNull(clientId, nameof(clientId));
Check.NotNull(clientSecret, nameof(clientSecret));
Check.NotNull(userName, nameof(userName));
Check.NotNull(password, nameof(password));
var apiEndpoint = _configuration.GetValue<string>("AuthServer:Authority");
var scope = string.Join(" ", scopes);
var discoveryCache = new DiscoveryCache(apiEndpoint);
var disco = await discoveryCache.GetAsync();
if (disco.IsError)
{
Console.WriteLine(disco.Error);
throw new UserFriendlyException($"Error retrieving discovery document: {disco.Error}");
}
var client = new HttpClient();
var passwordTokenRequest = new PasswordTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = clientId,
ClientSecret = clientSecret,
UserName = userName,
Password = password,
Scope = scope
};
if (Tenant != null) passwordTokenRequest.Headers.Add("tenant", Tenant);
var tokenResponse = await client.RequestPasswordTokenAsync(passwordTokenRequest);
TokenResponseDto tokenRequestResponse = new();
if (tokenResponse.IsError)
{
Console.WriteLine("error", tokenResponse);
throw new UserFriendlyException($"Error retrieving token: {tokenResponse.ErrorDescription}");
}
else
{
tokenRequestResponse.AccessToken = tokenResponse.AccessToken;
tokenRequestResponse.RefreshToken = tokenResponse.RefreshToken;
tokenRequestResponse.ExpiresIn = tokenResponse.ExpiresIn;
}
return tokenRequestResponse;
}
}
When I call the token I get the error.
curl --location 'https://webgateway.mydomain.dev/api/token' \
--header 'Content-Type: application/json' \
--data-raw '{
"clientId": "CloverleafAPI",
"clientSecret": "*****",
"userName": "****",
"password": "****",
"scopes": ["address","email","phone","profile","roles","ActionItemService","AdministrationService","AIService","AuditLoggingService","AuthServer","ClientService","ClientServicesQuery","CommunicationsTemplateService","ContactService","DocTemplateService","DocumentService","EngagementLogService","FinancialService","GdprService","GuardianshipService","HousingService","HudService","IdentityService","LanguageService","MemberConfigService","NoteService","SaasService","ServicesService","StaffService","TokenService","WorkshopService"]
}'
{"error":{"code":null,"message":"Error retrieving discovery document: Endpoint does not use HTTPS: http://authserver.mydomain.dev/connect/authorize","details":null,"data":{},"validationErrors":null}}% ```
When I examine the authserver pod log it appears the configuration was created successfully but that's where it ends
```cs
[13:23:05 INF] Request starting HTTP/1.1 GET http://authserver.mydomain.dev/.well-known/openid-configuration - null null
[13:23:05 WRN] Unknown proxy: [::ffff:10.244.2.61]:41130
[13:23:05 INF] The request URI matched a server endpoint: Configuration.
[13:23:05 INF] The configuration request was successfully extracted: {}.
[13:23:05 INF] The configuration request was successfully validated.
[13:23:06 INF] The response was successfully returned as a JSON document: {
"issuer": "https://authserver.mydomain.dev/",
"authorization_endpoint": "http://authserver.mydomain.dev/connect/authorize",
"token_endpoint": "http://authserver.mydomain.dev/connect/token",
"introspection_endpoint": "http://authserver.mydomain.dev/connect/introspect",
"end_session_endpoint": "http://authserver.mydomain.dev/connect/endsession",
"revocation_endpoint": "http://authserver.mydomain.dev/connect/revocat",
"userinfo_endpoint": "http://authserver.mydomain.dev/connect/userinfo",
"device_authorization_endpoint": "http://authserver.mydomain.dev/device",
"pushed_authorization_request_endpoint": "http://authserver.mydomain.dev/connect/par",
"jwks_uri": "http://authserver.mydomain.dev/.well-known/jwks",
"grant_types_supported": [
"authorization_code",
"implicit",
"password",
"client_credentials",
"refresh_token",
"urn:ietf:params:oauth:grant-type:device_code",
"LinkLogin",
"Impersonation"
],
"response_types_supported": [
"code",
"code id_token",
"code id_token token",
"code token",
"id_token",
"id_token token",
"token",
"none"
],
"response_modes_supported": [
"query",
"form_post",
"fragment"
],
"scopes_supported": [
"openid",
"offline_access",
"email",
"profile",
"phone",
"roles",
"address",
"ActionItemService",
"AdministrationService",
"AIService",
"AuditLoggingService",
"AuthServer",
"ClientService",
"ClientServicesQuery",
"CommunicationsTemplateService",
"ContactService",
"DocTemplateService",
"DocumentService",
"EngagementLogService",
"FinancialService",
"GdprService",
"GuardianshipService",
"HousingService",
"HudService",
"IdentityService",
"LanguageService",
"MemberConfigService",
"NoteService",
"SaasService",
"ServicesService",
"SMSService",
"StaffService",
"TokenService",
"WorkshopService"
],
"claims_supported": [
"aud",
"exp",
"iat",
"iss",
"sub"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"code_challenge_methods_supported": [
"plain",
"S256"
],
"subject_types_supported": [
"public"
],
"prompt_values_supported": [
"consent",
"login",
"none",
"select_account"
],
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"introspection_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"revocation_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"device_authorization_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"pushed_authorization_request_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt",
"client_secret_basic"
],
"require_pushed_authorization_requests": false,
"claims_parameter_supported": false,
"request_parameter_supported": false,
"request_uri_parameter_supported": false,
"tls_client_certificate_bound_access_tokens": false,
"authorization_response_iss_parameter_supported": true
}.
[13:23:06 INF] Request finished HTTP/1.1 GET http://authserver.mydomain.dev/.well-known/openid-configuration - 200 3354 application/json;charset=UTF-8 900.7678ms
We have what I think is the exact same setup running in another cluster with no problem right now. However, this problem keeps popping up when we update the deployment. We use the same helm charts in both clusters and only change the values for the variables that are different between environments.
We're running the micro service template solution in AKS. How do we turn off the health-check messages? They're writing every 10 seconds which makes it difficult to find other log messages for debugging purposes
Applications using HealthChecks.UI.Client; using Microsoft.AspNetCore.Diagnostics.HealthChecks;
Thanks.
It was the Redis cache. Once I cleared it, I was able to edit them.
Solution Configuration
This just started happening, perhaps with my upgrade to Abp Studio Version 1.1.1.
If I create a new Microservice module in our existing solution created with the Micorservice Template, then use Abp Suite to generate the CRUD entities it isn't automatically seeding the permission grants database for the 'admin' role like it has in the past.
It is adding the permission group and permissions though.
Also, in the MVC web UI, the new permission group and permissions aren't showing so they can't be assigned to the manually.
Steps to reproduce:
Add a new Microservice module to an existing Microservice solution. Add a new entity and properties using Abp Suite. Generate the solution updates and migrations. Run the new microservice service on localhost Run a sql query to get the permission group, permissions and permission grants from the Administration database SELECT * FROM [CloverleafCMS__ST_Administration].[dbo].[AbpPermissionGroups] WHERE [DisplayName] LIKE '%TestS%' ORDER BY [Name]
SELECT * FROM [CloverleafCMS__ST_Administration].[dbo].[AbpPermissions] WHERE [Name] LIKE '%Items%' ORDER BY [GroupName], [Name]
SELECT * FROM [CloverleafCMS__ST_Administration].[dbo].[AbpPermissionGrants] -- WHERE [TenantId] IS NOT NULL -- AND [ProviderKey] != 'admin' WHERE [Name] LIKE '%.Items%' ORDER BY [TenantId], [ProviderKey], [Name]
However when I log in as admin in the host tenant the new permission group isn't available for assigning to a role.
I cleared my browser cache and it's still not showing.