OpenIdProvider.GetRequest()返回null

作为这个问题的延续,我遇到了dotnetopenauth的问题。

我导航到我的依赖方代码并创建请求,但是当我的提供者收到请求时, OpenIdProvider.GetRequest()返回null。 我查看了代码,据我所知,这是因为我的依赖方没有交付openid有效负载(request.form); 但我无法弄清楚为什么会这样。

码:

依赖方:

 public ActionResult Authenticate(string RuserName = "") { UriBuilder returnToBuilder = new UriBuilder(Request.Url); returnToBuilder.Path = "/OpenId/Authenticate"; returnToBuilder.Query = null; returnToBuilder.Fragment = null; Uri returnTo = returnToBuilder.Uri; returnToBuilder.Path = "/"; Realm realm = returnToBuilder.Uri; var response = openid.GetResponse(); if (response == null) { if (Request.QueryString["ReturnUrl"] != null && User.Identity.IsAuthenticated) { } else { string strIdentifier = "http://localhost:3314/User/Identity/" + RuserName; var request = openid.CreateRequest( strIdentifier, realm, returnTo); var fetchRequest = new FetchRequest(); request.AddExtension(fetchRequest); request.RedirectToProvider(); } } else { switch (response.Status) { case AuthenticationStatus.Canceled: break; case AuthenticationStatus.Failed: break; case AuthenticationStatus.Authenticated: //log the user in break; } } return new EmptyResult(); 

}

提供者:

 public ActionResult Index() { IRequest request = OpenIdProvider.GetRequest(); if (request != null) { if (request.IsResponseReady) { return OpenIdProvider.PrepareResponse(request).AsActionResult(); } ProviderEndpoint.PendingRequest = (IHostProcessedRequest)request; return this.ProcessAuthRequest(); } else { //user stumbled on openid endpoint - 404 maybe? return new EmptyResult(); } } public ActionResult ProcessAuthRequest() { if (ProviderEndpoint.PendingRequest == null) { //there is no pending request return new EmptyResult(); } ActionResult response; if (this.AutoRespondIfPossible(out response)) { return response; } if (ProviderEndpoint.PendingRequest.Immediate) { return this.SendAssertion(); } return new EmptyResult(); } 

日志:

RP:1) http://pastebin.com/Pnih3ND7 2) http://pastebin.com/eBzGun9y

提供者: http : //pastebin.com/YAUTBzHk

有趣的是,RP日志说localhost是不受信任的……但是我把它添加到我的web.config中列入白名单的主机上,它昨天“工作”了……

编辑:好的,这很奇怪。 昨天我正在试图找出问题所在的DNOA来源。 我启用了log4net,它创建了日志文件并将其留空。 今天我再次设置log4net – 它记录正常,但我有一个没有意义的错误(见上文)。 我也无法进入DNOA源。 我删除并重新添加了对dotnetopenauth.dll的引用,然后我与白名单主机的“原始错误”消失了,我能够进入源代码,但日志文件再次为空。 我仍然遇到request.form没有被填充的问题…

EDIT2 :我的控制器都命名为“OpenIdController”(RP和EP都有)。 我的RP在localhost:1903上运行,我的端点在localhost:3314上运行。


编辑3 :我做了更改后,你建议事情开始工作。 RP执行发现很好,但实际发出请求时我遇到了问题。

IRequest i_request = OpenIdProvider.GetRequest(); 工作正常,但是当我尝试投射它时: IAuthenticationRequest iR = (IAuthenticationRequest)i_request; 它给了我以下错误:

  System.InvalidCastException was unhandled by user code Message=Unable to cast object of type 'DotNetOpenAuth.OpenId.Provider.AutoResponsiveRequest' to type 'DotNetOpenAuth.OpenId.Provider.IAuthenticationRequest'. Source=Portal StackTrace: at Portal.Controllers.OpenIdController.Index() in Controllers\OpendIdController.cs:line 35 at lambda_method(Closure , ControllerBase , Object[] ) at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) at System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass42.b__41() at System.Web.Mvc.Async.AsyncResultWrapper.c__DisplayClass8`1.b__7(IAsyncResult _) at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End() at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass37.c__DisplayClass39.b__33() at System.Web.Mvc.Async.AsyncControllerActionInvoker.c__DisplayClass4f.b__49() 

这个代码在我发现相关的两个样本之间有点混乱。 我想设置一个SSO类型的环境,因此我使用的大部分代码来自\DotNetOpenAuth-4.1.0.12182\Samples\OpenIdWebRingSsoProvider\Code\Util.cs (ProcessAuthenticationChallenge函数)。 但是,由于该函数需要IAuthenticationRequest但OpenIdProvider.GetRequest返回AutoResponsiveRequest我认为我能够使用它来使用IAuthenticationRequest类的属性和方法。 显然我不对。

我不太确定如何处理这方面的事情。 我应该使用OpenIdProviderMVC样本中的示例代码吗? 关键是登录工作就像单点登录一样,用户实际上从未被提示进入OpenId。 我也只会有一个端点(虽然我会有多个RP)。

这是最新RP日志的链接: http : //pastebin.com/enpwYqq3


编辑4 :我做了你的建议,并取得了一些进展。 据我所知,我的EP接收到响应并处理它,但是当它重定向回到域url时它会出错。

012-10-10 13:55:01,171 (GMT-4) [25] ERROR DotNetOpenAuth.Messaging - Protocol error: An HTTP request to the realm URL (http://localhost:1903/) resulted in a redirect, which is not allowed during relying party discovery.

Realm的function究竟与ReturnTo相反? 使用示例代码,Realm最终成为http://localhost:1903/并且ReturnTo最终为http://localhost:1903/OpenId/Authenticate ,这看起来很好。 为什么EP需要向领域提出请求? 我原以为它应该只是在完成处理后将断言发送到returnTo。 如果我手动将Realm设置为http://localhost:1903/OpenId/AuthenticaterelyingParty.GetResponse()将返回null。

当有人访问基本URL时,我确实将我的应用程序设置为重定向( http://localhost:1903 ) – 我应该在那里运行什么代码来拦截DNOA EP请求?

新日志:

RP: http : //pastebin.com/L9K5Yft4

EP: http : //pastebin.com/kBPWiUxp

我还在问题开头更新了代码,以更好地反映我所做的更改。


EDIT5 :领域必须是应用程序的实际基本URL吗? 也就是说,( http://localhost:1903 )? 鉴于现有的体系结构,很难删除重定向 – 我尝试将域设置为基础OpenId控制器( http://localhost:1903/OpenId ),并且手动测试确实生成了XRDS文档。 但是,应用程序似乎冻结,EP日志显示以下错误:

2012-10-10 15:17:46,000 (GMT-4) [24] ERROR DotNetOpenAuth.OpenId - Attribute Exchange extension did not provide any aliases in the if_available or required lists.

你的RP有非常可疑的奇怪代码。 虽然return_to和realm都具有相同的Uri权限是正常的(实际上是必需的),但是作为OpenIdRelyingParty.CreateRequest的第一个参数传入的用户提供的标识符具有相同的主机和端口因为你的依赖方奇怪。 通常,您传入的标识符将是提供者托管的URL。 现在,我不知道端口3314是你的RP还是OP,但无论如何,RP代码中的其中一个端口号看起来是错误的。

其次,对用户标识符的发现失败,并带有空引用exception(根据RP日志的v2)。 这样可以防止登录请求到达您的提供商。 您的Provider 调用但存在不存在的OpenID请求这一事实表明http://localhost:3314/OpenId/实际上是您的OP端点(您的OpenID提供程序的操作方法的URL读取Op​​enID请求)。 这是不合适的。 您应该传递给OpenIdRelyingParty.CreateRequest方法的第一个参数的URL应该是用户的OpenID URL – 而不是OP端点。 查看OpenIdProviderMvc示例的用户控制器,以获取有关如何设置用户OpenID URL的示例。 然后使用 URL作为CreateRequest的第一个arg,我认为你会很好。

第三,一旦您的Provider收到非null请求,您就不能总是将其IAuthenticationRequestIAuthenticationRequest 。 并非所有OpenID消息都是认证消息。 有些是底层OpenID协议的一部分。 如果查看OpenIdProviderMvc示例的OpenID控制器,您应该注意到有条件转换来处理不同的消息类型。 您应该在控制器中有类似的消息处理。

由于您要使用SSO方案,因此控制器的显着差异可能是:

  1. 你的控制器永远不会通过重定向到登录页面来响应,而是“神奇地”指出用户是谁。
  2. 您的控制器应针对SSO Web环中包含的RP的白名单检查IAuthenticationRequest.Realm属性,并仅在Realm符合条件时提供肯定断言。 这可以缓解攻击,一旦您的服务器设置完毕,任何人都可以设置一个网站,该网站悄悄使用您的OpenID提供商来识别随机互联网网站的用户(如果他们属于您的组织),这会侵犯他们的隐私。

第四,OP发送到RP的“领域”URL的HTTP请求是OpenID调用“RP发现”的过程的一部分。 它可以缓解“开放重定向器”攻击。 您应该将RP的基本URL调整为重定向,而是在RP发现请求进入时返回XRDS文档。您仍然可以重定向到正常的浏览器案例。 您可以在OpenIdRelyingPartyMvc示例的HomeController中看到如何执行此操作的示例。

从依赖方日志中可以看出:

 ERROR DotNetOpenAuth.Messaging - Protocol error: The URL 'http://localhost:3314/OpenId/' is rated unsafe and cannot be requested this way. 

您的提供程序托管在localhost上,在生产服务器上,它不是安全的OpenID。 因此,默认情况下,localhost被禁用。 您可以通过将localhost添加到您的web.config文件(在顶部使用相应的configSections )将localhost添加到白名单中来允许它进行本地测试: