views:

739

answers:

3

I am using an authentication attribute on some of my actions in an asp.net mvc page to refer people to a login screen if they have not authenticated. My problem is returning them to the referring page after they have logged in. I was just keeping track of the referring action and referring controller but that becomes problematic when I also need to keep track of some parameters. Is there some nifty built in trick about which I don't know?

+2  A: 

What I did to achieve that result might be overdoing it, and I'd like to see some other methods as well. However, here's my code.

Please note it's using Moq to mock a context... And, I haven't done anything with the querystring yet (my routes don't contain any querystrings).

var urlReferrer = Request.UrlReferrer;
if (urlReferrer != null)
{
    var url = "~" + Server.UrlDecode(urlReferrer.PathAndQuery);

    // get routecollection
    var routeCollection = new RouteCollection();
    GlobalApplication.RegisterRoutes(routeCollection);

    // mcok context
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    context.Expect(ctx => ctx.Request).Returns(request.Object);

    // mock request
    // TODO: convert querystring to namevaluecollection
    // now it's just stripped
    if (url.IndexOf('?') > 0)
    {
        url = url.Substring(0, url.IndexOf('?'));
    }

    var mock = Mock.Get(context.Object.Request);

    // TODO: insert namevaluecollection of querystring
    mock.Expect(req => req.QueryString).Returns(new NameValueCollection());
    mock.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns(url);
    mock.Expect(req => req.PathInfo).Returns(string.Empty); 

    // get routedata with mocked context
    var routeData = routeCollection.GetRouteData(context.Object);
    var values = routeData.Values;

    return RedirectToAction(routeData.Values["action"].ToString(), values);
}

As I said, it's maybe a bit overcomplicated :)

Casper
Just as an extra comment, I also use the code above to modify some of the routedata's values.
Casper
+3  A: 

In case you're using FormsAuthentication, when ASP.NET redirects a user to the login page, the URL looks something like this:

http://www.mysite.com/Login?ReturnUrl=/Something

The login form's action attribute should have the same ReturnUrl parameter (either as hidden input or as part of Url) so that FormsAuthentication can pick it up and redirect, e.g.

<form action="Login?ReturnUrl=<%=Html.AttributeEncode(Request.QueryString["ReturnUrl"]) %>"></form>

or

<form><input type="hidden" name="ReturnUrl" id="ReturnUrl" value="<%=Html.AttributeEncode(Request.QueryString["ReturnUrl"])"%> /></form>
liggett78
A: 

You should always ensure that the referring URL is within your domain and a plausible string that they could be coming from. Otherwise this has the potential of being used with flash or other client side technologies to do things like response splitting or other attacks, known and unknown.

The HTTP referer is user input, and it should be validated like any other.

Daniel Papasian