hi i trying to learn identity server 4 . i tried a simple project with api client id4 api-gateway .... but now i try the same project with docker container. my client app at the beginning must redirect to identity server login page but throw error
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsyncInternal(AuthenticationProperties properties)
at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleChallengeAsync(AuthenticationProperties properties)
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.ChallengeAsync(AuthenticationProperties properties)
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAlwaysRunResultFilters>g__Awaited|27_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Identiti server client configuration in Config.cs
new Client
{
ClientId = "GEBlazoreApp",
ClientName = "GE frontend Blazor Web Application",
AllowedGrantTypes= GrantTypes.Hybrid,
RequirePkce = false,
AllowRememberConsent = false,
RedirectUris = new List<string>()
{
//gewebapp:80
"http://localhost:3002/signin-oidc"
},
PostLogoutRedirectUris = new List<string>()
{
"http://localhost:3002/signout-callback-oidc"
},
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
AllowedScopes = new List<string>()
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"GeHerd"
},
AllowAccessTokensViaBrowser = true
}
and this is my client program.cs
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Authority = "http://localhost:3300";
options.MetadataAddress = "http://localhost:3300/.well-known/openid-configuration";
//options.Authority = "http://identityserver:80";
//options.MetadataAddress = "http://identityserver:80/.well-known/openid-configuration";
options.ClientId = "GEBlazoreApp";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("GeHerd");
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
});
builder.Services.AddMvcCore(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
and http://localhost:3300/.well-known/openid-configuration is accessible and OK.
this is the docker compose override file
gewebapp:
container_name: gewebapp
environment:
- ASPNETCORE_ENVIRONMENT=Development
depends_on:
- identityserver
ports:
- "3002:80"
- "3003:443"
identityserver:
container_name: identityserver
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "3300:80"
CodePudding user response:
Looks like a container communication issue. The Exception occurs when the OpenId handler tries to parse the response from the discovery to an object. It's probably because the expected json is not being returned.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: 'System.String'.
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
Ensure you reach the discovery endpoint from your web app. You are using the url of your service available from the docker host (localhost):
options.Authority = "http://localhost:3300";
options.MetadataAddress = "http://localhost:3300/.well-known/openid-configuration";
But you need to configure a network to communicate both containers and use the service name instead of localhost:
gewebapp:
container_name: gewebapp
environment:
- ASPNETCORE_ENVIRONMENT=Development
depends_on:
- identityserver
ports:
- "3002:80"
- "3003:443"
networks:
- mynet
identityserver:
container_name: identityserver
environment:
- ASPNETCORE_ENVIRONMENT=Development
ports:
- "3300:80"
networks:
- mynet
And in the handler configuration:
options.Authority = "http://identityserver:3300";
options.MetadataAddress = "http://identityserver:3300/.well-known/openid-configuration";
CodePudding user response:
We had this error because we use self-signed certificate for IdentityServer that the client the web application rejected. Try this solution:
.AddOpenIdConnect("oidc", options =>
{
...
// add this lines
options.BackchannelHttpHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
};
});