Trouble with antiforgery token using owin - c#

I'm setting OWIN authentication with my app but I have one problem. I set the validate and anti-forgery token on my login page and when I make a POST all works fine, but on another page setting the validate and anti-forgery token when I make a POST causes the following error to appear:
Anti-forgery token provider was designed for user "user#domain.com" but the current user is "" ...
So how I can fix this without using AntiForgeryConfig.SuppressIdentityHeuristicCheck in Global.asax?
Why doesn't the anti-forgery token take the current user?
UPDATE
The Task<ClaimsIdentity> implements like this:
public override Task<ClaimsIdentity> CreateIdentityAsync(AppUser user, string authenticationType)
{
return Task<ClaimsIdentity>.Factory.StartNew(() =>
{
var claimsList = new List<Claim>()
{
new Claim(ClaimTypes.Name, user.Email),
};
return new ClaimsIdentity(authenticationType);
});
}
And the Task SignInAsync like this:
public override async Task SignInAsync(AppUser user, bool isPersistent, bool rememberBrowser)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Email));
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
The user.Email is user#domain.com

If the user is logged on then anti forgery token will be issued for that user. Let me give you an example:
Say you have two pages with anti forgery token that submit with form data: Login Page and Search Page
Open search page and perform a search, it will be fine.
Now open login page on another tab (in browser) and login successfully.
Now go back to search page that is already open in the previous tab. Try to perform a search and boooom, you will get anti forgery token error.
Now re-fresh the search page and do another search, it will be fine.
It is because initially the token on search page didn't have user info but the server expects it because the user is logged on. On re-fresh of the search page token gets updated with logged on user info, so it throws no error.

Related

ASP.NET Core. How can i create an auth cookie without an identity user account?

My app creates an Guid Event token
The customer visits the url of the event like so.
https://example.com/event/a3b2e538-e87c-4444-a655-5171f263ac70
The customer is then redirected to a login form to provide the event password.
If the password maches the event token customer will be able to see the event.
Can i acomblish this without an Identity user account? (I do not wish to follow the classical user identity login approach, in this case).
Maybe something like creating an auth cookie and use it, in the upcoming requests.
[HttpPost]
[Route("validate/{code}")]
public IActionResult Cookie(string code)
{
var user = true; //Validate event token against event password supplied by user
if (user == true)
{
var ident = _userManager.CreateAuthCookie(user, DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);
return Redirect("Wherever");
}
ModelState.AddModelError("", "Invalid login attempt");
return View();
}
I guess, I understand your point. You want to create a custom Owin Authentication Framework. The same thing can be achieved using JWT token. It has advantages over OWIN Authentication.
But if you want to design something like this using OWIN, Please take care of these:
First and most important thing, the parameter passed in the url should not have any password or sensitive value. The URL token should be encoded (for encoding u can refer https://www.nuget.org/packages/Microsoft.Owin.Security/) and that encoded token can carry this information. While encoding, you can encode someID (not email address), some sourcecd (that tells the token is from the valid source), some time limit and how many times that token will be valid.
Now, when you get the call to your API end point, you can decode that token, validate and then extract that someID, and make a call to your DB to understand, if the user is valid.
Important: Encoding and decoding algorithm plays a very important role here. So, your encoding and decoding token should not be exposed anywhere.
If he is a valid user, then create a claimsIdentity object.
ClaimsIdentity identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identity.FindFirst("sub").Value));
identity.AddClaim(new Claim("Name", <<add your claims like this>>));
identity = new ClaimsIdentity(identity.Claims, "ApplicationCookie");
AuthenticationProperties properties = new AuthenticationProperties();
AuthenticationManager.SignIn(properties, identity);
Setup Authentication class object in your controller or to a seperate file:
using Microsoft.Owin.Security;
private IAuthenticationManager authenticationManager;
public IAuthenticationManager AuthenticationManager
{
get
{
if (authenticationManager == null)
authenticationManager = HttpContext.GetOwinContext().Authentication;
return authenticationManager;
}
set { authenticationManager = value; }
}
You should also have OWIN layer configured in the middlelayer. You can configure OWIN middle layer based on .Net framework or .Net Core

Is it possible to use client login page instead of identityserver login page

i´m new to identityserver and the security. I finish all the quickstart in the documentation but all the samples use the identityserver login page. Is it possible to make login page from client website, so it wont redirect from localhost:5003 to localhost:5000 then back again to localhost:5003?
Yes, using GrantTypes.ResourceOwnerPassword. See Protecting an API using Passwords.
You have a form where the user enters their username & password, and then in your code-behind you do something similar to the code found on that page under "Requesting a token using the password grant", substituting "alice" and "password" below with the submitted values.
// request token
var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret");
var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

How can I get a User object returned when authenticating with ASP.NET Identity 2?

This authentication normally just involves calling the '/Token' endpoint, with user credentials, and receiving a ticket back containing an auth token for the user. I am calling this in my Web API from a WPF client application, and it would make life much easier for me, and the login process much quicker, if I could simple have one authentication request that returns the authenticated IdentityUser, or in a normal template based API project, an AspNetUser object.
I see the method TokenEndPoint in my API's ApplicationOAuthProvider does very little, so I don't think a change there could help much, but the GrantResourceOwnerCredentials seems to be the crux of that provider, yet its return is void.
The options for the provider include:
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin")
but I can find no evidence of that action being executed. I trace all successful requests to a log, and my Debug.WriteLine($"API TRACE: ExternalLogin called for {provider}.") doesn't appear in the output window, so I don't think I can use that action to server redirect to one that returns a User.
Is there anything I can do, except call the /Token endpoint from a login action that allows anonymous, and then redirect?
EDIT: The method that grants the token is in the ApplicationOAuthProvider class provided in my project template. It derives from OAuthAuthorizationServerProvider. It is:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<UserManager>();
var user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", $"The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
It is possible to do a Server.Transfer within the GrantResourceOwnerCredentials method of the ApplicationOAuthProvider : OAuthAuthorizationServerProvider class. This is provided out-the-box in the either the project template or a Nuget package.
The transfer would be to an added Login method in the AccountController, with username, password, and an additional ticket parameter, which will return an AspNetUser user class, to which you can add an extra property for the authentication ticket obtained in GrantResourceOwnerCredentials and normally returned by the /Token resource.
But this is too much meddling in code not written by me, so for this urgent prototype of the project, I just call /Token, and when I have the username, I call /User to get the now signed in AspNetUser.

need to pass a default emailid in azure active directory authentication

I am doing Azure Active Directory authentication and using openidconnect for authentication. My application has it own login page and I am trying to redirect the user as soon as they type user id in my login page.
But I am unable to pass userid from my login page to azure login page. I am using following code for
calling azure login page and it redirected correctly but I am not able to pass any default login id which should be displayed on the azure login page like "abc#microsoft.com".
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" });
You need to add a login_hint query string parameter in the redirect to the authorization server. Here is a post which describes this (in the context of Google login, which also uses OpenID Connect):
http://forums.asp.net/t/1999402.aspx?Owin+pass+custom+query+parameters+in+Authentication+Request
In your case, I suggest you try the following:
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties
{
RedirectUri = "/",
Dictionary =
{
{ "login_hint", "abc#microsoft.com" }
}
});

How to persist the login information after closing Browser using asp.net Identity?

When using the ASP.NET Identity, I want to persist the login information as long as possible when the user logs in to my website, so the user doesn't need to login again when they reopened their Browser (just like github.com and stackoverflow.com). When I login to github, it persists my information for many days, so I don't need to login again every day. Are there any methods can that can implement this functionality using ASP.NET Identity?
Just pass the appropriate value to the isPersistent argument of the SignIn methods:
SignInManager.PasswordSignInAsync("email#id.com", "password", isPersistent: true, shouldLockout: false);
or
SignInManager.SignInAsync(applicationUser, isPersistent: true, rememberBrowser: false);
The isPersistent argument is used to control if the user's authentication cookie should be persisted.
The rememberBrowser argument is used in case of Two Factor Authentication: a remembered browser can login directly with the password alone.
You need to set IsPersistent property on AuthenticationProperties to persist login after browser close. The registered method user.GenerateUserIdentityAsync generates the new ClaimsIdentity to be refreshed in the cookie.
private async Task<SignInStatus> SignIn(User user, bool isPersistent)
{
await SignInAsync(user, isPersistent);
return SignInStatus.Success;
}
public async Task SignInAsync(User user, bool isPersistent)
{
var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
AuthenticationManager.SignIn(
new AuthenticationProperties
{
IsPersistent = isPersistent
},
userIdentity
);
}

Categories