Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Login to the MVC 5 ASP.NET template Web Application fails when moved from the root folder

I used the ASP.NET Web Application template to create a new "Single Page Application" with "Authentication: Individual User Accounts". It will run with the default settings without any problem.

If I don't deploy the application to the root folder of the web server the authentication fails. The culprit is in the app.viewmodel.js file where the following code can be found:

self.addViewModel = function (options) {
    var viewItem = new options.factory(self, dataModel),
        navigator;

    // Add view to AppViewModel.Views enum (for example, app.Views.Home).
    self.Views[options.name] = viewItem;

    // Add binding member to AppViewModel (for example, app.home);
    self[options.bindingMemberName] = ko.computed(function () {
        if (!dataModel.getAccessToken()) {
            // The following code looks for a fragment in the URL to get the access token which will be
            // used to call the protected Web API resource
            var fragment = common.getFragment();

            if (fragment.access_token) {
                // returning with access token, restore old hash, or at least hide token
                window.location.hash = fragment.state || '';
                dataModel.setAccessToken(fragment.access_token);
            } else {
                // no token - so bounce to Authorize endpoint in AccountController to sign in or register
                window.location = "/Account/Authorize?client_id=web&response_type=token&state=" + encodeURIComponent(window.location.hash);
            }
        }

        return self.Views[options.name];
    });

The line where window.location = "/Account..." redirects the browser to an URL offset at the root directory. Unfortunately just hard coding this to the new folder instead (which I would like to avoid anyway) does not solve the problem entirely.

The redirect seems to work at first but behind the scenes in the AccountController.csfile Authorize()is called which in turn calls AuthenticationManager.SignIn(identity) and somehere there is magic going on. There is a redirect to http://localhost/foo/Account/Login?ReturnUrl=... and we're back where we started.

I am probably missing the obvious. I'd appreciate any pointers.

It's very easy to replicate. Just create a new web app with the default settings and then go into project properties and change the "Project Url" to something like http://localhost:49725/foo which moves the app to a new folder called "foo".

like image 997
Jay Avatar asked May 31 '14 00:05

Jay


1 Answers

I'm facing same problem, the change I did was:

  1. In the file app.viewmodel.js I added a new parameter (returnUrl):

    // no token - so bounce to Authorize endpoint in AccountController to sign in or register
    window.location = "/Account/Authorize?client_id=web&response_type=token&state=" 
        + encodeURIComponent(window.location.hash) 
        + "&returnUrl=" + encodeURIComponent(window.location);
    
  2. In the method ValidateClientRedirectUri of class ApplicationOAuthProvider I read this parameter and set as the return url:

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
    {
        if (context.ClientId == _publicClientId)
        {
            Uri expectedRootUri;
            if (!string.IsNullOrEmpty(context.Request.Query["returnUrl"]))
            {
                expectedRootUri = new Uri(context.Request.Query["returnUrl"]);
            }
            else
            {
                expectedRootUri = new Uri(context.Request.Uri, "/");
            }
    
            if (expectedRootUri.AbsoluteUri == context.RedirectUri)
            {
                context.Validated();
            }
            else if (context.ClientId == "web")
            {
                var expectedUri = new Uri(context.Request.Query["returnUrl"]);
                context.Validated(expectedUri.AbsoluteUri);
            }
        }
    
        return Task.FromResult<object>(null);
    }
    
like image 121
VictorV Avatar answered Oct 12 '22 17:10

VictorV