简体   繁体   English

Microsoft Graph:如何在客户端凭据流中使用证书获取访问令牌? (而不是使用 client_secret)

[英]Microsoft Graph: How to get access token with certificate in client credentials flow? (instead of using a client_secret)

Goal目标

I want to authenticate my daemon application with a certificate instead of client secret against Microsoft Graph & want understand the exact request necessary to successfully authenticate.我想使用证书而不是针对 Microsoft Graph 的客户端密码对我的守护程序应用程序进行身份验证,并希望了解成功进行身份验证所需的确切请求。

Using the following resources:使用以下资源:

Could there be an error in the Azure AD configuration of your app?您的应用程序的 Azure AD 配置是否有错误?

All Azure AD configurations were tested prior with a client-secret .所有 Azure AD 配置均事先使用client-secret进行了测试。 The certificate public key was also uploaded beforehand:证书公钥也是事先上传的: 在此处输入图像描述

Request & Problem请求和问题

I managed to create this request (tenant-id, client-id, certificates are just dummies)我设法创建了这个请求(租户 ID、客户端 ID、证书只是假人)

Values:价值观:

grant_type : urn:ietf:params:oauth:client-assertion-type:jwt-bearer grant_type : urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertion_type : logon_cert client_assertion_typelogon_cert
client_id : my-client-id-from-azure client_idmy-client-id-from-azure
scope : https://graph.microsoft.com/.default scope : https://graph.microsoft.com/.default
client_assertion : JWT containing client_assertion : JWT 包含

  • Header: (x5t contains the base64 encoded certificate sha1 thumbprint from the uploaded certificate, see above picture) Header:(x5t包含上传证书的base64编码证书sha1指纹,见上图)

     { "typ": "JWT", "x5t": "QUY4RjBERERGMDBBOURGRUQ0MzkzODRGQTYzMjhFQ0FBRDNBOEUzNw", "alg": "RS256" }
  • Payload:有效载荷:

     { "iss": "my-client-id-from-azure", "sub": "my-client-id-from-azure", "scope": "https://graph.microsoft.com/.default", "aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token", "iat": 1625591612, "nbf": 1625591612, "exp": 1625595212, "jti": "some-dynamically-generated-uuid" }
Request:要求:
POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=eyJ0eXAiOiJKV1QiLCJ4NXQiOiJSRFUwTUVRd016RkdOakpGTUVOQk5UaEVPVFpGTXpBNFFrRkZNMFUzTmpFd01USkVPRFUwUWc9PSIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsInNjb3BlIjoiaHR0cHM6Ly9ncmFwaC5taWNyb3NvZnQuY29tLy5kZWZhdWx0IiwiYXVkIjoiaHR0cHM6Ly9sb2dpbi5taWNyb3NvZnRvbmxpbmUuY29tL215LXRlbmFudC1pZC9vYXV0aDIvdjIuMC90b2tlbiIsImlhdCI6MTYyNTY2MDU3MywibmJmIjoxNjI1NjYwNTczLCJzdWIiOiJteS1jbGllbnQtaWQtZnJvbS1henVyZSIsImp0aSI6IjlhZTQwYTk2LTliMTgtNDRhOS1hOWM3LWE3NDZjMjA4OGUxMyIsImV4cCI6MTYyNTY2NDE3M30.pw81FeQirjIsnXGlLSLDG5Cz4rIdOuF54M8fPmDlubNs0-DoHpkj9OdrCXlCPDWvQLaYAs3mH9kcSP-Z4rf-NgaiCF-ECL-iA2xxvQ3n8JSDeaPPkLd6tMAKeMm5sEIcap7RJ8Fnt1kCflVAOIuYCh_zijJd9etQj-2wfbtiHnHtlpg6n0-4u7oj9wAx2naIU6J4dtgdIPypBTfwxyXtZWy0nkM8jde6Jr7CqVVlECdf7wyGwN1Jhwf6PeihKn8peQKaXzVnMmLpcCmjNENnTRM5PmhEQkCGOOR4hMJkdfCONWmOtSoRlndhCQypBQM-fzl_-sDviXNjAYKvrYTUM-kwZZBqKyzdekqMnxxwnaKmF1uGVnrSjad_AfW0A9Vg9UpaqGvsbe8Doq15I7KE46kzd4y3fDoibDQG-qaYL8LYKcrVUDkTw_PNfiyihlcaGjBvHVaMBsYhJJlNnohktO0OES0WO0iUlj_M0PuOF7JxYsPAQZM5uZGPTRCQhen_8khQ8z70C2YYz965kCROL9-WC53Ezbt1R0QjHR4UupV3CtQfZe_BkTG8vYu7SMWbxDEGZKb6cRsTCgzqmd6l3f6OGojQA_EAvFJpL0kw0d_tfYnY4ZkyLdcI3G3fMyhicm7qmkiq7ZRdnGL2uCl-tpxsoLD7UbvVPD3CS_LNAp4&client_id=my-client-id-from-azure&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&grant_type=client_credentials
Response:回复:

