IdentityServer / IdentityServer4.AccessTokenValidation

IdentityServer Access Token Validation for ASP.NET Core
Apache License 2.0
544 stars 214 forks source link

IdentityServer4.AccessTokenValidation with Authority in the same project #106

Closed ahmadakra closed 5 years ago

ahmadakra commented 5 years ago

Is your feature request related to a problem? Please describe. One goal for our system is to make deployments to new production servers as simple a process as humanly possible.

Describe the solution you'd like We want to embed an instance of IdentityServer4 in the same project as the API we wish to protect. In this setup the "Authority" URI for access token validation is the same URI as the API itself by default. How can we configure this automatically in Startup.cs without requiring that whoever is deploying the system should also manually specify the host URI in a configuration variable?

Describe alternatives you've considered I looked into ways of programmatically retrieving the host URI inside Startup.cs (in order to configure it as the Authority for access token validation), but so far I couldn't find a reliable way to do that.

Help is greatly appreciated, Yours,

leastprivilege commented 5 years ago

Have a look what Microsoft is doing with their new IdentityServer integration. This is exactly what you want.

ahmadakra commented 5 years ago

Thanks for your reply,

Yes! We just found out that ASP.NET Core 2.2 is shipping soon with exactly the feature we need. This is good news.

ahmadakra commented 5 years ago

They didn't ship that feature after all :/

brockallen commented 5 years ago

They didn't ship that feature after all

It will be included in an out-of-band release after 2.2 (along with the updates to VS for the templates) // @blowdart

blowdart commented 5 years ago

What Brock said. And no I don't have a date yet.

ahmadakra commented 5 years ago

@blowdart I hope I am not sounding pushy, but do you now have a rough/order-of-magnitude estimate on when this will be released? Just to help us plan that's all.

We appreciate all your good work

leastprivilege commented 5 years ago

We will have that built–in in 2.4

It’s already on the dev branch.

@blowdart maybe you want to use that — less code for you to maintain

ahmadakra commented 5 years ago

@leastprivilege looking forward to it! We cooked up something due to time constraints, the relevant code is all below. We managed to wire everything with 0-configuration except for one last piece (which has a TODO next to it below):

(1) IClientStore implementation at IdentityServer level which works with 0-config if the client is hosted in the same domain as IdentityServer:

    /// <summary>
    /// This client store implementation authorizes one client which is - by default - hosted in the same domain as IdentityServer
    /// </summary>
    public class DefaultsToSameOriginClientStore : IClientStore
    {
        private readonly IHttpContextAccessor _accessor;
        private readonly ClientStoreConfiguration _config;

        public DefaultsToSameOriginClientStore(IHttpContextAccessor accessor, IOptions<ClientStoreConfiguration> options)
        {
            _accessor = accessor;
            _config = options.Value;
        }

        // Implementation of IClientStore
        public Task<Client> FindClientByIdAsync(string clientId)
        {
            if(clientId != "MyClient"){
                return Task.FromResult<Client>(null);
            }

            // Determine the client app's URI from configuration
            var uri = _config.WebClientUri;
            if (string.IsNullOrWhiteSpace(uri))
            {
                // **IF it is not in configuration, assume it is hosted in the SAME domain as IdentityServer**
                var request = _accessor?.HttpContext?.Request;
                uri = $"https://{request?.Host}/{request?.PathBase}";
            }

            var client = new Client
            {
                ClientId = "MyClient",
                AllowedGrantTypes = GrantTypes.Implicit,
                AllowAccessTokensViaBrowser = true,
                RedirectUris = { $"{uri}sign-in-callback", $"{uri}assets/silent-refresh-callback.html" },
                PostLogoutRedirectUris = { $"{uri}welcome" },
                AllowedCorsOrigins = { uri },
                RequireConsent = false,
                AllowedScopes =
                    {
                        IdentityServerConstants.StandardScopes.OpenId,
                        IdentityServerConstants.StandardScopes.Profile,
                        IdentityServerConstants.StandardScopes.Email,
                        "MyAPI"
                    },
            };

            return Task.FromResult(client));
        }
    }
}

(2) Access token validation at the API level, with 0-config if the API is in the same domain as IdentityServer:

            var authorityUri = config["ApiAuthentication:AuthorityUri"];
            if (string.IsNullOrWhiteSpace(authorityUri))
            {
                // IF Authority is not specified in config assume IdentityServer is in the same domain as the API
                authorityUri = "https://localhost:44339"; // TODO: RETRIEVE THE HOST DOMAIN DYNAMICALLY!!
            }

            // Add access token validation for the API
            services.AddAuthentication()
            .AddIdentityServerAuthentication(JwtBearerDefaults.AuthenticationScheme, options =>
            {
                options.Authority = authorityUri;
                options.ApiName = "MyAPI";
            });
leastprivilege commented 5 years ago

Here is what we will put in.

https://github.com/IdentityServer/IdentityServer4/commit/29f2c4c6a5f7dcb9a3ef98d5cc547ba161396cc3