Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Para provar sua identidade, os aplicativos cliente confidenciais trocam um segredo com Microsoft Entra ID. O segredo pode ser:
- Um segredo do cliente (senha do aplicativo).
- Um certificado, que é usado para criar uma declaração assinada contendo declarações padrão.
Esse segredo também pode ser uma declaração assinada diretamente.
MSAL.NET tem quatro métodos para fornecer credenciais ou declarações ao aplicativo cliente confidencial:
.WithClientSecret().WithCertificate().WithClientAssertion().WithClientClaims()
Note
Embora seja possível usar a WithClientAssertion() API para adquirir tokens para o cliente confidencial, não recomendamos usá-la por padrão, pois ela é mais avançada e foi projetada para lidar com cenários muito específicos que não são comuns. O uso da .WithCertificate() API permitirá que MSAL.NET manipule isso para você. Esta API permite que você personalize sua solicitação de autenticação, se necessário, mas a asserção padrão criada por .WithCertificate() será suficiente para a maioria dos cenários de autenticação. Essa API também pode ser usada como uma solução alternativa em alguns cenários em que MSAL.NET falha ao executar a operação de assinatura internamente. A diferença entre os dois é que usar o WithCertificate() exige que o certificado e a chave privada estejam disponíveis na máquina que cria a asserção, e usar o WithClientAssertion() permite calcular a asserção em outro lugar, como no Azure Key Vault, a partir da Identidade Gerenciada ou com um módulo de segurança de hardware.
Declarações de cliente
Isso é útil se você quiser manipular o certificado por conta própria. Por exemplo, se você quiser usar as APIs do Azure Key Vault para assinar, o que elimina a necessidade de baixar os certificados. Uma declaração de cliente assinada assume a forma de um JWT assinado com o conteúdo que contém as declarações de autenticação necessárias exigidas pelo Microsoft Entra ID, codificado em Base64. Ou pode ser um JWT emitido por um provedor de identidade diferente, no cenário de "Credencial de Identidade Federada".
Use o delegado, que permite calcular a asserção sempre que a MSAL precisar obter um novo token do provedor de identidade. A MSAL não invoca seu delegado se um token for encontrado no cache.
string signedClientAssertion = GetOrComputeAssertion();
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithClientAssertion(async (AssertionRequestOptions options) => {
// use 'options.ClientID' or 'options.TokenEndpoint' to generate client assertion
return await GetClientAssertionAsync(options.ClientID, options.TokenEndpoint, options.CancellationToken);
})
.Build();
As declarações esperadas por Microsoft Entra ID na declaração assinada são:
| Tipo de declaração | Valor | Description |
|---|---|---|
| aud | https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token |
A declaração "aud" (audiência) identifica os destinatários para os quais o JWT se destina (aqui Microsoft Entra ID) Consulte RFC 7519, Seção 4.1.3. Nesse caso, o destinatário é o ponto de extremidade do token do provedor de identidade |
| exp | 1601519414 | A declaração "exp" (hora de expiração) identifica a hora de expiração ou a hora após ela na qual o JWT NÃO DEVE ser aceito para processamento. Consulte RFC 7519, Seção 4.1.4. Isso permite que a declaração seja usada até esse momento, portanto limite-a a, no máximo, 5 a 10 minutos após nbf. O Microsoft Entra ID não impõe restrições ao tempo exp atualmente. |
| iss | {ClientID} | A declaração "iss" (issuer) identifica a entidade de segurança que emitiu o JWT, neste caso, o aplicativo cliente. Use a ID do aplicativo GUID. |
| jti | (um Guid) | A declaração "jti" (ID JWT) fornece um identificador exclusivo para o JWT. O valor do identificador DEVE ser atribuído de uma maneira que garanta que haja uma probabilidade insignificante de que o mesmo valor possa ser atribuído acidentalmente a um objeto de dados diferente. Se o aplicativo usar vários emissores, as colisões deverão ser evitadas entre os valores produzidos por emissores diferentes também. O valor "jti" é uma cadeia de caracteres que diferencia maiúsculas de minúsculas. RFC 7519, Seção 4.1.7 |
| nbf | 1601519114 | A declaração "nbf" (não antes) identifica a hora antes da qual o JWT NÃO DEVE ser aceito para processamento. RFC 7519, Seção 4.1.5. Usar a hora atual é apropriado. |
| sub | {ClientID} | A declaração "sub" (subject) identifica o assunto do JWT, neste caso, também seu aplicativo. Use o mesmo valor que iss. |
Se você usar um certificado como um segredo do cliente, o certificado deverá ser implantado com segurança. Recomendamos que você armazene o certificado em um local seguro compatível com a plataforma, como no repositório de certificados no Windows ou usando Azure Key Vault.
Criando a asserção
Este é um exemplo usando Microsoft. IdentityModel.JsonWebTokens para criar a declaração para você.
string GetSignedClientAssertion(X509Certificate2 certificate, string tenantId, string clientId)
{
// no need to add exp, nbf as JsonWebTokenHandler will add them by default.
var claims = new Dictionary<string, object>()
{
{ "aud", tokenEndpoint },
{ "iss", clientId },
{ "jti", Guid.NewGuid().ToString() },
{ "sub", clientId }
};
var securityTokenDescriptor = new SecurityTokenDescriptor
{
Claims = claims,
SigningCredentials = new X509SigningCredentials(certificate)
};
var handler = new JsonWebTokenHandler();
var signedClientAssertion = handler.CreateToken(securityTokenDescriptor);
}
Como alternativa, se você não quiser usar Microsoft. IdentityModel.JsonWebTokens:
static string Base64UrlEncode(byte[] arg)
{
char Base64PadCharacter = '=';
char Base64Character62 = '+';
char Base64Character63 = '/';
char Base64UrlCharacter62 = '-';
char Base64UrlCharacter63 = '_';
string s = Convert.ToBase64String(arg);
s = s.Split(Base64PadCharacter)[0]; // RemoveAccount any trailing padding
s = s.Replace(Base64Character62, Base64UrlCharacter62); // 62nd char of encoding
s = s.Replace(Base64Character63, Base64UrlCharacter63); // 63rd char of encoding
return s;
}
static string GetSignedClientAssertion(X509Certificate2 certificate, string tenantId, string clientId)
{
// Get the RSA with the private key, used for signing.
var rsa = certificate.GetRSAPrivateKey();
//alg represents the desired signing algorithm, which is SHA-256 in this case
//x5t represents the certificate thumbprint base64 url encoded
var header = new Dictionary<string, string>()
{
{ "alg", "PS256"},
{ "typ", "JWT" },
{ "x5t#S256", Base64UrlHelpers.Encode(certificate.GetCertHash(HashAlgorithmName.SHA256))},
};
//Please see the previous code snippet on how to craft claims for the GetClaims() method
var claims = GetClaims(tenantId, clientId);
var headerBytes = JsonSerializer.SerializeToUtf8Bytes(header);
var claimsBytes = JsonSerializer.SerializeToUtf8Bytes(claims);
string token = Base64UrlEncode(headerBytes) + "." + Base64UrlEncode(claimsBytes);
string signature = Base64UrlEncode(rsa.SignData(Encoding.UTF8.GetBytes(token), HashAlgorithmName.SHA256, RSASignaturePadding.Pss));
string signedClientAssertion = string.Concat(token, ".", signature);
return signedClientAssertion;
}
WithClientClaims
Em alguns casos, os desenvolvedores querem injetar algumas declarações nas declarações, mas ainda gostariam que a MSAL lidasse com a criação da declaração e da assinatura.
WithClientClaims(X509Certificate2 certificate, IDictionary<string, string> claimsToSign, bool mergeWithDefaultClaims = true) produz uma asserção assinada que contém as declarações esperadas pelo Microsoft Entra ID, além de outras declarações de cliente que você deseja enviar.
string ipAddress = "192.168.1.2";
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithAuthority(new Uri(config.Authority))
.WithClientClaims(certificate,
new Dictionary<string, string> { { "client_ip", ipAddress } })
.Build();
Se uma das declarações no dicionário que você passar for a mesma que uma das declarações obrigatórias, o valor da declaração adicional será levado em conta. Ele substitui as declarações computadas por MSAL.NET.
Se você quiser fornecer as próprias declarações, incluindo as declarações obrigatórias esperadas pelo Microsoft Entra ID, passe false para o parâmetro mergeWithDefaultClaims.