I'm expecting an access token, instead, I get a 401 Unauthorized stating我期待一个访问令牌,相反,我得到一个401 Unauthorized声明

{
  "error": "invalid_client",
  "error_description": "AADSTS700027: Client assertion contains an invalid signature. [Reason - The key was not found., Thumbprint of key used by client: 'some-other-thumbprint', Please visit the Azure Portal, Graph Explorer or directly use MS Graph to see configured keys for app Id 'my-app-id'. Review the documentation at https://docs.microsoft.com/en-us/graph/deployments to determine the corresponding service endpoint and https://docs.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http to build a query request URL, such as 'https://graph.microsoft.com/beta/applications/my-app-id']\r\nTrace ID: some-uuid\r\nCorrelation ID: some-other-uuid\r\nTimestamp: 2021-07-07 12:25:46Z",
  "error_codes": [
    700027
  ],
  "timestamp": "2021-07-06 12:25:46Z",
  "trace_id": "some-uuid",
  "correlation_id": "some-other-uuid",
  "error_uri": "https://login.microsoftonline.com/error?code=700027"
}

I'm lost as to what the issue could be.我不知道问题可能是什么。

Question:问题:

What am I doing wrong?我究竟做错了什么?

So the issue came from the way the x5t header was being created.所以问题来自于创建x5t header 的方式。

I misunderstood the docs that clearly state the fingerprint as being a hex before encoding it base64 :在编码base64之前,我误解了在 state 指纹作为hex的文档: 来自文档的屏幕截图

With a fingerprint like this 204C837E10143C1428D7911CB60ED0075C3E1062 , the string needs to be treated as a HEX binary, not as a simple string.对于像这样的指纹204C837E10143C1428D7911CB60ED0075C3E1062 ,字符串需要被视为 HEX 二进制文件,而不是简单的字符串。

Example (PHP):示例(PHP):

PHPSandbox 笔记本

Pseudo code:伪代码:

// load certificate
certificate = load_file('/path/to/cert.pem')
// fingerprint is hex string 204C837E10143C1428D7911CB60ED0075C3E1062
certificate_fingerprint_hex_string = x509fingerprint($certificate)

// hexademical string is being converted to binary format
certificate_fingerprint_binary = hex_to_binary(certificate_fingerprint_hex_string)

// binary format gets base64 encoded (not base64url) to IEyDfhAUPBQo15Ectg7QB1w+EGI=
x5t = base64_encode(certificate_fingerprint_binary)

Request (Documentation)请求(文档)

在邮递员中运行

Method and headers Methodheaders

POST https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded; charset=UTF-8

Body (not yet formatted according to Content-Type)正文(尚未根据 Content-Type 格式化)

  • client_id : my-client-id-from-azure client_idmy-client-id-from-azure
  • client_assertion_type : urn:ietf:params:oauth:client-assertion-type:jwt- bearer client_assertion_type : urn:ietf:params:oauth:client-assertion-type:jwt- bearer
  • client_assertion : see below a JWT click here for details client_assertion见下面JWT 点击这里了解详情
  • grant_type : client_credentials grant_type : client_credentials
  • scope : https://graph.microsoft.com/.default scope : https://graph.microsoft.com/.default

