【问题标题】:IdentityServer client authentication with public/private keys instead of shared secrets使用公钥/私钥而不是共享密钥的 IdentityServer 客户端身份验证
【发布时间】:2018-09-16 02:19:04
【问题描述】:

我正在尝试对 IdentityServer4 的客户端机密使用公钥/私钥而不是共享机密。这种方法记录在here

如果它是共享密钥,则请求将包含纯文本形式的 secret。例如

curl -X POST \
  http://<identityserver>/connect/token \
  -F client_id=abc \
  -F client_secret=secret \
  -F grant_type=client_credentials \
  -F scope=api1 api2

我的问题是:应该使用公钥/私钥身份验证方法作为secret 传递什么?

为了提供一些背景知识,使用公钥/密钥身份验证的客户端将通过以下步骤向 IdentityServer 注册

  1. 客户端生成一个.crt 文件,例如

    // create key
    $ openssl genrsa -des3 -passout pass:x -out client.pass.key 2048
    $ openssl rsa -passin pass:x -in client.pass.key -out client.key
    
    // create certificate request (csr)
    $ openssl req -new -key client.key -out client.csr
    
    // create certificate (crt)
    $ openssl x509 -req -sha256 -days 365 -in client.csr -signkey client.key -out client.crt
    
    // export pfx file from key and crt
    $ openssl pkcs12 -export -out client.pfx -inkey client.key -in client.crt
    
  2. 客户端将与 IdentityServer 共享 client.crt 文件

  3. IdentityServer 将通过以下方式注册客户端

    var client = new Client
    {
        ClientId = "abc",
        ClientSecrets =
        {
            new Secret
            {
                Type = IdentityServerConstants.SecretTypes.X509CertificateBase64,
                Value = "MIIDF...." <================= contents of the crt file
            }
        },
    
        AllowedGrantTypes = GrantTypes.ClientCredentials,
        AllowedScopes = { "api1", "api2" }
    };
    

【问题讨论】:

  • 您提到了一个server.crt 文件。它是一个错字还是一个不同的文件?哪个是用作客户端机密的 crt 文件(我猜是 client.crt)?
  • 抱歉打错了.. 已修复

标签: c# asp.net-core identityserver4 identityserver3


【解决方案1】:

感谢 IdentityServer4 中的单元测试!

使用公共/私人身份验证时,不使用client_secret。而是使用 client_assertion,这是一个 JWT 令牌。

这是令牌请求的示例代码。 client.pfx 是问题中上述步骤生成的证书包。

var now = DateTime.UtcNow;
var clientId = "abc";
var tokenEndpoint = "http://localhost:5000/connect/token";

var cert = new X509Certificate2("client.pfx", "1234");

// create client_assertion JWT token
var token = new JwtSecurityToken(
    clientId,
    tokenEndpoint,
    new List<Claim>
    {
        new Claim("jti", Guid.NewGuid().ToString()),
        new Claim(JwtClaimTypes.Subject, clientId),
        new Claim(JwtClaimTypes.IssuedAt, now.ToEpochTime().ToString(), ClaimValueTypes.Integer64)
    },
    now,
    now.AddMinutes(1),
    new SigningCredentials(
        new X509SecurityKey(cert),
        SecurityAlgorithms.RsaSha256
    )
);

var tokenHandler = new JwtSecurityTokenHandler();
var tokenString = tokenHandler.WriteToken(token);


// token request - note there's no client_secret but a client_assertion which contains the token above
var requestBody = new FormUrlEncodedContent(new Dictionary<string, string>
{
    {"client_id", clientId},
    {"client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},
    {"client_assertion", tokenString},
    {"grant_type", "client_credentials"},
    {"scope", "api1 api2"}
});


var client = new HttpClient();
var response = await client.PostAsync(tokenEndpoint, requestBody);
var tokenRespone = new TokenResponse(await response.Content.ReadAsStringAsync());

【讨论】:

    【解决方案2】:

    我认为它必须是签名的 JWT。查看 IDS4 代码库中的 PrivateKeyJwtSecretValidator 类:

    https://github.com/IdentityServer/IdentityServer4/blob/2.1.3/src/IdentityServer4/Validation/PrivateKeyJwtSecretValidator.cs

    【讨论】:

      猜你喜欢
      • 2014-07-31
      • 2015-10-20
      • 1970-01-01
      • 1970-01-01
      • 2012-10-27
      • 1970-01-01
      • 2023-03-19
      • 2017-11-08
      • 2013-10-08
      相关资源
      最近更新 更多