This webpage has a redirect loop asp.net mvc4 - asp.net-mvc-4

I have a startup class with following code
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType="ApplicationCookie",
LoginPath = new Microsoft.Owin.PathString("/auth/login")
});
}
}
When I run my project showing me
The webpage at
/auth/login?ReturnUrl=%2Fauth%2Flogin%3FReturnUrl%3D%252Fauth%252Flogin%253FReturnUrl%253D%25252Fauth%25252Flogin%25253FReturnUrl%25253D%2525252Fauth%2525252Flogin%2525253FReturnUrl%2525253D%252525252Fauth%252525252Flogin%252525253FReturnUrl%252525253D%25252525252Fauth%25252525252Flogin%25252525253FReturnUrl%25252525253D%2525252525252Fauth%2525252525252Flogin%2525252525253FReturnUrl%2525252525253D%252525252525252Fauth%252525252525252Flogin%252525252525253FReturnUrl%252525252525253D%25252525252525252Fauth%25252525252525252Flogin%25252525252525253FReturnUrl%25252525252525253D%2525252525252525252Fauth%2525252525252525252Flogin%2525252525252525253FReturnUrl%2525252525252525253D%252525252525252525252Fauth%252525252525252525252Flogin%252525252525252525253FReturnUrl%252525252525252525253D%25252525252525252525252Fauth%25252525252525252525252Flogin%25252525252525252525253FReturnUrl%25252525252525252525253D%2525252525252525252525252Fauth%2525252525252525252525252Flogin%2525252525252525252525253FReturnUrl%2525252525252525252525253D%252525252525252525252525252Fauth%252525252525252525252525252Flogin%252525252525252525252525253FReturnUrl%252525252525252525252525253D%25252525252525252525252525252Fauth%25252525252525252525252525252Flogin%25252525252525252525252525253FReturnUrl%25252525252525252525252525253D%2525252525252525252525252525252Fauth%2525252525252525252525252525252Flogin%2525252525252525252525252525253FReturnUrl%2525252525252525252525252525253D%252525252525252525252525252525252Fauth%252525252525252525252525252525252Flogin%252525252525252525252525252525253FReturnUrl%252525252525252525252525252525253D%25252525252525252525252525252525252Fauth%25252525252525252525252525252525252Flogin%25252525252525252525252525252525253FReturnUrl%25252525252525252525252525252525253D%2525252525252525252525252525252525252Fauth%2525252525252525252525252525252525252Flogin%2525252525252525252525252525252525253FReturnUrl%2525252525252525252525252525252525253D%252525252525252525252525252525252525252Fauth%252525252525252525252525252525252525252Flogin%252525252525252525252525252525252525253FReturnUrl%252525252525252525252525252525252525253D%25252525252525252525252525252525252525252F
has resulted in too many redirects. Clearing your cookies for this
site or allowing third-party cookies may fix the problem. If not, it
is possibly a server configuration issue and not a problem with your
computer.
I cleared my cookie but still unchanged.

I agree with #StephenMuecke this is from a
endless redirect loop.
If the page you are trying to land need authentication to view, by either having [Authorize]
on the controller class or :
[Authorize]
public class AccountController:Controller
{
or at the controller ActionResult:
[Authorize]
public ActionResult Index
This will redirect the user to the login page.
If this does not allow anonymous authenitcation, it is immpossible for a user to land on the page
without being logged in.
[Authorize]
public ActionResult Login(string message, string returnUrl)
{
Hence the app keeps redirecting the user to the login page continously until there is
some type of overflow.
You need to use this:
[AllowAnonymous]
public ActionResult Login(string message, string returnUrl)
{
ReturnUrl=%2Fauth%2Flogin%3FReturnUrl%3D%252Fauth%252Flogin%253FReturnUrl%253D%25252Fauth%
The return url requires authentication, so login, which requires authentication.. and so on.
This same prinicple works throughout your entire project.

Related

Identity Server 4 OIDC authorization_code flow multi tenancy

I'm facing an issue for authenticating my users on my IS4 server with an application (Blazor Server/WASM).
My IDSRV4 is located on the same app that the API to protect, and each client has it owns database (for users and business models).
To choose the good database, I use an header and have set up a interceptor on EF Core to choose database according to header value.
Everything works great, except authentication. I was using resource_owner_password flow with a JavaScript app (security breach, I know) which allows me to pass custom headers for each calls (calling /connect/token with my custom header).
Now, with the authorization_code flow, I cannot manage to pass the header to choose good tenant, meaning good database, which causes authentication to failed because token is validated on another database that the user is currently register to.
I can pass the tenant to choose database during login process (when posting login info on IDSRV4 side), and I've set up event on client side to add header on when sending back code for having back id_token, but I lost the capability to do that after my idp redirect user after login on /connect/authorize (it seems there no extension on IDSRV4 side for adding custom headers).
So my user post login data (with tenant infos), that I lost when redirecting to /connect/authorize, and I have no way to customize this. Is there any chance to do that ?
Merging all users in the same database is not an option.
You can still add any custom headers to any HttpResponse from your MVC app hosting Identityserver.
// public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseCustomHeaders();
//CustomHeadersMiddleware.cs
public static class CustomHeadersMiddlewareExtensions
{
public static IApplicationBuilder UseCustomHeaders(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomHeadersMiddleware>();
}
}
public class CustomHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<CustomHeadersMiddleware> _logger;
public CustomHeadersMiddleware(RequestDelegate next,
ILogger<CustomHeadersMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task Invoke(HttpContext context)
{
var watch = new Stopwatch();
watch.Start();
//To add Headers AFTER everything you need to do this
context.Response.OnStarting(() =>
{
if (!context.Response.Headers.ContainsKey("X-Response-Time-Milliseconds"))
context.Response.Headers.Add("X-Response-Time-Milliseconds",
new[] {watch.ElapsedMilliseconds.ToString()});
return Task.FromResult(0);
});
await _next(context);
}
}

how to perform "dry-run" authorization check in .NET Core?

Consider that I have .NET Controller with Policy-based authorization:
public class ImportantController: Controller {
[HttpGet]
[Authorize(Policy = "CanAccessVIPArea")]
public IActionResult ShowInformation() {
...
return OK(VipData);
}
[HttpPost]
[Authorize(Policy = "CanChangeVIPData")]
public IActionResult SaveInformation([FromBody] VipData) {
...
return CreatedAtAction(...);
}
}
Obviously, the real example is much more complex; I apologize if my simplification leads to too much make-believe in it. Also, real application is SPA with Angular front end; but I don't think it makes any difference for the purposes of this question.
When the user calls ShowInformation() I show a lot of data. On that page I have Save button that calls SaveInformation(). Authorization middleware checks for the right policy and it all works fine.
The problem is that by the time the user presses Save, she entered a lot of data, only to find out that she doesn't have the permissions to save. Obviously, leading to bad experience. I want to check for permissions on SaveInformation in the middleware that gets invoked when the user calls ShowInformation. I would prefer not to check for the hardcoded policy because it is on the server and it can change (we have pretty sophisticated permission management system that manipulates permissions at runtime). Invocation of SaveInformation is in the same Angular service as ShowInformation, and it is very easy to check...
I would like to invoke something like /api/SaveInformation?dryrun that will short-circuit the pipeline after authorization middleware with success or failure.
You can inject an IAuthorizationService and ask to evaluate a policy by name:
public class ImportantController: Controller
{
private readonly IAuthorizationService authorization;
public ImportantController(IAuthorizationService authorization)
{
this.authorization = authorization;
}
public async Task<IActionResult> ShowInformation()
{
// ...
var result = await authorizationService.AuthorizeAsync(User, "IsLucky");
return OK(VipData);
}
}
My pratice is to include all permission claims in the id token, when the user first login to the system, the id token will return to the client side. The client side then render the page according to the permission claims.

Checking if the user is logged in asp.net mvc

In my application I am restricting some view and the user has to be logged in to view them. One way would be to check on every action if the user is logged in or not. But after a bit of research I found that asp.net MVS supports some global filter rules.
How do we use them? Ideally I would want to call a filter onBeforeAction and check if the user is logged in or not..
Is this a right approach? If yes, then can any body give me an example?
The easiest way is to add the Authorize attribute to your controller or action methods. For example:
public class MyController : Controller
{
//Normal action
public ActionResult DoSomethingForAnyone() { }
//Secured action
[Authorize]
public ActionResult DoSomethingOnlyForAuthorisedUsers() { }
}
Alternatively you can secure the entire controller and exclude actions you want to be accessible to anonymous users:
[Authorize]
public class SecureController : Controller
{
public ActionResult DoSomething() { }
[AllowAnonymous]
public ActionResult DoSomethingForAnyone() { }
}
Your [Authorize] will not work with the custom login. If you are using Form Authentication or other Authentication method than [Authorize] will work smoothly.
For custom login on success set
FormsAuthentication.SetAuthCookie([user name], false);
This will make your [Authorize] attribute to work properly.
And for logout use below statement
FormsAuthentication.SignOut();
If you follow the above solution than it will reduce your code as well as valid user check on before Action call.

How am I supposed to use ReturnUrl = ViewBag.ReturnUrl in MVC 4

I'm working on 'ASP.NET MVC 4' application. I'm using/learning SimpleMembershipProvider and try to stick to the default logic created by VS2012 with the Internet template (if I'm not mistaken, the one with 'SimpleMembershipProvider' out of the box).
I'm stuck at the AccountController where I just can't figure put how exactly I can use this method:
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
From what I understand the whole idea is to get redirected to the location from where you've decided to log in (exactly what I want to accomplish). I took a look at how it's used in the view :
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
Look for a place where actually ViewBag.ReturnUrl is set with some value and I only got this method here:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
and I'm getting pretty confused about how exactly I'm supposed to get the location/url. I set some breakpoints and I have never seen returnUrl to be something different from null which in this scenario seems pretty logical to me since it doesn't get value anywhere (unless I miss something of course).
So I really can't figure out how this work. I post the above just to show that I tried to do my homework, I investigate as much as I could but I didn't found an answer so I ask here. Could you provide explanation/example on how this actually work?
When using forms authentication and the user is not authenticated or authorized the ASP.NET security pipeline will redirect to the login page and pass as a parameter in the query string the returnUrl equal to the page that redirected to the login page. The login action grabs the value of this parameter and puts it in the ViewBag so it can be passed to the View.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The View then stores this value in the form as shown by this line of code in the View.
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
The reason it is stored in the View is so that when the user does a Submit after entering their user name and password, the controller action that handles the post back will have access to this value.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
If the model state is valid and they are authenticated by calling the WebSecurity.Login method then it calls the method RedirectToLocal with the value of returnUrl which came from the View, which originally came form the login action that created the View.
The returnUrl value will be null if the user is not redirected to the login page as is the case when they just click on the login link at the top of the page in the default layout. In this case the user will be redirected to the home page after successful login. The whole purpose of the returnUrl is to automatically send the user back to the page they were trying to access before they were authenticated/authorized.
That's because the default ASP.NET MVC template is using Forms authentication, and controllers are decorated with [Authorize] attribute:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
[Authorize]
public class AccountController : Controller
{
//...
}
That means that if the user is not authenticated it will be redirected to the logon page defined in the LoginUrl attribute of the forms element.
During the redirection, FormsAuthentication which is an HttpModule will append the url which was requested in the query string automatically.
So if you navigate to /Account/Login, you wont get anything in the query string since it is decorated with [AllowAnonymous] attribute.
But if you navigate to /Account/Manage you'll notice that the returnUrl in the query string becomes /Account/Manage (/Account/Login?ReturnUrl=%2fAccount%2fManage)
So you are not setting the returnUrl, the framework does it for you, you just use it in the AccountController to know where to redirect the user after he is authenticated.
When an unauthenticated user tries to get into a section of your application which requires authentication, then returnUrl comes into the picture. The Url requested by the unauthenticated user is basically stored in returnUrl.
You can go through the PluralSight tutorial: Building Applications with ASP.NET MVC 4

MVC 4 Using Authorize with Custom Code Not Working

New to MVC 4. What I do not want to do is used the built-in Account management that comes with MVC 4. However, I have created an Account folder under Views, an AccountModel, and AccountController.
What I would like to do is restrict access to Views within the Account folder. for this, in my AccountController, I use the following:
[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
public ActionResult bob()
{
return View();
}...
On my home page, I have a link to the bob view under the Accounts view which now reroutes me to the login page (which is correct).
Now, upon form submittal, with the right credentials (anything goes) I should be able to see bob, but instead I am redirected back to the Login because I was not authorized. The code:
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
return RedirectToLocal(returnUrl);
}...
I do not want to use the built-in connect to the DB, but rather what do I need to check the username against a string and then keep an authorization = true so that I can view bob?
In the long run, I plan on connecting to a DB and pulling info back with a SPROC, so right now, I just want the user to be authenticed based upon a string that is checked.
You continue to be Redirected until ASP.net sees a Forms Authenticated cookie.
FormsAuthentication.SetAuthCookie(theUsersNameasString, boolForSessionOrPersistentCookie);
Assuming your Web.Config is configured for Forms Authentication
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
ASP.Net will look for .ASPXAUTH cookie unless the name of this cookie was altered in WEB.CONFIG