2012-09-20 50 views
2

作爲this問題的延續,我對dotnetopenauth存在問題。OpenIdProvider.GetRequest()返回null

我導航到我的依賴方代碼並創建請求,但是當我的提供程序收到請求時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的日誌說,本地主機是不可信的......但我把它添加到我的web.config中的白名單的主機,它是「工作」昨天...

編輯:好的,這很奇怪。昨天我正在通過DNOA來源,試圖找出問題所在。我啓用了log4net,它創建了日誌文件並將其留空。今天我再次設置了log4net--它記錄的很好,但是我有一個沒有道理的錯誤(見上文)。我也無法步入DNOA來源。我刪除並重新添加了對dotnetopenauth.dll的引用,然後我的白名單主機的「原始錯誤」消失了,我能夠進入源代碼,但日誌文件又是空白的。我仍然有request.form沒有被填充的問題...

EDIT2:我的控制器都命名爲「OpenIdController」(RP和EP)。我的RP在localhost:1903上運行,我的端點在localhost:3314上運行。


EDIT3:以後,我所做的更改你的建議,事情開始工作。 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.<BeginInvokeSynchronousActionMethod>b__41() 
    at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>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.<BeginInvokeActionMethodWithFilters>b__33() 
    at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>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


EDIT4:我做了你的建議,並取得了一些進展。據我所知,我的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的功能,而不是在ReturnTo?使用示例代碼,領域結束爲http://localhost:1903/和ReturnTo結束爲http://localhost:1903/OpenId/Authenticate這似乎很好。爲什麼EP需要向領域提出請求?我一直認爲它應該只是在斷言完成處理後將斷言發送給returnTo。如果我手動將Realm設置爲http://localhost:1903/OpenId/Authenticate,則relyingParty.GetResponse()將返回null。

我有我的應用程序設置爲當有人訪問基地址(http://localhost:1903)重定向 - 我應該運行哪些代碼來攔截DNOA EP請求?

新日誌:

RP:http://pastebin.com/L9K5Yft4

EP:http://pastebin.com/kBPWiUxp

我還更新了代碼在問題之初,以更好地反映我所做的更改。


EDIT5:請問領域必須是實際應用的基礎網址是什麼?那就是(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.

+1

它可能有助於[從RP和OP收集日誌](http://tinyurl.com/dnoalogs)並將它們包括在您的問題中。 –

+0

@AndrewArnott我試過了 - glimpse沒有起作用,log4net創建了日誌文件,但是留下了空白。我會盡力給它另一個鏡頭,雖然... – Mansfield

+0

@AndrewArnott:得到了依賴方日誌,仍然在提供商工作。添加了OP的鏈接。 – Mansfield

回答

2

你的RP有很奇怪的可疑代碼。儘管return_to和realm都具有相同的Uri權限是正常的(實際上是必需的),但您傳入的作爲OpenIdRelyingParty.CreateRequest的第一個參數的用戶提供的標識符與您的主機和端口具有相同的主機和端口依靠方是非常奇怪。通常,您通過的標識符將是由供應商承載的URL。現在,我不知道3314端口是你的RP還是你的OP,但無論哪種方式,RP代碼中的其中一個端口號看起來是錯誤的。

其次,對用戶標識符的發現失敗,出現空引用異常(根據RP日誌的v2)。這將阻止登錄請求到達您的提供者。提供者被調用的事實是被調用但帶有不存在的OpenID請求表明http://localhost:3314/OpenId/實際上是您的OP端點(OpenID提供程序的讀取OpenID請求的操作方法的URL)。這是不合適的。您應該傳遞給您的OpenIdRelyingParty.CreateRequest方法的第一個參數的URL應該再次成爲用戶的OpenID URL--而不是OP端點。查看OpenIdProviderMvc示例的用戶控制器,瞭解如何設置用戶OpenID URL的示例。然後使用的URL作爲第一個參數爲CreateRequest,我認爲你會很好。

第三,一旦你的提供者收到一個非空請求,你不能總是將它投到IAuthenticationRequest。並非所有的OpenID消息都是身份驗證消息。有些是底層OpenID協議的一部分。如果您查看OpenIdProviderMvc示例的OpenID控制器,則應注意到存在處理不同消息類型的條件轉換。你的控制器應該有類似的消息處理。

既然你要爲SSO的情況下,在你的控制器的顯著差異大概是:

  1. 控制器從來沒有重定向到登錄頁面響應,而是「神奇」數字出誰用戶是。
  2. 您的控制器應該檢查IAuthenticationRequest.Realm屬性與您SSO Web環中包含的RP白名單的關係,並且只在Realm符合要求時提供肯定的斷言。這可以緩解攻擊,一旦您的服務器設置完成,任何人都可以設置一個站點,悄悄地使用您的OpenID提供程序來識別隨機Internet站點的用戶,如果他們屬於您的組織,這將違反他們的隱私。

第四,OP發送到您的RP​​的「領域」URL的HTTP請求是OpenID調用「RP發現」的過程的一部分。它可以緩解「開放重定向器」攻擊。您應該將您的RP的基本URL調整爲而不是重定向,而是在發現RP發現請求時返回XRDS文檔。您仍然可以重定向瀏覽器正常情況。您可以在OpenIdRelyingPartyMvc示例的HomeController中看到如何執行此操作的示例。

+0

有趣 - 這是很有道理的。我將不會在星期二回來工作,但我會盡力而爲,希望它能奏效。謝謝! – Mansfield

+0

我不得不做出其他一些改變,但你對核心問題是正確的。我還有一個問題 - 請參閱我最後一次編輯OP的進一步解釋。 – Mansfield

+0

我在回答中添加了「第三」。 –

1

你可以從依賴方日誌中看到:

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

您的提供商託管在本地主機上,在生產服務器上這不是一個安全的OpenID。所以默認情況下localhost被禁用。您可以通過添加以下內容到你的web.config文件(在頂部適當configSections)將本地主機列入白名單允許它用於本地測試:

<dotNetOpenAuth> 
    <messaging> 
     <untrustedWebRequest> 
      <whitelistHosts> 
       <add name="localhost" /> 
      </whitelistHosts> 
     </untrustedWebRequest> 
    </messaging> 
</dotNetOpenAuth> 
+0

您是否看到我的第二個編輯?我在白名單上(現在仍然是這樣),而且無論如何都給了我這個錯誤。一旦我過去了,那就是當我遇到Request.form不發送的問題。 – Mansfield

+0

只是爲了澄清 - 我過去了這個錯誤。 RP發出EP接收到的請求,但是這一行:'IRequest i_request = OpenIdProvider.GetRequest();'返回null,從我可以看到的代碼中可以看出它是因爲Request.Form爲空(字段是沒有設置)。爲什麼這是......好吧,那就是我卡住的地方。 – Mansfield

+0

我正在迴應您的日誌文件中存在的問題。如果你通過了這一點,你能否更新日誌文件? –