In my Asp.Net MVC application users are coming from another system and I'm logging them in like below.
IAccount account = null;
if (userType == UserType.SystemUser)
account = _accountService.CheckSystemUser(userId);
if (userType == UserType.Employee)
account = _accountService.CheckEmployee(userId);
if (account == null) throw new Exception(ErrorMessages.UserNotFound);
var roles = account.Roles.ToArray();
var principalModel = new CustomPrincipalViewModel
{
UserId = account.UserId.ToString(),
FullName = account.FullName,
Roles = roles,
Language = account.Language
};
var userData = JsonConvert.SerializeObject(principalModel);
var ticket = new FormsAuthenticationTicket(1, principalModel.FullName, DateTime.Now, DateTime.Now.AddMinutes(30), false, userData);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
Response.Cookies.Add(cookie);
SetCulture(account.Language.CultureCode);
return Json(new { isSuccess = true, userFullName = account.FullName });
And setting current culture like this with SetCulture method.
private void SetCulture(string culture)
{
culture = CultureHelper.GetImplementedCulture(culture);
var cookie = Request.Cookies["_culture"];
if (cookie != null)
{
cookie.Value = culture;
cookie.Expires = DateTime.Now.AddYears(1);
}
else
{
cookie = new HttpCookie("_culture")
{
Value = culture,
Expires = DateTime.Now.AddYears(1)
};
}
Response.Cookies.Add(cookie);
}
And my view pages I'm setting text values from Resource files like below.
<span class="pageButton"> #Global.Cancel </span>
But when I change user language from other system and log in again to my system, all texts are still in previous language. After I refresh my page with ctrl+F5 everything looks in true language.
Is there a way to force to load page texts in new language without clearing cache manually ?
The problem in cookie var cookie = Request.Cookies["_culture"];, still keep old value, clean it when you logOff or when you try to log-In again
And you can use also Thread.CurrentThread to set culture
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
Related
I am trying to set a rememberMe cookie. It works however the domain it is being set to is using the subdomain as well as the main domain .... How can I set it to use just the main domain? I have tried rememberMeCookie.Domain = "MyNewDomain"; but then no cookie gets set.
I need the cookie to be set to the main domain in order for my rememberMe cookie to be read from another site as I am implementing a SSO procedure.
var rememberUrlSelection = Request.Cookies["rememberUrlSelection_" + Session["GuiId"]];
if (login.RememberMe || !login.RememberMe)
{
if (Request.Cookies["rememberMeWf"] == null)
{
HttpCookie rememberMeCookie = new HttpCookie("rememberMeWf");
var val = Newtonsoft.Json.JsonConvert.DeserializeObject<ApiResponse>(apiResp.Content);
string remC = Newtonsoft.Json.JsonConvert.SerializeObject(val.responseObject);
rememberMeCookie.Value = remC.UrlEncode();
rememberMeCookie.Expires = DateTime.Now.AddMonths(3);
rememberMeCookie.Domain = "MyNewDomain";
Response.Cookies.Add(rememberMeCookie);
}
}
You can try:-
cookie.Domain = Request.RequestUri.Host;
var rememberUrlSelection =
Request.Cookies["rememberUrlSelection_" + Session["GuiId"]];
if (login.RememberMe || !login.RememberMe) {
if (Request.Cookies["rememberMeWf"] == null) {
HttpCookie rememberMeCookie = new HttpCookie("rememberMeWf");
var val = Newtonsoft.Json.JsonConvert.DeserializeObject<ApiResponse>(
apiResp.Content);
string remC =
Newtonsoft.Json.JsonConvert.SerializeObject(val.responseObject);
rememberMeCookie.Value = remC.UrlEncode();
rememberMeCookie.Expires = DateTime.Now.AddMonths(3);
// rememberMeCookie.Domain = "MyNewDomain";
rememberMeCookie.Domain = Request.RequestUri.Host;
Response.Cookies.Add(rememberMeCookie);
}
}
**Edit: If anyone has any clue how i can better ask or inform you guys about this problem please let me know.
So I am creating custom claims and trying to add them to my user. I see the claims in the User.Identity right after I add them and slightly down the line in the pipeline but by the time it gets to my Global.asax the User.Identity has lost all but one of my claims. I also think the user is changing from a claimsPrinciapl to a GenericPrincipal during the same time. I dont know if I am understanding this or explaining this very well. Not even sure what all code to post but I will post some below.
This is where my user is Authenticated and cookies and claims are create. Note i have been trying a lot of stuff so this might have some weird code:
private AuthenticationResponse AuthenticateUserByService(string userName, string password, bool rememberMe)
{
Authenticator auth = new Authenticator(AppInfo.AuthServiceAddress, AppInfo.ClientId, AppInfo.Secret);
AppInfo.rememberMe = rememberMe;
AuthenticationResponse response = auth.Authenticate(userName, password);
if (response.IsError)
{
// MessageBox.Show(response.ErrorDescription);
return null;
}
if (response.AppUser == null)
{
//MessageBox.Show("No error or user! Unknown reason.");
return null;
}
var cookieHelper = new Helpers.CookieHelper();
//FormsAuthenticationTicket authtick = new FormsAuthenticationTicket(1, response.AppUser.Username, DateTime.Now, DateTime.Now.AddSeconds(response.AppUser.ExpiresIn *2), true, response.AppUser.RefreshToken);
var authtick = cookieHelper.CreateAuthTicket(response.AppUser, true);
var authCookie = cookieHelper.CreateAuthCookie(authtick);
Response.Cookies.Add(authCookie);
var tokenCookie = cookieHelper.CreateTokenCookie(response.AppUser, true);
Response.Cookies.Add(tokenCookie);
// If caching roles in userData field then extract
string[] roles = response.AppUser.Permissions.Select(x => x.PermissionName).ToArray(); // = authTicket.UserData.Split(new char[] { '|' });
// Create the IIdentity instance
IIdentity id = new FormsIdentity(authtick);
var newIdent = new ClaimsIdentity(id);
foreach (var item in roles)
{
newIdent.AddClaim(new Claim(ClaimTypes.Role, item));
}
ClaimsPrincipal cp = new ClaimsPrincipal(newIdent);
// Create the IPrinciple instance
IPrincipal principal = cp; //new GenericPrincipal(id, roles);
Thread.CurrentPrincipal = cp;
AppDomain.CurrentDomain.SetThreadPrincipal(cp);
// Set the context user
HttpContext.User = principal;
//IOwinContext context = Request.GetOwinContext();
//var authManager = context.Authentication;
//authManager.SignIn(newIdent);
this.AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = true }, newIdent);
return response;
In the above code, I can see my user and his claims right after I set the HttpContext.User.
Below is just me checking out the User to make sure it was successful:
private AppUser AuthenticateUser(string userName, string password, bool rememberMe)
{
//bool userAuthenticated = false;
AuthenticationResponse userAuthenticated = null;
bool success = false;
try
{
userAuthenticated = AuthenticateUserByService(userName, password, rememberMe);
var c = User.Identity;
success = !userAuthenticated.IsError;
}
catch { }
}
At one point the claims disappeared by the time I set c to the user.
And i figured this might be important so below is where i create my cookies and tickets:
internal class CookieHelper
{
internal FormsAuthenticationTicket CreateAuthTicket(AppUser appUser, bool isPersistent)
{
return new FormsAuthenticationTicket(
1,
appUser.Username,
DateTime.Now,
DateTime.Now.AddSeconds((appUser.ExpiresIn * 2)),
isPersistent,
appUser.RefreshToken == null ? "" : appUser.RefreshToken,
FormsAuthentication.FormsCookiePath);
}
internal HttpCookie CreateAuthCookie(FormsAuthenticationTicket authTicket)
{
// Encrypt the ticket.
string encAuthTicket = FormsAuthentication.Encrypt(authTicket);
// Create the cookie.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encAuthTicket);
authCookie.Expires = authTicket.Expiration;
return authCookie;
}
internal HttpCookie CreateTokenCookie(AppUser appUser, bool isPersistent)
{
// Create token ticket
FormsAuthenticationTicket tokenTicket = new FormsAuthenticationTicket(
1,
appUser.Username,
DateTime.Now,
DateTime.Now.AddSeconds(appUser.ExpiresIn),
isPersistent,
appUser.AccessToken);
// Encrypt the ticket.
string encTokenTicket = FormsAuthentication.Encrypt(tokenTicket);
// Create the cookie.
HttpCookie tokenCookie = new HttpCookie("Mellon", encTokenTicket);
tokenCookie.Secure = false;
tokenCookie.Name = "Mellon";
//tokenCookie.Path = Request.ApplicationPath;
tokenCookie.Expires = tokenTicket.Expiration;
return tokenCookie;
}
}
I feel like questions will need to be asked of me to get the right info for help. I am just lost and at this point my tunnel vision is killing me. Any insight or hints or jsut some love at this point would help. Thanks in advance.
Update
This is where I check if cookie is still valid and perform a refresh if its still valid.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
HttpCookie tokenCookie = Request.Cookies["Mellon"];
if (authCookie == null)
{
FormsAuthentication.SignOut();
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
return;
}
// Extract the forms authentication cookie
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket == null || authTicket.Expired)
{
FormsAuthentication.SignOut();
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
return;
}
// Extract the forms authentication cookie
//FormsAuthenticationTicket newAuthTicket;
if (tokenCookie == null)
{
RefreshCookies(authTicket);
return;
}
else
{
FormsAuthenticationTicket tokenTicket = FormsAuthentication.Decrypt(tokenCookie.Value);
// If the access token is stil good, then continue on.
if (tokenTicket.Expired)
{
RefreshCookies(authTicket);
return;
}
}
var tick = (FormsIdentity)HttpContext.Current.User.Identity;
if (tick == null)
{
FormsAuthentication.SignOut();
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity(string.Empty), null);
return;
}
if (authTicket.UserData != tick.Ticket.UserData) // .Ticket.UserData)
{
RefreshCookies(authTicket);
}
}
Basically what I have is my AuthToken which holds me refresh token and a second cookie that holds me AccessToken. Those are created in the AuthenticateUserByService method which gets all that info from our webapi and is returned in response.AppUser. So I can't use forms.setauthcookie because that would overwrite what is already in there.
Image proof of whats going on:
As I said in my comment, it's rather tough to digest the snippets you have posted, So I'll break down into smaller logical chunks.
Let's start of with an Authentication Service Class:
Authentication Service calls the client repository and returns a User
public class AuthenticationService
{
IUserRepository _userRepo;
public AuthenticationService()
{
_userRepo = new UserRepository();
}
public User GetUser(string username, string password)
{
return _userRepo.FindByCredentials(username, password);
}
public User GetUserByUserName(string username)
{
return _userRepo.FindByUserName(username);
}
}
In the Global.asax we need to authenticate with pre-flight request.
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
//Check the request for a cookie
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
//Decrypt the Auth Cookie vale
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
//Instantiate Auth Service
var _authService = new AuthenticationService();
//Get user by encrypted name stored in ticket
var user = _authService.GetUserByUserName(ticket.Name);
if (user != null)
{
// Create a ClaimsIdentity with all the claims for this user.
Claim emailClaim = new Claim("Email", (!string.IsNullOrWhiteSpace(user.Email)) ? user.Email: "");
Claim AddressClaim = new Claim("Address", (!string.IsNullOrWhiteSpace(user.Address)) ? user.Address: "");
Claim userNameClaim = new Claim(ClaimTypes.Name, (!string.IsNullOrWhiteSpace(user.Username)) ? user.Username : "");
//Add claims to a collection of claims
List<Claim> claims = new List<Claim>
{
emailClaim ,
AddressClaim ,
userNameClaim
};
//Create forms Identity
FormsIdentity formsIdentity = new FormsIdentity(ticket);
//Create Claims Identity
ClaimsIdentity claimsIdentity = new ClaimsIdentity(formsIdentity);
//Add Claims
claimsIdentity.AddClaims(claims);
//Create Claims Principal
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
//Assign principal to current user
HttpContext.Current.User = claimsPrincipal;
}
}
}
Login Controller:
[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginModel model)
{
if (ModelState.IsValid)
{
var user = _authService.GetUser(model.UserName, model.password);
if (user != null)
{
FormsAuthentication.SetAuthCookie(model.UserName,model.RememberMe);
return Redirect(model.ReturnUrl); }
}
}
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
As I've said this is a naïve attempt, please consider a little more security, but this is working sln I've quickly put together and I can access the claims.
Having looked at your code, it feels that your just missing adding the Claims of the user.
Basically what is happening is the claims are getting overwritten in my global.asax. My fix so far has been to just rebuild my claims in my global.asax.
I am authenticating a user:
[Route("Login"), HttpPost, AllowAnonymous]
public LoginViewModelResponse Login(LoginViewModelRequest data)
{
if(!Membership.ValidateUser(data.Username, data.Password))
{
return new LoginViewModelResponse
{
DisplayMessage = "Invalid Username/Password!",
IsSuccess = false,
RedirectUrl = "/Home/"
};
}
FormsAuthentication.SetAuthCookie(data.Username, false);
ClaimsIdentity identity = new GenericIdentity(data.Username);
var roles = "Administrator,User".Split(',');
// var client = AuthorisationService.instance.GetAuthenticatedUser();// new ClientService().GetClientById(1);
var principle = new GenericPrincipal(identity, roles);
HttpContext.Current.User = principle;
System.Threading.Thread.CurrentPrincipal = principle;
if (User.IsInRole("Administrator"))
{
var b = 1;
}
return new LoginViewModelResponse
{
IsSuccess = true,
DisplayMessage = "OK",
RedirectUrl = "/Home/"
};
}
And the test for 'IsInRole' is working.
However, I have the following in my View (_layout), and the check for Administrator fails.
if (ViewContext.HttpContext.User.IsInRole("Administrator"))
{
<li class="dropdown">
...
Is there something I need to do to allow the View to understand "IsInRole"?
This works:
#if (ViewContext.HttpContext.User.Identity.IsAuthenticated == false)
But 'IsInRole' always evaluated to false.
Since you set FormsAuthentication cookie by yourself, you'll need to create Principle object and assign it to current thread on every request inside AuthenticateRequest event.
Global.asax.cs
public class Global : HttpApplication
{
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
HttpCookie decryptedCookie =
Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (decryptedCookie != null)
{
FormsAuthenticationTicket ticket =
FormsAuthentication.Decrypt(decryptedCookie.Value);
var identity = new GenericIdentity(ticket.Name);
var roles = ticket.UserData.Split(',');
var principal = new GenericPrincipal(identity, roles);
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = HttpContext.Current.User;
}
}
}
Sign-In method
public void SignIn(string username, bool createPersistentCookie)
{
var now = DateTime.UtcNow.ToLocalTime();
TimeSpan expirationTimeSpan = FormsAuthentication.Timeout;
var ticket = new FormsAuthenticationTicket(
1 /*version*/,
username,
now,
now.Add(expirationTimeSpan),
createPersistentCookie,
"" /*userData*/,
FormsAuthentication.FormsCookiePath);
var encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket)
{
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
Path = FormsAuthentication.FormsCookiePath
};
if (ticket.IsPersistent)
{
cookie.Expires = ticket.Expiration;
}
if (FormsAuthentication.CookieDomain != null)
{
cookie.Domain = FormsAuthentication.CookieDomain;
}
Response.Cookies.Add(cookie);
}
I want to make login and logOut functions in mvc4. In login func, if login cookie exist and not empty, user is in signIn mode, else redirect to login page.
In logOut func, all cookies and sessions clear and redirect to login func, but in login func login cookie exist!
Login:
public ActionResult Login()
{
if (Request.Cookies["login"] != null)
{
string login = Request.Cookies["login"].Value.ToString();
if (login != string.Empty)
{
//Get from service
Service srv = new Service();
UserItem userItem = srv.getUserItem(login);
srv.Close();
Session.Timeout = 30;
Session["login "] = login;
Session["userId"] = userItem.No;
Session["firstName"] = userItem.FirstName;
Session["lastName"] = userItem.LastName;
string loginName = userItem.LoginName;
FormsAuthentication.SetAuthCookie(loginName, false);
return Redirect(“Index”);
}
else
{
Return redirect("http://mySite/SignIn.aspx");
}
}
else
{
Return redirect("http://mySite/SignIn.aspx");
}
}
LogOut:
public ActionResult LogOut()
{
string login = Session["login"].ToString();
Request.Cookies["login"].Value = "";
Response.Cookies["login"].Value = "";
FormsAuthentication.SignOut();
HttpCookie c = Request.Cookies[FormsAuthentication.FormsCookieName];
c.Expires = DateTime.Now.AddDays(-1);
Session.Clear();
Request.Cookies.Clear();
Response.Cookies.Clear();
//FormsAuthentication.Initialize();
//string strRole = String.Empty;
//FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, "", DateTime.Now, DateTime.Now.AddMinutes(-30), false, strRole, FormsAuthentication.FormsCookiePath);
//Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(fat)));
//Session.Abandon();
//// clear authentication cookie
//HttpCookie cookie1 = new HttpCookie(FormsAuthentication.FormsCookieName, "");
//cookie1.Expires = DateTime.Now.AddYears(-1);
//Response.Cookies.Add(cookie1);
//// clear session cookie (not necessary for your current problem but i would recommend you do it anyway)
//HttpCookie cookie2 = new HttpCookie("ASP.NET_SessionId", "");
//cookie2.Expires = DateTime.Now.AddYears(-1);
//Response.Cookies.Add(cookie2);
//FormsAuthentication.RedirectToLoginPage();
return RedirectToAction("Login", "Usr");
}
Web.config:
<authentication mode="Forms">
<forms loginUrl="~/Usr/Login" timeout="30" />
</authentication>
I am trying comment codes, even comment this line:
FormsAuthentication.SignOut();
Even I set the cookie value to "", but in login page this cookie have old value!
And trying several ways to clear cookie like set expire to one day later. But…
Thanks
You're changing the value of the cookie, but you're not adding it to the response again!
FormsAuthentication.SignOut();
HttpCookie c = Request.Cookies[FormsAuthentication.FormsCookieName];
c.Expires = DateTime.Now.AddDays(-1);
// Update the amended cookie!
Response.Cookies.Set(c)
Session.Clear();
/* Get rid of this, it will break the above by clearing
* the cookie collection that you've just updated. */
// Request.Cookies.Clear();
// Response.Cookies.Clear();
There is a much easier way to determine if the user is authenticated, as per this post
How to check if user is authorized inside Action
After you have called the FormsAuthentication.SetAuthCookie(), you can call User.Identity.IsAuthenticated. No need to set your own cookies.
If you do it like this, the FormsAuthentication.SignOut() will destroy the correct cookie
Thank you AndreyMaybe, Ant P
This code work:
Response.Cookies.Clear();
FormsAuthentication.SignOut();
HttpCookie c = new HttpCookie("login");
c.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(c);
Session.Clear();
I have an interesting problem where I have hit a brick wall. I have an issue with a login page which implements forms authentication and uses Intellegencia.Rewriter. The authentication works fine on localhost for all browsers, but on the server it appears that the postback nature of the page is lost in IE9, yet works fine in Chrome. The code I have on the Login page is:
bool isAuthenticated = Membership.ValidateUser(username, password);
string returnUrl = Server.HtmlDecode(Request["ReturnUrl"]);
lblLoggedIn.Text = Page.IsPostBack.ToString();
if (isAuthenticated &&
Thread.CurrentPrincipal.Identity.Name == "")
{
HttpContext.Current.User = AuthenticateUserIfValid(username);
Thread.CurrentPrincipal = HttpContext.Current.User;
}
Where the Function AuthenticateUserIfValid is:
public Principal.GenericPrincipal AuthenticateUserIfValid(string username)
{
MembershipUser mpc = Membership.FindUsersByName(username)[username];
string[] roles = Roles.GetRolesForUser(mpc.UserName);
string strRoles = "";
foreach (string role in roles)
strRoles += strRoles != "" ? "," + role : role;
FormsAuthenticationTicket fat =
new FormsAuthenticationTicket(1, mpc.UserName.ToString(),
DateTime.Now,
DateTime.Now.AddMinutes(30),
true,
strRoles,
FormsAuthentication.FormsCookiePath);
Response.Cookies.Add(
new HttpCookie(FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(fat)));
Response.Cookies.Add(new HttpCookie("UserRoles", strRoles));
Principal.GenericPrincipal myPrincipal;
Principal.GenericIdentity myIdentity =
new Principal.GenericIdentity(mpc.UserName);
myPrincipal = new Principal.GenericPrincipal(myIdentity, roles);
return myPrincipal;
}
Any thoughts or solutions would be most appreciated. Regards,
MD