Cem
Cem

Reputation: 357

Docker and identity server 4, api, angular : Cannot assign requested address

I set up a docker in macos (but should work in any environement):

1) Identity server 4 running in a container

launchsettings:

"MacTest": {
  "commandName": "Project",
  "environmentVariables": {
    "ASPNETCORE_HTTPS_PORT": "44000",
    "ASPNETCORE_ENVIRONMENT": "MacTest"
  },
  "applicationUrl": "https://0.0.0.0:44000" 
}

dockerfile (dockerfile-idp):

ENTRYPOINT ["dotnet", "run", "--launch-profile", "MacTest"]

composer:

identityserver:
image: idp
build: 
  context: .
  dockerfile: ./docker/dockerfile-idp
ports:
 - "9000:9000"
 - "44000:44000"
volumes:
 - .:/idp

2) An APIsource authenticate on identity server running on an container: launchsettings:

"MacTest": {
  "commandName": "Project",
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "MacLocalTest",
    "ASPNETCORE_HTTPS_PORT": 44100
  },
  "applicationUrl": "https://0.0.0.0:44100"
}

dockerfile (dockerfile-api):

ENTRYPOINT ["dotnet", "run", "--launch-profile", "MacTest"]

composer:

  api:
image: api
build: 
  context: .
  dockerfile: ./docker/dockerfile-api
ports:
 - "9100:9100"
 - "44100:44100"
volumes:
 - .:/api 

3) An angular app running on other container

Problem: Angular login page can connect to identity server and can get the token that works... OK

It can can Api and retrieve public data... OK

BUT it can't call a protected method with Authorize. I start believing that the api try to authenticate itself from identity server but for some reason it can't access to the server.

[HttpGet("info")]
[AppAuthorize]   => THIS NOT WORK 
public IActionResult Info()
{
...
} 

ERROR:

System.Net.Sockets.SocketException (99): Cannot assign requested address
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
HttpRequestException: Cannot assign requested address
System.Net.Http.ConnectHelper.ConnectAsync(string host, int port, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask<ValueTuple<HttpConnection, HttpResponseMessage>> creationTask)
System.Threading.Tasks.ValueTask<TResult>.get_Result()
System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, bool doRequestAuth, CancellationToken cancellationToken)
System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task<HttpResponseMessage> sendTask, HttpRequestMessage request, CancellationTokenSource cts, bool disposeCts)
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)

Show raw exception details
System.Net.Http.HttpRequestException: Cannot assign requested address ---> System.Net.Sockets.SocketException: Cannot assign requested address
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
IOException: IDX20804: Unable to retrieve document from: 'https://localhost:44000/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(string address, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>.GetConfigurationAsync(CancellationToken cancel)

Show raw exception details
System.IO.IOException: IDX20804: Unable to retrieve document from: 'https://localhost:44000/.well-known/openid-configuration'. ---> System.Net.Http.HttpRequestException: Cannot assign requested address ---> System.Net.Sockets.SocketException: Cannot assign requested address
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   --- End of inner exception stack trace ---
   at Microsoft.IdentityModel.Protocols.HttpDocumentRetriever.GetDocumentAsync(String address, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectConfigurationRetriever.GetAsync(String address, IDocumentRetriever retriever, CancellationToken cancel)
   at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
InvalidOperationException: IDX20803: Unable to obtain configuration from: 'https://localhost:44000/.well-known/openid-configuration'.
Microsoft.IdentityModel.Protocols.ConfigurationManager<T>.GetConfigurationAsync(CancellationToken cancel)
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync() in C:\local\identity\server4\AccessTokenValidation\src\IdentityServerAuthenticationHandler.cs
Microsoft.AspNetCore.Authentication.AuthenticationHandler<TOptions>.AuthenticateAsync()
Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, string scheme)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.InvokeCore(HttpContext context)
Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I'm trying to set a new wetwork setting but quite challanging, I don't even know if the network is the problem. Anybody can help?

Thnak you

Upvotes: 2

Views: 3406

Answers (3)

Cem
Cem

Reputation: 357

I resolved my problem (not yet with https) but notmal workflow get worked.

If anybody had the same issue I recommend the article: Exactly what I did but I have an angular app in plus

For https I recommend: To get it work with https

It's quite challenging, still work to do but at least this enoying step done.

Upvotes: 0

Cem
Cem

Reputation: 357

Thank you for your help. I think I managed to pass this error and now another error shows up:

AuthenticationException: The remote certificate is invalid according to the validation procedure.

identity server startup:

services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "https://localhost:44000";
                options.SupportedTokens = SupportedTokens.Jwt;
                // Note: Set to true in production
                options.RequireHttpsMetadata = true;
                options.ApiName = "api";
            });

Api startup:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = "oidc";
        })
        .AddIdentityServerAuthentication(options =>
        {
            options.Authority = "https://idp:44000";
            options.RequireHttpsMetadata = true;
            options.ApiName = "api";
        });

I couldn't find any solution. Is it any certificate problem do you think?

Upvotes: 0

Kristian Barrett
Kristian Barrett

Reputation: 3762

So you have shown a lot of the setup of the IdentityServer, but you haven't shown much of the setup for your API.

My best bet is one of the following two:

1) You haven't installed a middleware and set it up correctly on your API. And therefore the API is not able to do anything with the bearer token.

From the documentation: Securing APIs

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        // base-address of your identityserver
        options.Authority = "https://demo.identityserver.io";

        // name of the API resource
        options.Audience = "api1";
    });

You need to add the authority (which is the IdentityServer) and then you need to tell the IdentityServer that it will be securing an API. All of this can be found in the documentation.

2) Your network between the two docker containers does not allow them to communicate with each other.

Try to connect to the docker container of your API with SSH (google how to do that). Try to call the identityserver with cURL and see if you can hit the IP from inside of the Docker container of the API. If you cannot do that, you need to setup a shared internal network between the two docker containers.

Upvotes: 2

Related Questions