Office 365 Rest API - 守护程序周身份验证
Office 365 Rest API - Daemon week authentication
我正在尝试构建 Ruby 守护程序服务以访问 Office 365 rest API。最近可以通过 OAuth 'client_credentials' 流程执行此操作,详见此博客 post:https://docs.microsoft.com/en-us/archive/blogs/exchangedev/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow
我正在努力生成有效的访问令牌。令牌端点 returns 我是 JWT 但是在使用此令牌时我收到了 401 消息:
The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2
我知道 client_credentials 流程要求您出示 X.509 证书,不幸的是博客 post 中的所有示例都是针对 C# 的。
我在请求令牌时使用生成的自签名证书和私钥进行客户端断言。我按照博客 post 中的步骤生成证书并更新清单以使用此证书。
这是ruby代码供参考:
def request_token
uri = URI.parse("https://login.windows.net/== TENANT-ID ==/oauth2/token?api-version=1.0")
https = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.request_uri)
req.set_form_data(
:grant_type => 'client_credentials',
:redirect_uri => 'http://spready.dev',
:resource => 'https://outlook.office365.com/',
:client_id => '== Client ID ==',
:client_secret => '== Client secret =='
)
https.use_ssl = true
https.cert = client_cert
https.key = client_key
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
resp = https.start { |cx| cx.request(req) }
@access_token = JSON.parse(resp.body)
end
显然,为了安全起见,我删除了某些信息。尽管它是 ruby 你可以看到我正在使用我的证书来验证使用 SSL 连接的客户端。
以下是有关该错误的更多信息:
"x-ms-diagnostics" => "2000010;
reason=\"The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.\";
error_category=\"insufficient_auth_strength\"",
"x-diaginfo"=>"AM3PR01MB0662",
"x-beserver"=>"AM3PR01MB0662"
如有任何帮助,我们将不胜感激。
编辑
对于其他希望在 Ruby 中做类似事情的人,这里是我使用的代码的要点:https://gist.github.com/NGMarmaduke/a088943edbe4e703129d
该示例使用 Rails 环境,但去除 Rails 特定位应该相当容易。
记得用正确的值替换您的客户端 ID、TENANT_ID 和 CERT_THUMBPRINT,并将证书路径和客户端密钥方法指向正确的文件路径。
然后你可以这样做:
mailbox = OfficeAPI.new("nick@test.com")
messages = mailbox.request_messages
您的请求 body 中不需要 client_secret
,您需要 client_assertion
。这有点复杂,但这就是您需要该证书的原因。
基本上您需要构建一个 JSON Web 令牌并使用 SHA256 哈希使用您的证书对其进行签名。令牌看起来像这样:
Header:
{
"alg": "RS256",
"x5t": "..." // THUMBPRINT of Cert
}
有效负载:
{
"aud": "https:\/\/login.windows.net\/<The logged in user's tenant ID>\/oauth2\/token",
"exp": 1423168488,
"iss": "YOUR CLIENT ID",
"jti": "SOME GUID YOU ASSIGN",
"nbf": 1423167888,
"sub": "YOUR CLIENT ID"
}
如果您仍然同意我的意见,您现在需要(分别)对两部分进行 base64 编码,然后用“.”将它们连接起来。所以现在你应该有:
base64_header.base64_payload
现在您获取该字符串并使用您的证书使用 SHA256 哈希对其进行签名。然后对结果进行 base64 编码,url-encode,然后附加到字符串,所以现在你有:
base64_header.base64_payload.base64_signature
最后,将此作为 client_assertion
参数包含在您的 POST 到令牌端点中,并且还包含一个设置为 "urn:ietf:params:oauth:client-assertion-type:jwt-bearer":[=20 的 client_assertion_type
参数=]
req.set_form_data(
:grant_type => 'client_credentials',
:redirect_uri => 'http://spready.dev',
:resource => 'https://outlook.office365.com/',
:client_id => '== Client ID ==',
:client_assertion_type => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
:client_assertion => 'base64_header.base64_payload.base64_signature'
)
希望对您有所帮助!这都是基于我对 ADAL 是如何做到的研究,我还没有在 Ruby.
中亲自测试过。
只是一些补充:断言中的观众声明与您使用令牌请求处理的端点相同。正如 Jason 正确识别的那样,这是 AAD 的令牌端点:https://login.windows.net/{您想要应用程序令牌的租户}/oauth2/token。 nbf 和 exp 也是您在 unix 纪元时间中创建断言的时间,例如在 .net 中,你会做类似 "WebConvert.EpocTime(DateTime.UtcNow)" 的事情。对于 "not before" (nbf) 可能减去时钟偏差的缓冲区,例如5分钟;并为 (exp) 中的过期添加一些时间,例如15 分钟(因此断言在那段时间内仍然有效)。
这是令牌请求的 fiddler 跟踪(原始):
POSThttps://login.windows.net/0e49ef1f-ca07-45f1-b4c0-ac9409d3e576/oauth2/tokenHTTP/1.1
内容类型:application/x-www-form-urlencoded
客户端请求 ID:a8108f88-275b-424d-ac28-f675aabe548e
return-client-request-id: true
x 客户端 SKU:.NET
x-客户端版本:2.12.0.0
x-客户端-CPU: x64
x-客户端-OS:微软Windows NT 6.2.9200.0
主持人:login.windows.net
内容长度:983
期望:100-继续
连接:保持活动
resource=https%3A%2F%2Fgraph.windows.net%2F&client_id=f17bb8a5-2bef-4ad5-a83f-cd7113449fc2&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient -assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6ImY4S2JVY0xtMnItS2s4b1Z3ZVZYTFU0NzhJcyJ9.eyJhdWQiOiJodHRwczpcL1wvbG9naW4ud2luZG93cy5uZXRcLzBlNDllZjFmLWNhMDctNDVmMS1iNGMwLWFjOTQwOWQzZTU3Nlwvb2F1dGgyXC90b2tlbiIsImV4cCI6MTQyMjk4NDMzNSwiaXNzIjoiZjE3YmI4YTUtMmJlZi00YWQ1LWE4M2YtY2Q3MTEzNDQ5ZmMyIiwianRpIjoiZTI3OTA5YTctZGYwMC00NjBhLTlmZjctOGZkNDExOWVmNTYzIiwibmJmIjoxNDIyOTgzNzM1LCJzdWIiOiJmMTdiYjhhNS0yYmVmLTRhZDUtYTgzZi1jZDcxMTM0NDlmYzIifQ.g9bo4-lxpNJ4kEOMuQxODU-5iakwSVIzyRQEPLdbpuNn_XD4lcvt2yBIWT12EQaUVKkMyqFrDiIh4Oav565-Po7HfhmSPF3URXVj8Kx5lx17Zh0nWiaNkRXEi1vhwswsfjm1o-8B8LGUJTtT6JXTognrueuSL1aEE_-4qSG1y74aoc949Un1pQCjwuBtao4vs4CPJLu9Y9mVbirVRRtiIfxkUMmzf6yfMtuhugoGmrvUYntUo4x6N2fu4LxGjuIs7czyrMMAmDRo-XK4sAhDo5uof10HKb8ETEU8mhObwNZcz86MYHWbZm3Z_HDOwzC9kA_tp6hWqmlJ3c-gLg5VXA&grant_type=client_credentials
希望对您有所帮助!
祝你好运!
马蒂亚斯
我在 git 上的 HomeController 中添加了一个函数来演示如何使用客户端断言 w/o ADAL 手动请求访问令牌。使用此端口可能更容易:https://github.com/mattleib/o365api-as-apponly-webapp/commit/12d5b6dc66055625683020576139f5771e6059e1
我刚刚成功完成了这项工作,所以我想再提一条建议。那里的所有说明文章都说您应该将证书添加到清单文件中。我在这方面遇到了麻烦,但这是我所做的,最终让它发挥作用:
- 在 Azure 中,转到“设置”>“管理证书”
- 将 public 密钥作为
.cer
文件上传(google,如果您不知道如何转换它)。这应该是您的文本编辑器 barfs 的二进制文件。
现在已上传,Microsoft 将为您提供指纹。它在 "Thumbprint" 列中。 但是,它是十六进制的,不是base64。所以,像这样转换它:
# Hint: use your actual thumbprint, not this fake one
echo '5292850026FADB09700E7D6C1BCB1CD1F3270BCC' | xxd -r -p | base64
最后,使用这个 base64 编码的指纹作为 JSON header 中 x5t
的值。
我正在尝试构建 Ruby 守护程序服务以访问 Office 365 rest API。最近可以通过 OAuth 'client_credentials' 流程执行此操作,详见此博客 post:https://docs.microsoft.com/en-us/archive/blogs/exchangedev/building-daemon-or-service-apps-with-office-365-mail-calendar-and-contacts-apis-oauth2-client-credential-flow
我正在努力生成有效的访问令牌。令牌端点 returns 我是 JWT 但是在使用此令牌时我收到了 401 消息:
The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2
我知道 client_credentials 流程要求您出示 X.509 证书,不幸的是博客 post 中的所有示例都是针对 C# 的。
我在请求令牌时使用生成的自签名证书和私钥进行客户端断言。我按照博客 post 中的步骤生成证书并更新清单以使用此证书。
这是ruby代码供参考:
def request_token
uri = URI.parse("https://login.windows.net/== TENANT-ID ==/oauth2/token?api-version=1.0")
https = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.request_uri)
req.set_form_data(
:grant_type => 'client_credentials',
:redirect_uri => 'http://spready.dev',
:resource => 'https://outlook.office365.com/',
:client_id => '== Client ID ==',
:client_secret => '== Client secret =='
)
https.use_ssl = true
https.cert = client_cert
https.key = client_key
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
resp = https.start { |cx| cx.request(req) }
@access_token = JSON.parse(resp.body)
end
显然,为了安全起见,我删除了某些信息。尽管它是 ruby 你可以看到我正在使用我的证书来验证使用 SSL 连接的客户端。
以下是有关该错误的更多信息:
"x-ms-diagnostics" => "2000010;
reason=\"The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.\";
error_category=\"insufficient_auth_strength\"",
"x-diaginfo"=>"AM3PR01MB0662",
"x-beserver"=>"AM3PR01MB0662"
如有任何帮助,我们将不胜感激。
编辑
对于其他希望在 Ruby 中做类似事情的人,这里是我使用的代码的要点:https://gist.github.com/NGMarmaduke/a088943edbe4e703129d
该示例使用 Rails 环境,但去除 Rails 特定位应该相当容易。
记得用正确的值替换您的客户端 ID、TENANT_ID 和 CERT_THUMBPRINT,并将证书路径和客户端密钥方法指向正确的文件路径。
然后你可以这样做:
mailbox = OfficeAPI.new("nick@test.com")
messages = mailbox.request_messages
您的请求 body 中不需要 client_secret
,您需要 client_assertion
。这有点复杂,但这就是您需要该证书的原因。
基本上您需要构建一个 JSON Web 令牌并使用 SHA256 哈希使用您的证书对其进行签名。令牌看起来像这样:
Header:
{
"alg": "RS256",
"x5t": "..." // THUMBPRINT of Cert
}
有效负载:
{
"aud": "https:\/\/login.windows.net\/<The logged in user's tenant ID>\/oauth2\/token",
"exp": 1423168488,
"iss": "YOUR CLIENT ID",
"jti": "SOME GUID YOU ASSIGN",
"nbf": 1423167888,
"sub": "YOUR CLIENT ID"
}
如果您仍然同意我的意见,您现在需要(分别)对两部分进行 base64 编码,然后用“.”将它们连接起来。所以现在你应该有:
base64_header.base64_payload
现在您获取该字符串并使用您的证书使用 SHA256 哈希对其进行签名。然后对结果进行 base64 编码,url-encode,然后附加到字符串,所以现在你有:
base64_header.base64_payload.base64_signature
最后,将此作为 client_assertion
参数包含在您的 POST 到令牌端点中,并且还包含一个设置为 "urn:ietf:params:oauth:client-assertion-type:jwt-bearer":[=20 的 client_assertion_type
参数=]
req.set_form_data(
:grant_type => 'client_credentials',
:redirect_uri => 'http://spready.dev',
:resource => 'https://outlook.office365.com/',
:client_id => '== Client ID ==',
:client_assertion_type => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
:client_assertion => 'base64_header.base64_payload.base64_signature'
)
希望对您有所帮助!这都是基于我对 ADAL 是如何做到的研究,我还没有在 Ruby.
中亲自测试过。只是一些补充:断言中的观众声明与您使用令牌请求处理的端点相同。正如 Jason 正确识别的那样,这是 AAD 的令牌端点:https://login.windows.net/{您想要应用程序令牌的租户}/oauth2/token。 nbf 和 exp 也是您在 unix 纪元时间中创建断言的时间,例如在 .net 中,你会做类似 "WebConvert.EpocTime(DateTime.UtcNow)" 的事情。对于 "not before" (nbf) 可能减去时钟偏差的缓冲区,例如5分钟;并为 (exp) 中的过期添加一些时间,例如15 分钟(因此断言在那段时间内仍然有效)。
这是令牌请求的 fiddler 跟踪(原始): POSThttps://login.windows.net/0e49ef1f-ca07-45f1-b4c0-ac9409d3e576/oauth2/tokenHTTP/1.1 内容类型:application/x-www-form-urlencoded 客户端请求 ID:a8108f88-275b-424d-ac28-f675aabe548e return-client-request-id: true x 客户端 SKU:.NET x-客户端版本:2.12.0.0 x-客户端-CPU: x64 x-客户端-OS:微软Windows NT 6.2.9200.0 主持人:login.windows.net 内容长度:983 期望:100-继续 连接:保持活动
resource=https%3A%2F%2Fgraph.windows.net%2F&client_id=f17bb8a5-2bef-4ad5-a83f-cd7113449fc2&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient -assertion-type%3Ajwt-bearer&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6ImY4S2JVY0xtMnItS2s4b1Z3ZVZYTFU0NzhJcyJ9.eyJhdWQiOiJodHRwczpcL1wvbG9naW4ud2luZG93cy5uZXRcLzBlNDllZjFmLWNhMDctNDVmMS1iNGMwLWFjOTQwOWQzZTU3Nlwvb2F1dGgyXC90b2tlbiIsImV4cCI6MTQyMjk4NDMzNSwiaXNzIjoiZjE3YmI4YTUtMmJlZi00YWQ1LWE4M2YtY2Q3MTEzNDQ5ZmMyIiwianRpIjoiZTI3OTA5YTctZGYwMC00NjBhLTlmZjctOGZkNDExOWVmNTYzIiwibmJmIjoxNDIyOTgzNzM1LCJzdWIiOiJmMTdiYjhhNS0yYmVmLTRhZDUtYTgzZi1jZDcxMTM0NDlmYzIifQ.g9bo4-lxpNJ4kEOMuQxODU-5iakwSVIzyRQEPLdbpuNn_XD4lcvt2yBIWT12EQaUVKkMyqFrDiIh4Oav565-Po7HfhmSPF3URXVj8Kx5lx17Zh0nWiaNkRXEi1vhwswsfjm1o-8B8LGUJTtT6JXTognrueuSL1aEE_-4qSG1y74aoc949Un1pQCjwuBtao4vs4CPJLu9Y9mVbirVRRtiIfxkUMmzf6yfMtuhugoGmrvUYntUo4x6N2fu4LxGjuIs7czyrMMAmDRo-XK4sAhDo5uof10HKb8ETEU8mhObwNZcz86MYHWbZm3Z_HDOwzC9kA_tp6hWqmlJ3c-gLg5VXA&grant_type=client_credentials
希望对您有所帮助! 祝你好运!
马蒂亚斯
我在 git 上的 HomeController 中添加了一个函数来演示如何使用客户端断言 w/o ADAL 手动请求访问令牌。使用此端口可能更容易:https://github.com/mattleib/o365api-as-apponly-webapp/commit/12d5b6dc66055625683020576139f5771e6059e1
我刚刚成功完成了这项工作,所以我想再提一条建议。那里的所有说明文章都说您应该将证书添加到清单文件中。我在这方面遇到了麻烦,但这是我所做的,最终让它发挥作用:
- 在 Azure 中,转到“设置”>“管理证书”
- 将 public 密钥作为
.cer
文件上传(google,如果您不知道如何转换它)。这应该是您的文本编辑器 barfs 的二进制文件。 现在已上传,Microsoft 将为您提供指纹。它在 "Thumbprint" 列中。 但是,它是十六进制的,不是base64。所以,像这样转换它:
# Hint: use your actual thumbprint, not this fake one echo '5292850026FADB09700E7D6C1BCB1CD1F3270BCC' | xxd -r -p | base64
最后,使用这个 base64 编码的指纹作为 JSON header 中
x5t
的值。