Identity Server 4 and docker

2019-02-06 23:00发布

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

1条回答
家丑人穷心不美
2楼-- · 2019-02-06 23:35

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.

查看更多
登录 后发表回答