Reputation: 7668
I'm trying to configure IdentityServer4 with docker but I cannot make it work. To get started, I took the Client Credential example of the identity server documentation: Protecting an API using Client Credentials
IdentityServer
Hosted on port 5000
WebApi
Hosted on port 5001
In the Configure
method of the Startup.cs
file of my WebApi I did the following (the problem is probably here):
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = "http://web:5000",
RequireHttpsMetadata = false,
ApiName = "api1"
});
Client
And the client
// Everything is fine here...
var disco = await DiscoveryClient.GetAsync("http://localhost:5000");
var tokenClient = new TokenClient(disco.TokenEndpoint, "client", "secret");
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("api");
// This does not work
var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync("http://localhost:5001/identity");
The problem is probably in my WebApi:
1) If I set the authority to localhost:5000, I get an internal server error: "Unable to obtain configuration from: 'http://localhost:5000/.well-known/openid-configuration'" which makes sense since localhost:5000 is unknown in this container
2) If I set the authority to http://web:5000 I get an authorization error: "Issuer validation failed. Issuer: 'http://localhost:5000'. Did not match: validationParameters.ValidIssuer: 'http://web:5000' or validationParameters.ValidIssuers" which also makes sense but I don't know if it's possible to change the authority name? I also tried to set the IssuerUri
in the IdentityServer project but it didn't help
Upvotes: 16
Views: 8417
Reputation: 25019
Network
Let's suppose you have two physical machines: C1 and C2. Each machine is a docker host.
C1 runs Auth container.
C2 runs WebApi container.
As you expose port 5000 in Auth dockerfile, the address C1:5000
should be accessible from C2 and from WebApi container itself. You could prefer IPs to DNS, it doesn't matter. Moreover you should be able to make a successfull GET request to http://C1:5000/.well-known/openid-configuration
to be sure.
There are a lot of network issues you could face to achieve that. For example: What would prevent code running in a Docker container from connecting to a database on a separate server?
Issuer validation
Issuer validation failed
Your client's authority URL differs from Auth hostname. By default, authority URL should be equal to issuer
property value (this property is in Identity Server autodiscovery document response).
issuer
property value depends on your client's web request:
GET http://127.0.0.1:6000/.well-known/openid-configuration -> "issuer": "http://127.0.0.1:6000"
GET http://localhost:6000/.well-known/openid-configuration -> "issuer": "localhost:6000"
Try to set IssuerUri
to a constant for a dev environment:
services.AddIdentityServer(x =>
{
x.IssuerUri = "foo";
})
to achieve a constant issuer
value. This allowes to call Identity Server by any valid URL (using IP, machine name or DNS):
GET http://anything/.well-known/openid-configuration -> "issuer": "foo"
DiscoveryClient
also validates issuer
value. It's a simple equality comparison:
public bool ValidateIssuerName(string issuer, string authority)
{
return string.Equals(issuer, authority, StringComparison.Ordinal);
}
You could disable it by:
DiscoveryClient.Policy.ValidateIssuerName = false;
FYI, IssuerUri
setting is not recommended for a production environment:
IssuerUri Set the issuer name that will appear in the discovery document and the issued JWT tokens. It is recommended to not set this property, which infers the issuer name from the host name that is used by the clients.
Upvotes: 16