身份服务器4 - 停用发现端点

时间:2017-05-09 09:03:12

标签: c# mongodb openid identityserver4

我正在开发一个身份验证服务器来提供令牌,用于使用 IdentityServer4 来使用我们的API。 我使用MongoDB作为数据库,我允许用户获取令牌,为了更安全,我使用自定义证书来加密令牌。 这就是我AuthenticationServer Startup.cs 的样子:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

    var cert = new X509Certificate2(Path.Combine(_environment.ContentRootPath, "cert", "whatever.pfx"), "whatever");

    services.AddIdentityServer().AddSigningCredential(cert)
            .AddInMemoryApiResources(Config.Config.GetApiResources());

    services.AddTransient<IUserRepository, UserRepository>();

    services.AddTransient<IClientStore, ClientStore>();
    services.AddTransient<IProfileService, UserProfileService>();
    services.AddTransient<IResourceOwnerPasswordValidator, UserResourceOwnerPasswordValidator>();
    services.AddTransient<IPasswordHasher<User.Model.User>, PasswordHasher<User.Model.User>>();

}

如您所见,我可以自定义实现客户端身份验证和密码验证的接口。这很好。

然后我用生成的令牌保护另一个应用程序,我在那里定义它必须使用IdentityServerAuthetication(localhost:5020是我的AuthenticationServer所在的位置运行)

 public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseCors("CorsPolicy");

        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
        {
            Authority = "http://localhost:5020",
            RequireHttpsMetadata = false,
            ApiName = "MyAPI",
            RoleClaimType = JwtClaimTypes.Role
        });

        app.UseMvc();
    }

一切正常,但如果我关闭了AuthenticationServer,那么我从我正在保护的API中收到此错误:

  

System.InvalidOperationException:IDX10803:无法从:&#39; http://localhost:5020/.well-known/openid-configuration&#39;获取配置。      在Microsoft.IdentityModel.Protocols.ConfigurationManager`1.d__24.MoveNext()   ---从抛出异常的先前位置开始的堆栈跟踪结束---      在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)      在Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.d__1.MoveNext()   失败:Microsoft.AspNetCore.Server.Kestrel [13]

所以看起来API似乎是去发现端点看看解密令牌的端点在哪里(我猜它会是userinfo_endpoint)。

我的观点是:

  • 似乎发现端点用于获取有关如何使用身份验证服务器的信息(对我来说对开放API有意义),但在我们的例子中,我们不是在开发和开放API,所以我们的客户只是我们已达成协议,我们会提前告知他们终端,我们很可能会受到IP地址的限制。
  • 有没有办法停用发现端点,并在API上设置证书以正确解密令牌。

也许我错过了完整的画面,我说的是愚蠢的事情,但我很乐意理解背后的概念。 提前致谢

3 个答案:

答案 0 :(得分:1)

可以让发现端点关闭/不可用并仍然验证令牌。

您需要实现IConfigurationManager并将其传递给IdentityServerAuthenticationOptions中的JwtBearerOptions对象。

以下是一些示例代码:

public class OidcConfigurationManager : IConfigurationManager<OpenIdConnectConfiguration>
{
    public OidcConfigurationManager()
    {
        SetConfiguration();
    }
    private OpenIdConnectConfiguration _config;
    public Task<OpenIdConnectConfiguration> GetConfigurationAsync(CancellationToken cancel)
    {
        return Task.FromResult<OpenIdConnectConfiguration>(_config);
    }
    public void RequestRefresh()
    {
    }

    private void SetConfiguration()
    {
        // Build config from JSON
        var configJson =
            @"{""issuer"":""http://localhost/id"",""jwks_uri"":""http://localhost/id/.well-known/openid-configuration/jwks"",""authorization_endpoint"":""http://localhost/id/connect/authorize"",""token_endpoint"":""http://localhost/id/connect/token"",""userinfo_endpoint"":""http://localhost/id/connect/userinfo"",""end_session_endpoint"":""http://localhost/id/connect/endsession"",""check_session_iframe"":""http://localhost/id/connect/checksession"",""revocation_endpoint"":""http://localhost/id/connect/revocation"",""introspection_endpoint"":""http://localhost/id/connect/introspect"",""frontchannel_logout_supported"":true,""frontchannel_logout_session_supported"":true,""scopes_supported"":[""openid"",""profile"",""api1"",""offline_access""],""claims_supported"":[""sub"",""name"",""family_name"",""given_name"",""middle_name"",""nickname"",""preferred_username"",""profile"",""picture"",""website"",""gender"",""birthdate"",""zoneinfo"",""locale"",""updated_at""],""grant_types_supported"":[""authorization_code"",""client_credentials"",""refresh_token"",""implicit"",""password""],""response_types_supported"":[""code"",""token"",""id_token"",""id_token token"",""code id_token"",""code token"",""code id_token token""],""response_modes_supported"":[""form_post"",""query"",""fragment""],""token_endpoint_auth_methods_supported"":[""client_secret_basic"",""client_secret_post""],""subject_types_supported"":[""public""],""id_token_signing_alg_values_supported"":[""RS256""],""code_challenge_methods_supported"":[""plain"",""S256""]}";
        _config = new OpenIdConnectConfiguration(configJson);

        // Add signing keys if not present in json above
        _config.SigningKeys.Add(new X509SecurityKey(cert));
    }
}

现在将该配置对象传递给IdentityServerAuthenticationOptions中的一些JwtBearerOptions(有点烦人,但这是我所知道的唯一方式)

var identityServerOptions = new IdentityServerAuthenticationOptions
{
    Authority = "http://localhost:5020",
    RequireHttpsMetadata = false,
    ApiName = "MyAPI",
    RoleClaimType = JwtClaimTypes.Role,

};
var jwtBearerOptions = new JwtBearerOptions() {ConfigurationManager = new OidcConfigurationManager()};
var combinedOptions = CombinedAuthenticationOptions.FromIdentityServerAuthenticationOptions(identityServerOptions);
combinedOptions.JwtBearerOptions = jwtBearerOptions;
app.UseIdentityServerAuthentication(combinedOptions);

现在,即使OIDC发现端点关闭,您的API也能够接收令牌并验证签名。

答案 1 :(得分:1)

API验证中间件在启动时下载发现文档的副本 - 然后(至少在默认情况下)每24小时下载一次。

如果签名验证失败,可能会重新触发下载(以适应计划外密钥翻转)。

您可以静态定义所有配置值 - 但是您将失去动态配置更新的所有好处。

如果您的发现端点不可用,那么整个令牌服务可能无法正常运行,这可能是一个更大的问题。

答案 2 :(得分:0)

IdentityServer需要X509证书的公钥来验证access_token。它正在使用发现端点来获取该公钥,并且不时刷新已保存的公钥(因为公钥可能会更改)。

如果无法访问IdentityServer,则您的API无法保证access_token有效。您可以增加access_token验证请求结果的缓存。

我对IdentityServer4.AccessTokenValidation并不完全确定,但是使用IdentityServer3.AccessTokenValidation,您可以将ValidationMode设置为Local,因此只需下载一次公钥即可。