导出 (0) 打印
全部展开
展开 最小化

操作方法:通过 OAuth WRAP 协议从 ACS 请求令牌

更新时间: 2015年3月

  • Microsoft Azure Active Directory 访问控制(也称为访问控制服务或 ACS)

当 Web 应用程序和服务使用 ACS 处理身份验证时,客户端必须获取 ACS 颁发的安全令牌以登录到你的应用程序或服务。为了获取 ACS 颁发的这个令牌(输出令牌),客户端必须直接在 ACS 上进行身份验证,或者向 ACS 发送其标识提供程序颁发的安全令牌(输入令牌)。ACS 将验证此输入安全令牌,通过 ACS 规则引擎处理此令牌中的标识声明,计算输出标识声明,然后颁发输出安全令牌。

本主题介绍通过 OAuth WRAP 协议从 ACS 请求令牌的方法。通过 OAuth WRAP 协议发出的所有令牌请求将通过 SSL 传输。ACS 始终通过 OAuth WRAP 协议颁发简单 Web 令牌 (SWT),以响应格式正确的令牌请求。通过 OAuth WRAP 协议发出的所有令牌请求将以 HTTP POST 发送到 ACS。你可以在发出 HTTPS FORM POST 请求的任何平台中通过 OAuth WRAP 协议请求 ACS 令牌:.NET framework、Windows Communication Foundation (WCF)、Silverlight、ASP.NET、Java、Python、Ruby、PHP、Flash 和其他平台。

下表列出了通过 OAuth WRAP 协议请求 ACS 颁发的 SWT 令牌的三种受支持方法。

通过 OAuth WRAP 协议从 ACS 请求令牌的三种方法

令牌请求方法 说明

密码令牌请求

这是最简单的方法,它要求客户端通过 OAuth WRAP 协议直接向 ACS 发送服务标识的用户名和密码以进行身份验证。

SWT 令牌请求

此方法要求客户端通过 OAuth WRAP 协议将可以使用服务标识对称密钥或标识提供程序对称密钥签名的 SWT 令牌发送到 ACS 以进行身份验证。

SAML 令牌请求

主要适用于 Active Directory 联合身份验证服务 (AD FS) 2.0 集成,安全断言标记语言 (SAML) 方法要求客户端通过 OAuth WRAP 协议将签名的 SAML 令牌发送到 ACS 以进行身份验证。这种方法允许客户端使用企业标识在 ACS 上进行身份验证。

通过 OAuth WRAP 协议发出的所有 ACS 令牌请求将定向到 ACS 令牌颁发终结点。此终结点的 URI 取决于 “访问控制”命名空间。命名空间在令牌请求 URI 中显示为 DNS 名称前缀。与路径一样,DNS 名称的剩余部分是固定的。例如,如果你要从名为“mysnservice”的 “访问控制”命名空间请求令牌,可以将令牌请求定向到以下 URI:https://mysnservice.accesscontrol.windows.net/WRAPv0.9。

对于密码令牌请求,客户端可以通过 OAuth WRAP 协议将用户名和密码从服务标识直接发送到 ACS 以进行身份验证。这是使用 OAuth WRAP 协议从 ACS 请求令牌的最简单方法。除了建立 SSL 连接以外,此方法不需要任何加密功能。在实践中,这类似于 REST Web 服务中常见的用户名/密码模型。这种类型的令牌请求实际上是 HTTPS 格式的 POST。密码令牌请求中的参数已经过格式编码。

以下是向名为“mysnservice”的命名空间发出的纯文本请求线路跟踪示例。

POST /WRAPv0.9/ HTTP/1.1
Host: mysnservice.accesscontrol.windows.net
Content-Type: application/x-www-form-urlencoded

wrap_scope=http%3A%2F%2Fmysnservice.com%2Fservices%2F&
wrap_name=mysncustomer1&
wrap_password=5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ%3D

下表提供了要在密码令牌请求中提供的参数的名称、说明和值要求:

 

参数名称 说明 值要求

wrap_scope

根据一组规则匹配令牌请求。请将此参数的值设置为信赖方应用程序领域的值。你可以在 ACS 管理门户中,从“信赖方应用程序”页中选择相应的信赖方应用程序来获取此值(在“领域”字段中)。

  • HTTP 或 HTTP(s) URI

  • 无查询参数或定位点。

  • 路径段 <= 32。

  • 最大长度:256 个字符。

  • 必须采用 URL 编码。

wrap_name

验证下一参数的键。请将此参数的值设置为 “访问控制”命名空间中的服务标识的名称。你可以在 ACS 管理门户中,从“服务标识”页中选择相应的服务标识来获取此值(在“名称”字段中)。

  • 最小长度:1 个字符。

  • 最大长度:128 个字符。

  • 必须采用 URL 编码。

