As somewhat of a continuation of this question, I'm having problems with dotnetopenauth.
I navigate to my relying party code and create the request, however when my provider receives the request OpenIdProvider.GetRequest()
returns null. I went through the code and as far as I can tell, this is because the openid payload (request.form) is not being delivered by my relying party; but I can't figure out why this is.
Code:
Relying Party:
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();
}
Provider:
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();
}
Logs:
RP: 1) http://pastebin.com/Pnih3ND7 2) http://pastebin.com/eBzGun9y
Provider: http://pastebin.com/YAUTBzHk
Interestingly enough the RP log says that localhost is untrusted...yet I added it to the whitelisted hosts in my web.config, and it was "working" yesterday...
EDIT: Okay, this is weird. Yesterday I was stepping through the DNOA source trying to find out what the problem is. I enabled log4net and it created the log file and left it blank. Today I set up log4net again - it logged fine but I had an error that didn't make sense (see above). I also wasn't able to step into the DNOA source. I removed and re-added the reference to dotnetopenauth.dll, and then my "original error" with the whitelisted hosts went away, I was able to step into the source, but the log file was blank again. And I stil have the problem with request.form not being populated...
EDIT2: Both my controllers are named "OpenIdController" (both on the RP and EP). My RP is running on localhost:1903, and my endpoint is running on localhost:3314.
EDIT3: After I made the changes you suggested things started working. The RP performs the discovery fine, but I have an issue when it actually makes the request.
The line IRequest i_request = OpenIdProvider.GetRequest();
works fine, but when I try to cast it: IAuthenticationRequest iR = (IAuthenticationRequest)i_request;
it gives me the following error:
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()
This code is a bit of a hodge-podge between the two samples I found relevant. I want to set up an SSO type environment so the majority of the code I'm using is from \DotNetOpenAuth-4.1.0.12182\Samples\OpenIdWebRingSsoProvider\Code\Util.cs
(ProcessAuthenticationChallenge function). However, since that function expects an IAuthenticationRequest
but OpenIdProvider.GetRequest returns an AutoResponsiveRequest
I figured I'd be able to cast it in order to use the properties and methods of the IAuthenticationRequest
class. Obviously I was incorrect.
I'm not quite sure how to approach things at this point. Should I be using the sample code from the OpenIdProviderMVC sample? The key thing is that the login work like a single sign on, and the user is never actually prompted to enter an OpenId. I will only ever have one endpoint as well (although I will have multiple RP's).
Here's the link to the most recent RP logs: http://pastebin.com/enpwYqq3
EDIT4: I did what you suggested, and made some progress. My EP recieves the response and processes it as far as I can tell, but when it redirects back to the realm url it errors out.
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.
What exactly is the function of the Realm
as opposed to the ReturnTo
? Using the sample code, the Realm ends up being http://localhost:1903/
and the ReturnTo ends up being http://localhost:1903/OpenId/Authenticate
which seems fine. Why does the EP need to make a request to the realm? I'd have thought that it should simply be sending the assertion to the returnTo once it finished processing. If I manually set the Realm to http://localhost:1903/OpenId/Authenticate
then relyingParty.GetResponse()
returns null.
I do have my application set up to redirect when someone accesses the base url (http://localhost:1903
) - what code should I have running there to intercept the DNOA EP request?
New Logs:
RP: http://pastebin.com/L9K5Yft4
EP: http://pastebin.com/kBPWiUxp
I've also updated the code at the beginning of the question to better reflect the changes I've made.
EDIT5: Does the realm have to be the actual base URL of the application? That is, (http://localhost:1903
)? Given the existing architecture in place it is difficult to remove the redirect - I tried setting the realm to the base OpenId controller (http://localhost:1903/OpenId
) and testing manually did generate the XRDS document. However, the application seems to freeze, and the EP log reveals the following error:
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.