I have a custom authorization filter for my Authorize method in my OAuth controller. When the authorization filter notes the user is logged, it stuffs the current OAuth request into the session, and ships them off to log in.
After log in, in my /OAuth/Authorize endpoint, I check to see if that request is in the session, instead of immediately failing because there is not an authorization request attached to the current request. Then, I call the authorization server with that request object.
The code in my Authorize action looks like this:
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
[ExternalAppAuthorizeAttribute]
public ActionResult Authorize() {
Object requestObject = this.HttpContext.Session["AuthRequest"];
HttpRequestBase request = null;
if ((requestObject != null) && (requestObject.GetType() == typeof(HttpRequestWrapper)))
{
request = (HttpRequestWrapper)requestObject;
this.HttpContext.Session.Remove("AuthRequest");
}
EndUserAuthorizationRequest pendingRequest = null;
if (request != null)
{
pendingRequest = this.authorizationServer.ReadAuthorizationRequest(request);
} else
{
pendingRequest = this.authorizationServer.ReadAuthorizationRequest();
}
if (pendingRequest == null) {
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
ReadAuthorizationRequest fails, however, when the request was found in the session and restored. The error message is not very helpful: "Value does not fall within the expected range. "
Here is the stacktrace:
[ArgumentException: Value does not fall within the expected range.]
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo) +0
System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode) +10
System.Web.Util.Misc.ThrowIfFailedHr(Int32 hresult) +9
System.Web.Hosting.IIS7WorkerRequest.GetServerVariableInternal(String name) +36
System.Web.Hosting.IIS7WorkerRequest.GetServerVariable(String name) +49
System.Web.HttpRequest.AddServerVariableToCollection(String name) +22
System.Web.HttpRequest.FillInServerVariablesCollection() +85
System.Web.HttpServerVarsCollection.Populate() +36
System.Web.HttpServerVarsCollection.Get(String name) +42
System.Collections.Specialized.NameValueCollection.get_Item(String name) +10
DotNetOpenAuth.Messaging.MessagingUtilities.GetPublicFacingUrl(HttpRequestBase request, NameValueCollection serverVariables) +61
DotNetOpenAuth.Messaging.MessagingUtilities.GetPublicFacingUrl(HttpRequestBase request) +43
DotNetOpenAuth.Messaging.Channel.ReadFromRequestCore(HttpRequestBase request) +69
I've inspected my request in flight and everything used by oauth in it looks totally fine: headers, URI, etc. I'm at a loss as to what might be causing this.
Does anyone know why this might be the case? Or, if you have alternative recommendations for storing the oauth request while the user is authenticating, I am open to them.
Turns out that ServerVariables on the HttpRequestWrapper was throwing an exception when called (which is now obvious from the stack trace). I believe this is because the request hadn't hit the controller action yet since it was intercepted by the filter. I guess that ServerVariables gets set when the request is processed by the controller action?
I resolved this by creating a new class that implements HttpRequestBase. I passed it my stored oauth request and the actual request, and returned the properties from the oauth request for everything in HttpRequestBase except ServerVariables, which I returned from the current request.