Using FormsAuthentication, I am creating a FormsAuthenticationTicket, encrypting, adding this to a cookie using Response.Cookies.Add(authCookie). I then do a redirect using Response.Redirect to the original page that was requested. There is code in the Global.asax in the Application_AuthenticateRequest method that looks to retrieve the cookie - HttpCookie authCookie = Context.Request.Cookies[cookieName]. For some reason, however, when it hits the Global.asax code after the redirect is called, there are no cookies in the collection. At this point, I am a bit stumped as to why it is losing the cookie from the collection. Any thoughts as to why this would happen? Right now, I am just working within localhost.
Login Page Code:
string adPath = "LDAP://ldapserveraddress";
LdapAuthentication adAuth = new LdapAuthentication(adPath);
try
{
if (true == adAuth.IsAuthenticated("ES", txtUsername.Text, txtPassword.Text))
{
string groups = adAuth.GetGroups();
//Create the ticket, and add the groups.
bool isCookiePersistent = chkPersist.Checked;
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
txtUsername.Text, DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
//Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
//Create a cookie, and then add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
if (true == isCookiePersistent)
authCookie.Expires = authTicket.Expiration;
//Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
string redirect = FormsAuthentication.GetRedirectUrl(txtUsername.Text, false);
//You can redirect now.
Response.Redirect(redirect,false);
}
else
{
errorLabel.Text = "Authentication did not succeed. Check user name and password.";
}
}
catch (Exception ex)
{
errorLabel.Text = "Error authenticating. " + ex.Message;
}
}
Global.asax Code (Application_AuthenticateRequest):
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if (null == authCookie)
{
//There is no authentication cookie.
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch (Exception ex)
{
//Write the exception to the Event Log.
return;
}
if (null == authTicket)
{
//Cookie failed to decrypt.
return;
}
//When the ticket was created, the UserData property was assigned a
//pipe-delimited string of group names.
string[] groups = authTicket.UserData.Split(new char[] { '|' });
//Create an Identity.
GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
//This principal flows throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);
Context.User = principal;
}`
I was able to resolve my issue by adjusting the data that was being stored in the userData of the FormsAuthenticationTicket. It appears as though the amount of data that I was trying to insert exceeded a maximum. Once I removed, everything works as expected.
Related
Here is my code about Authentication and Authorization
public class SessionContext
{
public void setAuthenticationToken(UserAccount userAccount,bool isPersistant,string name)
{
string data = new JavaScriptSerializer().Serialize(userAccount.Roles);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,name,DateTime.Now,DateTime.Now.AddYears(1),isPersistant,data);
var encryptedCookieData = FormsAuthentication.Encrypt(ticket);
HttpCookie httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookieData) { HttpOnly=true,Expires=ticket.Expiration };
HttpContext.Current.Response.Cookies.Add(httpCookie);
}
}
My Global.asax has this method:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(new Char[] { ',' });
GenericPrincipal userPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), roles);
HttpContext.Current.User = userPrincipal;
Debug.WriteLine(roles.FirstOrDefault() +" "+ userPrincipal.IsInRole("Admin"));
}
}
But when I using [Authorize(Roles="Admin")] authorizing not working.
I tried these solutions but didn't work:
I used [CustomAthorize(Roles="Admin")] that explained in StackOverflow
I used Thread.CurrentPrincipal=userPrincipal
Notice: As you can see I added Debug.WriteLine() in my Global.asax to show me userPrincipal role state but always returns false.
Notice: If you can , show me another way to use Authorization and Authentication that not based on OWIN
I realized the problem is in saving role name to HttpContext it was saving role name with "" in while it have to save without ""
**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 trying to traverse our ldap path at the min obv dont want to share live details but here is some code I think i may have to loop our ou groups as they are in differernt folders when i look at the nodes, would any have idea how I would loop the ou groups using the below code I have already created.
string logintype = rbAuthenticationType.SelectedItem.Value.ToString();
if (logintype == "Domain")
{
string adPath = "LDAP://ipaddress/DC=companynamee"; //Path to your LDAP directory server
LdapAuthentication adAuth = new LdapAuthentication(adPath);
try
{
if (true == adAuth.IsAuthenticated(txtDomain.Text, txtUserName.Text, txtPassword.Text))
{
string groups = adAuth.GetGroups();
//Create the ticket, and add the groups.
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
txtUserName.Text, DateTime.Now, DateTime.Now.AddMinutes(60), chkRememberMe.Checked, groups);
//Encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
//Create a cookie, and then add the encrypted ticket to the cookie as data.
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
//Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
//You can redirect now.
Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUserName.Text, false));
}
else
{
lblerror.Text = "Authentication did not succeed. Check user name and password.";
}
}
catch (Exception ex)
{
lblerror.Text = "Error authenticating. " + ex.Message;
}
}
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'm building a web application using the default master template in VS2010 - very new to doing this. I'm also using the Login.aspx page, but instead of using the built in user validation, my user info is in a database table. So Following instructions I found, I'm doing something wery similar to this:
protected void Login1_Authenticate(object sender, AuthenticateEventArgs e)
{
Boolean bauthenticated = false;
bauthenticated = isValidUser(Login1.UserName, Login1.Password);
if (bauthenticated)
{
e.Authenticated = true;
}
else
{
e.Authenticated = false;
}
}
The problem is that I put the method isValidUser in a .dll so it could be used elsewhere, and it is not receiving the password because the default behaivor is to blank it out. I even tried to set a string variable to Login1.Password, and pass the variable without success. I understand why this is happening, but can't find any info as to how to do this correctly. Do I need to put the user name and password into an object and pass that to my class constructor? I really don't want to connect to my database from every Login.aspx page I create to avoid sending the password over http.
Try to use the following code.
protected void LoginButton_Click(object sender, EventArgs e)
{
try
{
dtUserDetails = new DataTable();
if (UserRepositoryBL.ValidateUser(LoginUser.UserName.Trim(), LoginUser.Password.Trim(), out dtUserDetails))
{
AuthUser au = new AuthUser();
if (dtUserDetails.Rows.Count > 0)
{
DataRow DR = dtUserDetails.Rows[0];
au.UserID = Convert.ToInt32(DR["UserID"].ToString());
au.UserNo = DR["UserNo"].ToString();
au.UserName = DR["UserName"].ToString();
au.Password = DR["Password"].ToString();
}
string userData = au.ToString();
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Version number
LoginUser.UserName.Trim(), // Username
DateTime.Now, // Issue date
DateTime.Now.AddMinutes(60), // Expiration date
false, // Persistent?
userData // User data
);
string eticket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie
(FormsAuthentication.FormsCookieName, eticket);
Response.Cookies.Add(cookie);
BasePage.ActivityLog("User Login", LoginUser.UserName.Trim(), true, Request.RawUrl);
string url = FormsAuthentication.GetRedirectUrl(LoginUser.UserName, false);
Response.Redirect(url);
// FormsAuthentication.RedirectFromLoginPage(LoginUser.UserName, false);
}
else
{
LoginUser.FailureText = "Your login attempt was not successful. Please try again.";
}
}
catch (Exception ex)
{
throw ex;
}
}
dtUserDetails is a out parameter which contains the user details like password,username,etc.. on successful login.datatable returns empty if invalid login.with in userData string all those information will be available.then u can retrieve those from any page using User Authenticated Ticket