'Configure redirect Uris of Identity server in docker environment

Okay, this quite big so just skip to the last section for a brief.

I have a demo application (netcore 6.0) built on micro-service architect, suppose we have 3 services:

  • identity (Auth service - IdentityServer4)
  • frontend (mvc - aspnet)
  • nginx (reverse proxy server)

and all three are running on docker environment here is the docker-compose file

services:
  demo-identity:
    image: ${DOCKER_REGISTRY-}demoidentity:lastest
    build:
      context: .
      dockerfile: Identity/Demo.Identity/Dockerfile
    ports:
      - 5000:80 //only export port 80,
    volumes:
      - ./Identity/Demo.Identity/Certificate:/app/Certificate:ro
    networks:
      - internal

  demo-frontend:
    image: ${DOCKER_REGISTRY-}demofrontend:lastest
    build:
      context: .
      dockerfile: Frontend/Demo.Frontend/Dockerfile
    ports:
      - 5004:80 //only export port 80,
    networks:
      - internal

  proxy:
    build:  
      context: ./nginx-reverse-proxy
      dockerfile: Dockerfile
    ports:
      - 80:80
      - 443:443
    volumes:
      - ./nginx-reverse-proxy/cert/:/etc/cert/
    links:
      - demo-identity
    depends_on:
      - demo-identity
      - demo-frontend
    networks:
      - internal

They all design to run internal, but nginx, it will be the proxy server, and here is the nginx.config file

worker_processes 4;

events { worker_connections 1024; }

http {

    upstream app_servers_identity {
        server demo-identity:80;
    }

    upstream app_servers_frontend {
        server demo-frontend:80;
    }

    server {
        listen 80;
        listen [::]:80;
        server_name demo-identity;
        return 301 https://identity.demo.local$request_uri;
    }

    server {
        listen 80;
        listen [::]:80;
        server_name identity.demo.local;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl;
        server_name identity.demo.local;
        ssl_certificate /etc/cert/demo.crt;
        ssl_certificate_key /etc/cert/demo.key;

        location / {            
            proxy_pass         http://app_servers_identity;
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }

    server {
        listen 80;
        listen [::]:80;
        server_name frontend.demo.local;
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl;
        server_name frontend.demo.local;
        ssl_certificate /etc/cert/demo.crt;
        ssl_certificate_key /etc/cert/demo.key;

        location / {   
            proxy_pass         http://app_servers_frontend;
            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
        }
    }
}

also I update the host file to configure two virtual hosts identity.demo.local and frontend.demo.local (the term "localhost" sometimes confusing me when using docker.)

Then I setup the identity server like this

...
builder.Services.Configure<IdentityOptions>(options => {
    // Default Password settings.
});

services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddAspNetIdentity<ApplicationUser>()
.AddSigningCredential(new X509Certificate2("./Certificate/demo_dev.pfx", "******"));
...

and here is the client static config

               ...
                new Client
                {
                    ClientName = "MVC Client",
                    ClientId = "mvc-client",
                    AllowedGrantTypes = GrantTypes.Hybrid,
                    RedirectUris = new List<string>{ "http://gateway.demo.local/signin-oidc"},
                    RequirePkce = false,
                    AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile },
                    ClientSecrets = { new Secret("MVCSecret".Sha512()) }
                }
               ...

In the Frontend service, I also configure Oidc as below

...
services.AddAuthentication(opt =>
{
    opt.DefaultScheme = "Cookies";
    opt.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", opt => {

    opt.CookieManager = new ChunkingCookieManager();

    opt.Cookie.HttpOnly = true;
    opt.Cookie.SameSite = SameSiteMode.None;
    opt.Cookie.SecurePolicy = CookieSecurePolicy.Always;
})
.AddOpenIdConnect("oidc", opt => {
    opt.SignInScheme = "Cookies";
    opt.Authority = "http://demo-identity";
    opt.ClientId = "mvc-client";
    opt.ResponseType = "code id_token";
    opt.SaveTokens = true;
    opt.ClientSecret = "MVCSecret";
    opt.ClaimsIssuer = "https://identity.demo.local";
    opt.RequireHttpsMetadata = false;
});
...

TL,DR: A micro-service application host on docker, which included IdentityServer, MVC, Nginx. They all run internal and only can be access via nginx proxy. The host name also configure to virtual host names - which make more sense.

Okay here is the problem, when I access to a protected api of MVC, it redirect me to identity server (identity.demo.local) to login, but after I login success, it should redirect me to the mvc, but it did not. After research, I figure out the reason that after login, the identity redirect me to the origin site with the cookies contain authentication info, but the redirect uri is not secured, it's http://frontend.demo.local instead of https. I'm not sure how this property is configured ( I try to update the nginx.conf but nothing change). And it still work correctly when I run by visual studio, without docker.

Any help is appreciated.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source