1

目前,我正在使用 OpenID(通过 C# 和 DotNetOpenAuth)在 App A(“他们的应用”)和 App B(“我的应用”)之间创建单点登录功能。

我希望利用属性交换来获取他们的应用程序提供的数据。他们的 API 记录了 AX 请求的外观:

openid.ns.ax              = http://openid.net/srv/ax/1.0
openid.ax.type.studentids = http://theirapp.com/path/student-ids

请注意 .ax 命名空间。这似乎符合 OpenID 的 AX 规范。

这就是我使用 DotNetOpenAuth 请求和获取属性的方式,正如 SO和大量其他来源所建议的那样:

FetchRequest ax = new FetchRequest();
ax.Attributes.AddRequired("http://theirapp.com/path/student-ids");
request.AddExtension(ax);

string sIDs = String.Empty;
if (fetch != null)
    sIDs = fetch.GetAttributeValue("http://theirapp.com/path/student-ids");

当回复完全无视 AX 请求时,我感到很困惑。在观察了我们发送的查询字符串参数之后,我认为这实际上不是他们的错:

openid.ns:http://specs.openid.net/auth/2.0
openid.ns.alias3:http://openid.net/srv/ax/1.0
openid.alias3.required:alias1
openid.alias3.mode:fetch_request
openid.alias3.type.alias1:http://theirapp.com/path/student-ids
openid.alias3.count.alias1:1

什么鬼,DotNetOpenAuth?“alias3”是从哪里来的?这应该是“斧头”。我无法判断我正在使用的应用程序是否对 AX 命名空间过于敏感,或者 DotNetOpenAuth 没有关注强制性 OpenID 协议。

所以,在所有这些积累之后,我的问题是:

  1. 我需要我的 AX 请求位于命名空间 openid.ax 中,而不是 openid.alias3。我如何强制 DotNetOpenAuth 这样做?
  2. API 要求将请求的属性命名为 - 在本例中为“student-ids”。上面,他们得到了像“alias1”这样的默认名称。如何强制 DotNetOpenAuth 使用自定义名称标记属性?
  3. 谁在这里:要求 openid.ax 或 DotNetOpenAuth 不关心的 API?
4

2 回答 2

2

问题一:

我需要我的 AX 请求位于命名空间 openid.ax 中,而不是 openid.alias3。我如何强制 DotNetOpenAuth 这样做?

DotNetOpenAuth 不允许您强制使用特定扩展名的别名。要求一个特定的是违反 OpenID 2.0 规范的。甚至AX 扩展本身也在 1.1 节中说明了这一点

openid.ns.<extension_alias>=http://openid.net/srv/ax/1.0

实际的扩展命名空间别名应该由组成消息的一方根据每个消息确定,以避免多个扩展之间的冲突。就本文档而言,属性交换服务的扩展命名空间别名将是“ax”。

问题2:

API 要求将请求的属性命名为 - 在本例中为“student-ids”。上面,他们得到了像“alias1”这样的默认名称。如何强制 DotNetOpenAuth 使用自定义名称标记属性?

就像您的第一个问题一样,DotNetOpenAuth 没有为您提供强制单个属性别名的方法,因为 AX 扩展不允许这些类型的要求。属性的类型在 URI 中给出。该属性的别名由依赖方定义,并且 OpenID 提供者应该查看属性的类型 URI,并接受来自依赖方的任何别名。

问题 3:

谁在这里:要求 openid.ax 或 DotNetOpenAuth 不关心的 API?

DotNetOpenAuth 是正确的。如果您正在查看此学生 ID 交换的文档之间的别名差异确实与 DotNetOpenAuth 是您在忽略 AX 属性时看到的问题的根本原因,那么错误在于执行不善在服务器上运行的 OpenID 提供程序。OpenID Providers 的糟糕实现非常可怕——不仅因为互操作性差,而且因为它们表明可能存在许多可能的安全问题,以及在正确实施规范时缺乏注意。

我建议您尝试使用 Fiddler 或其他一些 HTTP 嗅探器来拦截出站请求,修复所有别名以匹配文档建议的内容,并查看它是否解决了问题。如果是这样,应该修复 OpenID 提供程序,您可以联系他们以请求他们升级到他们正在使用的任何库的更新版本(希望仅此一项就可以修复它)。如果“修复”别名不能解决问题,那么您可以继续调查互操作失败的其他可能原因。

于 2012-10-25T06:03:13.290 回答
1

谢谢垃圾邮件。我想出了一个解决此问题的技巧,并将其发布在这里,以供其他可能遇到与 PowerSchool 的 OpenID 提供程序限制相同的问题的人使用。

您需要使用 DotNetOpenAuth 正常构建请求,然后从请求中提取重定向响应。一旦你有了这个,你可以拉出 Location 头并根据需要覆盖命名空间值。

此示例适用于 MVC 应用程序。如果您需要在 WebForms 应用程序中执行此操作,只需从方法中获取逻辑并将该行替换return redirectResponse.AsActionResult();redirectResponse.Send(). 对于 ThreadAbortExceptions,您需要将其包装在通常的 try...catch... 中。

使用的命名空间:

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.RelyingParty;

黑客:

const string NS_DCID = "http://powerschool.com/entity/id";
const string NS_USERTYPE = "http://powerschool.com/entity/type";

static readonly OpenIdRelyingParty openid = new OpenIdRelyingParty();

private ActionResult SubmitOpenIdRequest(string openid_identifier)
{
    var request = openid.CreateRequest(openid_identifier);

    var ax = new FetchRequest();

    // any modification to the following attributes will require a corresponding change in the string replacement hack
    ax.Attributes.AddRequired(NS_DCID);
    ax.Attributes.AddRequired(NS_USERTYPE);

    request.AddExtension(ax);

    var redirectResponse = request.RedirectingResponse;

    // PowerSchool is violating the attribute exchange specification, requiring specific namespaces and elements to function
    // Need to overwrite the values generated by OpenID to patch PowerSchool's incorrect provider implementation
    redirectResponse.Headers["Location"] = redirectResponse.Headers["Location"]
        .Replace("openid.ns.alias3", "openid.ns.ax")
        .Replace("openid.alias3.required=dcid%2Calias2", "openid.ax.required=dcid%2Cusertype")
        .Replace("openid.alias3.mode", "openid.ax.mode")
        .Replace("openid.alias3.type.alias1", "openid.ax.type.dcid")
        .Replace("openid.alias3.count.alias1", "openid.ax.count.dcid")
        .Replace("openid.alias3.type.alias2", "openid.ax.type.usertype")
        .Replace("openid.alias3.count.alias2", "openid.ax.count.usertype");

    return redirectResponse.AsActionResult();
}

请注意:这是一个脆弱的 hack。DNOA 的内部更改或 FetchRequest 的更改可能会破坏替换逻辑。

于 2013-02-08T18:02:28.623 回答