views:

4334

answers:

3

I have a central authentication application on server a. Server b has one or more applications on the same domain that need to authenticate from server a. It's easy enough to set it up so that the server b apps redirect out to server a. What's not so easy is getting the ReturnURL to be absolute.

Here's the wrinkle. Consuming app on server b has two controllers, one public and one secured. If the [authorize] decoration is placed on an action in the public (which is the default controller), I get the proper absolute URL. However, if its in it's own controller I get a relative URL.

I can intercept the on pre-request event in the consuming applications, but I need some parts of the site to be public, not the whole smash.

Ideas?

+7  A: 

The way the standard AuthorizeAttribute works is by setting the response status code to 401 if the request is not authenticated. This kicks in the default authentication module's standard response to an unauthorized request. I assume that you're using forms-based authentication, which would build the return url based on the url in the request. In this case, probably a relative URL.

One thing you could do is instead of relying on the built-in behavior, you could implement a SSOAuthorizeAttribute which extends the AuthorizeAttribute class and overrides OnAuthorization. You could then extract the loginUrl from the forms element in the web configuration and build your own RedirectResult and pull the returnUrl from the HttpContext.Request.Url.AbsoluteUri property in the AuthorizationContext parameter.

 public class SSOAuthorizeAttribute : AuthorizeAttribute
 {
      public override void OnAuthorization( 
                          AuthorizationContext filterContext )
      {
          if (filterContext == null)
          {
              throw new ArgumentNullException( "filterContext" );
          }

          if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
          {
              // get from cached variable from web configuration
              string loginUrl = ... 
              if (filterContext.HttpContext.Request != null)
              {
                  loginUrl += "?ReturnUrl=" + filterContext.HttpContext
                                                           .Request
                                                           .Url
                                                           .AbsoluteUri;
              }
              filterContext.Cancel = true;
              filterContext.Result = new RedirectResult( loginUrl );
          }
      }
 }
tvanfosson
A: 

It's very odd. If I have a URL like this:

http://someserver.net/EDAuthentication?ReturnUrl=http://someserver.net/IAMWebShell/Public/SecureLink

Things are good, but this URL not so much:

http://someserver.net/EDAuthentication?ReturnUrl=%2fIAMWebShell%2fSecure%2fSecureLink

I will put together the filter attribute, thanks!

bxlewi1
Can you show your route set up? I don't know why they would be different from each other. Actually I would expect them both to be like the latter.
tvanfosson
+1  A: 

Assuming forms authentication, in the server B apps web.config, set the loginUrl attribute on the forms tag to a Controller Action method that tacks on the absolute url before redirecting to server A.

Config on server B

<authentication mode="Forms">
  <forms loginUrl="/Account/LoginRedirect" />
</authentication>

The action method would look like

 public RedirectResult LoginRedirect(string returnUrl)
    {
       var requestUrl = HttpContext.Current.Request.Url;
       return LoginUrlOnServerA + 
              "?returnUrl=" +          
              HttpUtility.UrlEncode(string.Format("http://{0}:{1}{2}",
                requestUrl.Host,
                requestUrl.Port,
                HttpUtility.UrlDecode(returnUrl)));
     }
LukeDuff