wrap_password

对传入的请求进行身份验证。请将此参数的值设置为 “访问控制”命名空间中的服务标识的密码。可以通过 ACS 管理门户获取此值,方法是先在“服务标识”页上选择相应的服务标识,然后在“编辑服务标识”页上的“凭据”表中选择相应的密码(在“编辑凭据”页上的“密码”字段中)。

  • 字符串,最小和最大长度分别为 1 和 64 个字符。

  • 必须采用 URL 编码。

在将请求发送到 ACS 之前,必须对这些参数的值进行 URL 编码。Web 应用程序或服务可以向客户端提供 wrap_scope 的值,或者,客户端可以决定将 wrap_scope 参数的值设置为 Web 应用程序或服务资源目标的 URI。

通过 OAuth WRAP 协议发出的密码令牌请求还可以包含 ACS 在处理输出声明计算时使用的附加参数。这些附加参数的名称和值必须采用 URL 编码,并且值必须用引号括住。

使用 执行的密码令牌请求方法相当直接。

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", "mysncustomer1");
values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
values.Add("wrap_scope", "http://mysnservice.com/services");

// WebClient takes care of the URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

有关如何解包 ACS 提供的输出令牌,以及如何将其发送到 Web 应用程序或服务的信息,请参阅Unwrapping and sending the token to a web application or service

你也可以使用由对称密钥签名的 SWT 令牌,通过 OAuth WRAP 协议从 ACS 请求令牌。所有 SWT 令牌请求都将通过 HTTPS 格式的 POST 发出。此令牌请求方法中的参数值已经过格式编码。

以下是向“mysnservice”命名空间发出的 SWT 令牌请求线路跟踪示例。

POST /WRAPv0.9/ HTTP/1.1
Host: mysnservice.accesscontrol.windows.net
Content-Type: application/x-www-form-urlencoded

wrap_scope=http%3A%2F%2Fmysnservice.com%2Fservices%2F&
wrap_assertion_format=SWT&
wrap_assertion=Issuer%3dmysncustomer1%26HMACSHA256%3db%252f%252bJFwbngGdufECFjQb8qhb9YH0e32Cf9ABMDZFiPPA%253d

SWT 令牌请求必须具有以下参数和值:

 

参数名称 说明 值要求

wrap_scope

根据一组规则匹配令牌请求。

  • 请将此参数的值设置为信赖方应用程序领域的值。你可以在 ACS 管理门户中,从“信赖方应用程序”页中选择相应的信赖方应用程序来获取此值(在“领域”字段中)。

  • HTTP 或 HTTP(s) URI。

  • 无查询参数或定位点。

  • 路径段 <= 32。

  • 最大长度:256 个字符。

  • 必须采用 URL 编码。

wrap_assertion

这是发送到 ACS 的输入令牌。

  • 具有包含颁发者和 HMACSHA256 参数的输入声明的已签名 SWT 令牌。

  • 最大长度:2048 个字符。

  • 必须采用 URL 编码。

wrap_assertion_format

这是发送到 ACS 的输入令牌的格式。

SWT

如下面的示例中所示,发出 SWT 令牌请求所需的代码类似于发出密码令牌请求所需的代码。

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
// add the wrap_scope
values.Add("wrap_scope", "http://mysnservice.com/services");
// add the format
values.Add("wrap_assertion_format", "SWT");
// add the SWT
values.Add("wrap_assertion", "Issuer=mysncustomer1&HMACSHA256=b%2f%2bJFwbngGdufECFjQb8qhb9YH0e32Cf9ABMDZFiPPA%3d");
// WebClient takes care of the remaining URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

有关如何解包 ACS 提供的响应,以及如何将其发送到 Web 应用程序或服务的信息,请参阅Unwrapping and sending the token to a web application or service

SWT 令牌是使用颁发者密钥(对称密钥)签名的一组键/值对。在 SWT 令牌请求中发送到 ACS 的 SWT 令牌必须包含 IssuerHMACSHA256 参数以及附加参数,例如,ExpiresOnAudience 和其他特定于客户端的声明。下表提供了 SWT 令牌参数的名称和说明:

 

参数名称 说明

Issuer

在 ACS 中,查找用于令牌签名的密钥。如果该签名有效,则此值将用于执行输出声明计算。

可以将此参数设置为 “访问控制”命名空间中某个标识提供程序的领域值,或者 “访问控制”命名空间中某个服务标识的名称。你可以在 ACS 管理门户中,从“标识提供程序”页中选择相应的标识提供程序来获取此值(在“编辑标识提供程序”页上的“领域”字段中)。或者,可以通过 ACS 管理服务获取此值 – 这是为每个标识提供程序创建的“颁发者”记录的属性名称。

HMACSHA256

在 ACS 中,验证 SWT 签名并查找 Issuer 参数中命名的颁发者密钥。

SWT 签名是使用附加到 “访问控制”命名空间中的服务标识或标识提供程序的对称签名密钥创建的。

读者

如果存在,,ACS 将使用此值来确保 ACS 是 SWT 令牌的预期目标。这是 “访问控制”命名空间的 URL,例如,https://contoso.accesscontrol.windows.net/

ExpiresOn

如果存在(采用 Epoch 时间),则指示令牌是否已过期。例如,此参数的值可以是 1324300962

附加声明

如果存在,ACS 将使用这些参数执行输出声明计算。每个声明类型只能出现一次。同一声明类型的多个声明值必须与以“,”(逗号)字符连接在一起。有关在 ACS 中断言声明的详细信息,请参阅通过 OAuth WRAP 协议声明断言

下面的代码示例演示了如何使用 生成 SWT 令牌。它包含一个类型,该类型生成包含 IssuerHMACSHA256 参数的 SWT 令牌。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

public class TokenFactory
{
    string signingKey;   
    string issuer;
    
    public TokenFactory(string issuer, string signingKey)
    {
        this.issuer = issuer;
        this.signingKey = signingKey;
    }

    public string CreateToken()
    {
        StringBuilder builder = new StringBuilder();

        // add the issuer name
        builder.Append("Issuer=");
        builder.Append(HttpUtility.UrlEncode(this.issuer));

        string signature = this.GenerateSignature(builder.ToString(), this.signingKey);
        builder.Append("&HMACSHA256=");
        builder.Append(signature);

        return builder.ToString();
    }

   
    private string GenerateSignature(string unsignedToken, string signingKey)
    {
        HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(signingKey));

        byte[] locallyGeneratedSignatureInBytes = hmac.ComputeHash(Encoding.ASCII.GetBytes(unsignedToken));

        string locallyGeneratedSignature = HttpUtility.UrlEncode(Convert.ToBase64String(locallyGeneratedSignatureInBytes));

        return locallyGeneratedSignature;
    }
}

SAML 令牌请求方法主要适用于 AD FS 2.0 集成,它允许客户端使用企业标识 (Active Directory) 在 ACS 上进行身份验证。通过 SAML 令牌请求方法,你可以通过 OAuth WRAP 协议将 AD FS 2.0 颁发的已签名 SAML 1.1 或 SAML 2.0 令牌(输入令牌)发送到 ACS。

ACS 使用其规则来计算输出声明,将声明分组到 SWT 令牌(输出令牌)中,对其进行签名,然后通过 OAuth WRAP 协议将其返回到客户端。

SAML 令牌请求必须具有以下参数和值:

 

参数名称 说明 值要求

wrap_scope

根据一组规则匹配令牌请求。

  • 请将此参数的值设置为信赖方应用程序领域的值。你可以在 ACS 管理门户中,从“信赖方应用程序”页中选择相应的信赖方应用程序来获取此值(在“领域”字段中)。

  • HTTP 或 HTTP(s) URI。

  • 无查询参数或定位点。

  • 路径段 <= 32。

  • 最大长度:256 个字符。

  • 必须采用 URL 编码。

wrap_assertion

这是发送到 ACS 的输入令牌。

  • 具有输入声明的已签名 SAML 1.1 或 2.0 令牌。作为令牌限制,SAML 1.1 令牌至少需要一个输入声明。这意味着,必须将标识提供程序或启用声明的服务标识用于 SAML 1.1 令牌身份验证。SAML 2.0 令牌不需要使用任何输入声明(隐式 NameIdentifier 声明除外)针对服务标识进行身份验证,因此可以使用 SAML 2.0 令牌针对未启用声明的普通服务标识进行身份验证。

  • 必须采用 URL 编码。

wrap_assertion_format

这是发送到 ACS 的输入令牌的格式。

SAML

以下是发出 SAML 令牌请求所需的代码示例。

private static string SendSAMLTokenToACS(string samlToken)
{
 try
 {
  WebClient client = new WebClient();
  client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");
  NameValueCollection parameters = new NameValueCollection();
  parameters.Add("wrap_assertion_format", "SAML");
  parameters.Add("wrap_assertion", samlToken);
  parameters.Add("wrap_scope", "http://mysnservice.com/services");

  byte[] responseBytes = client.UploadValues("WRAPv0.9", parameters);
  string response = Encoding.UTF8.GetString(responseBytes);

  return response
   .Split('&')
   .Single(value => value.StartsWith("wrap_access_token=", StringComparison.OrdinalIgnoreCase))
   .Split('=')[1];
 }
 catch (WebException wex)
 {
  string value = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
  throw;
 }
}  

有关如何解包 ACS 提供的响应,以及如何将其发送到 Web 应用程序或服务的信息,请参阅解包令牌并将其发送到 Web 应用程序或服务

为了实现与 ACS 1.0 令牌请求行为的向后兼容,ACS 支持在发出令牌请求过程中断言声明的功能。

执行此操作的建议方法是将断言应用程序或服务注册为 ACS 标识提供程序。然后,应用程序或服务将通过提供包含它想要断言的声明的 SAML 或 SWT 令牌从 ACS 请求令牌,此令牌将使用 ACS 中存储的标识提供程序密钥进行加密。例如,可以通过 OAuth WRAP 协议将包含断言声明的 SAML 令牌请求从使用 Windows Identity Foundation (WIF) 构建的、已在 ACS 中注册为 WS 联合身份验证标识提供程序的 AD FS 2.0 或任何自定义安全令牌服务 (STS) 发送到 ACS。

可以在 ACS 管理门户中使用 WS 联合身份验证元数据注册标识提供程序,或者使用 ACS 管理服务分别设置标识提供程序属性、地址和密钥。(有关示例,请参阅操作方法:使用 ACS 管理服务将 AD FS 2.0 配置为企业标识提供程序。)这种在令牌请求中断言声明的方法不需要服务标识。此方法通过 ACS 支持的所有协议执行。

如果对令牌请求成功进行身份验证,ACS 将返回两个格式编码的参数:wrap_tokenwrap_token_expires_in。这些参数的值分别是客户端可用来访问 Web 应用程序或服务的实际 SWT 令牌,以及此令牌的近似剩余生存期(以秒为单位)。

将 SWT 令牌发送到 Web 应用程序或服务之前,客户端必须从 ACS 响应中提取该令牌并对其进行 URL 解码。如果 Web 应用程序或服务要求在 HTTP Authorization 标头中提供令牌,该令牌的前面必须带有方案 WRAPv0.9

下面的代码示例演示了如何解包令牌和设置 Authorization 标头的格式。

WebClient client = new WebClient();
client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

NameValueCollection values = new NameValueCollection();
values.Add("wrap_name", "mysncustomer1");
values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
values.Add("wrap_scope", "http://mysnservice.com/services");

// WebClient takes care of the URL Encoding
byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

// the raw response from ACS
string response = Encoding.UTF8.GetString(responseBytes);

string token = response
    .Split('&')
    .Single(value => value.StartsWith("wrap_token=", StringComparison.OrdinalIgnoreCase))
    .Split('=')[1];

string.Format("WRAP access_token=\"{0}\"", HttpUtility.UrlDecode(token));

当无法满足令牌请求时,ACS 将返回错误。错误中包含与 REST 设计相一致的 HTTP 响应代码。在许多情况下,ACS 错误中还包含提供有关失败项的上下文的 SubCodeDetail。错误格式为:Error:Code:<httpStatus>:Sub-Code:<code>:Detail:<message>。错误的 Content-Type 始终是 text/plain。

HTTP/1.1 401 Access Forbidden
Content-Type: text/plain; charset=us-ascii

Error:Code:401:SubCode:T0:Detail:ACS50009: SWT token is invalid. :TraceID:<trace id value>:TimeStamp:<timestamp value>

有关 ACS 错误代码的详细信息,请参阅 ACS 错误代码

在调试 ACS 返回的错误或者从中恢复时,通常需要读取响应正文。下面的代码示例演示了如何读取来自 WebException 对象的错误消息。

try
{
    WebClient client = new WebClient();
    client.BaseAddress = string.Format("https://mysnservice.accesscontrol.windows.net");

    NameValueCollection values = new NameValueCollection();
    values.Add("wrap_name", "mysncustomer1");
    values.Add("wrap_password", "5znwNTZDYC39dqhFOTDtnaikd1hiuRa4XaAj3Y9kJhQ=");
    values.Add("wrap_scope", "http://mysnservice.com/services");

    // WebClient takes care of the URL Encoding
    byte[] responseBytes = client.UploadValues("WRAPv0.9", "POST", values);

    // the raw response from ACS
    string response = Encoding.UTF8.GetString(responseBytes);

    string token = response
        .Split('&')
        .Single(value => value.StartsWith("wrap_access_token=",       StringComparison.OrdinalIgnoreCase))
        .Split('=')[1];
}
catch (WebException wex)
{
    if (wex.Response != null)
    {
        // the response Stream contains the error message
        StreamReader reader = new StreamReader(wex.Response.GetResponseStream());
        string message = reader.ReadToEnd();
    }
    // Throw as appropriate
}

另请参阅

社区附加资源

添加
显示:
© 2015 Microsoft