client_assertion client_assertion

  • Header: ( x5t contains the base64 encoded certificate sha1 thumbprint from the uploaded certificate, see above picture) Header:( x5t包含上传证书的base64编码证书sha1指纹,见上图)

     { "typ": "JWT", "x5t": "IEyDfhAUPBQo15Ectg7QB1w+EGI=", "alg": "RS256" }
  • Payload:有效载荷:

     { "iss": "my-client-id-from-azure", "sub": "my-client-id-from-azure", "scope": "https://graph.microsoft.com/.default", "aud": "https://login.microsoftonline.com/my-tenant-id/oauth2/v2.0/token", "iat": 1625591612, "nbf": 1625591612, "exp": 1625595212, "jti": "some-dynamically-generated-uuid" }

Based on some search, here how I create the JWT token to request accessToken:根据一些搜索,这里我如何创建 JWT 令牌来请求 accessToken:

package required需要 package

composer required firebase/php-jwt ramsey/uuid guzzlehttp/guzzle

php code php 代码

<?php
use Firebase\JWT\JWT;
use Ramsey\Uuid\Uuid;

require_once (__DIR__.'/vendor/autoload.php');

$guzzle = new \GuzzleHttp\Client();
$authTenant = '';
$clientID = '';
$certPubFile = '';
$certPrivFile = '';

$url = 'https://login.microsoftonline.com/' . $authTenant . '/oauth2/v2.0/token';

$cert = openssl_x509_read(file_get_contents($certPubFile));
$sha1_hash = openssl_x509_fingerprint($cert); // sha1 hash (x5t parameter)
$jwt =  JWT::encode([
    'aud' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
    'exp' => (new DateTime())->add(new DateInterval('PT150S'))->format('U'),
    'nbf' => time() - 1,
    'iss' => clientID,
    'sub' => clientID,
    'jti' => Uuid::uuid4(),
],
file_get_contents($certPrivFile),
'RS256',
null,
[
    "alg" => "RS256",
    "typ" => "JWT",
    "x5t" => base64_encode(pack('H*', $sha1_hash)),
]
);
$authFormParameters = [
    'client_id' => clientID,
    'client_assertion_type' => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
    'client_assertion' => $jwt,
    'scope' => 'https://graph.microsoft.com/.default',
    'grant_type' => 'client_credentials',
];

$token = json_decode($guzzle->post($url, [
'form_params' => $authFormParameters,
])->getBody()->getContents());
$accessToken = $token->access_token;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用联合凭据而不是客户端密码或证书(应用程序用户)登录到 Microsoft Graph JavaScript SDK - Login to Microsoft Graph JavaScript SDK using federated credential instead of client secret or certificate (application user) 如何为 IdentityServer4 创建一个 client_secret? - How to create a client_secret for IdentityServer4? 自动获取Google API Client_ID和Client_Secret - Get Google API Client_ID and Client_Secret automatically 在Oauth2中哪里存储client_id和client_secret? - Where to store client_id and client_secret in Oauth2? 如何以编程方式生成gcloud项目oauth信任client_secret json文件 - How to generate gcloud project oauth creds client_secret json file programmatically Oauth2.0,将client_secret存储在本地存储是否安全 - Oauth2.0, Is it safe to store client_secret on a local storage Azure:将角色添加到应用注册的 client_secret - Azure : Add a role to a client_secret for an App Registrations 如何使用客户端密码通过 Powershell 访问 Azure WebApp - How to access Azure WebApp via Powershell using client secret Azure AD Graph API访问,不使用客户端ID和密钥 - Azure AD Graph API access without using client id and secret key 使用 MSAL 时,如何避免为 Blazor 服务器使用客户端密码或证书? - How do I avoid using a client secret or certificate for Blazor Server when using MSAL?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM