How to get forms authentication ticket to respecting cookie expiration date - asp.net-mvc

I am having an issue where users of my website login sessions are expiring way before it should.
Here is my login method”
public ActionResult Login(LoginModel model, string returnUrl)
{
var mcookie = new MyCompanyCookie();
if (ModelState.IsValid)
{
using (var myRepo = new MyCompanyRepositry())
{
var passwordHash = MyCompany.Web.Portal.Helpers.Security.CreatePasswordHash(model.Password);
var userAccount = myRepo.GetMyCompanyUser(model.UserName,model.PartnerAccessCode);
if(userAccount != null && userAccount.Password == passwordHash && userAccount.PartnerAccessCode == model.PartnerAccessCode.ToUpper())
{
mcookie.GetMMformsauthentication(userAccount, model.RememberMe);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "The user name,access code or password provided is incorrect.");
}
}
And forms authentication ticket:
public void GetMMformsauthentication(UserAccount useraccount, bool createPersistentCookie)
{
const string UnknownUsername = "anonymous";
// Composing UserData to be stored in the auth cookie
var userCookieData = new MarvMentUserCookieData()
{
UserId = useraccount.UserID,
Password = useraccount.Password,
PartnerAccessCode = useraccount.PartnerAccessCode
};
var ticket = new FormsAuthenticationTicket(1, string.IsNullOrEmpty(useraccount.UserID) ? UnknownUsername : useraccount.UserID, DateTime.Now,
DateTime.Now.AddDays(100), createPersistentCookie, userCookieData.ToString(), FormsAuthentication.FormsCookiePath);
var hashedCookie = FormsAuthentication.Encrypt(ticket);
HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashedCookie); // Hashed ticket
authCookie.HttpOnly = true;
authCookie.Expires = ticket.Expiration;
authCookie.Path = ticket.CookiePath;
authCookie.Secure = false;
HttpContext.Current.Response.SetCookie(authCookie);
}
}
And expiration settings inmy Web.config
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
Here you can see that the forms expiration settings is set 2880 minutes however users are beign logged out after around 5-10 minutes.
The cookie is set to expire in 100 days
Does anyone have and idea what may be causing this issue?

It looks issue is not with session in authentication tag. Just check what happens if cookies stuff is commented... If Session retained for more time, then focus on cookie stuff.

Related

How to maintain a Id value throughout my Asp.net MVC application session management

How to maintain a Id value throughout my Asp.net MVC application after login -- Persist ID throughout ASP.NET MVC application?
I tried using session variable like this in login controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LoginPage(UserLogin login)
{
else if (string.Compare(CryptoCode.Hash(login.Password), v.PPassword) == 0)
{
int timeout = login.RememberMe ? 60 : 60; // 525600 min = 1 year
var ticket = new FormsAuthenticationTicket(login.EmailID, login.RememberMe, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = DateTime.Now.AddMinutes(timeout);
cookie.HttpOnly = true;
Response.Cookies.Add(cookie);
var profile = db.Profile.Where(x => x.UserLoginId == v.UserLoginId).FirstOrDefault();
Session["PId"] = profile.PId;
if (Url.IsLocalUrl(login.ReturnUrl))
{
return Redirect(login.ReturnUrl);
}
else
{
return Redirect("/ProfilePage/fileupload/index");
}
}
In my Another Controller top level
public ActionResult MainPage()
{
if (Session["PId"] != null)
{
Int64 pid = (Int64)System.Web.HttpContext.Current.Session["PId"];
......
......
}
else
{
return View("~/Registration/Registration/loginpage");
}
}
In web.config file
<authentication mode="Forms">
<forms cookieless="UseCookies" loginUrl="~/Registration/loginpage" timeout="60" slidingExpiration="true"></forms>
</authentication>
<sessionState mode="InProc" timeout="60"></sessionState>
when i close browser the session value getting null but my session login is active, so i get null reference exception or pid null.
In my application i have many controllers that have many action methods. i am not interested to check if condition session value in every action method.
How to maintain a session value after browser close and reopen in given timeout in session (like 20 min)?

Implement Active Directory login in an existing ASP.NET MVC 4.6 web project

I have to change the existing (Windows) login for my ASP.NET MVC + Knockout application with Active Directory authentication.
It consists of mvc controllers and webapi controllers. Both have to be authenticated.
I thought I would do this by changing to forms authentication and create a login page and when the users clicks login, query Active Directory with the System.DirectoryServices.DirectoryEntry.
Then the other processes like change password, register etc. would also get a custom html page and do their actions via the System.DirectoryServices.DirectoryEntry on our Active Directory.
(that is, I could not find any other way that people would do it, and I did find some who would do it like this, and it sounds the same like previous forms authentications I've seen. In this case the user/passwords would not be in a database table but in Active Directory. Same idea, swap database table by active directory).
To see how this would be on a brandnew project, I created a new ASP.NET MVC project and choose 'work- or school acounts' (which says 'for applications that authenticate users with active directory) and choose 'on premise'.
However, then I have to provide these items:
on-premises authority
app Id url
I don't know what to do with that. The only thing I have is an active directory url like ldap://etc..
Is this another/newer/better way of doing active directory login? Or the only right one (is forms authentication wrong?) or the wrong one?
I'm confused.
You can use the following approach in order to implement Active Directory Authentication in ASP.NET MVC.
Step 1: Modify the Login methods in the AccountController as shown below (also add the necessary references):
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
try
{
if (!ModelState.IsValid)
{
return View(model);
}
// Check if the User exists in LDAP
if (Membership.GetUser(model.UserName) == null)
{
ModelState.AddModelError("", "Wrong username or password");
return this.View(model);
}
ApplicationGroupManager groupManager = new ApplicationGroupManager();
// Validate the user using LDAP
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
// FormsAuthentication.SetAuthCookie(model.UserName, false);
// Check if the User exists in the ASP.NET Identity table (AspNetUsers)
string userName = model.UserName.ToString().ToLower(new CultureInfo("en-US", false)); // When UserName is entered in uppercase containing "I", the user cannot be found in LDAP
//ApplicationUser user = UserManager.FindByName(userName);
ApplicationUser user = await UserManager.FindByNameAsync(userName); //Asynchronous method
if (user == null) // If the User DOES NOT exists in the ASP.NET Identity table (AspNetUsers)
{
// Create a new user using the User data retrieved from LDAP
// Create an array of properties that we would like and add them to the search object
string[] requiredProperties = new string[] { "samaccountname", "givenname", "sn", "mail", "physicalDeliveryOfficeName", "title" };
var userInfo = CreateDirectoryEntry(model.UserName, requiredProperties);
user = new ApplicationUser();
// For more information about "User Attributes - Inside Active Directory" : http://www.kouti.com/tables/userattributes.htm
user.UserName = userInfo.GetDirectoryEntry().Properties["samaccountname"].Value.ToString();
user.Name = userInfo.GetDirectoryEntry().Properties["givenname"].Value.ToString();
user.Surname = userInfo.GetDirectoryEntry().Properties["sn"].Value.ToString();
user.Email = userInfo.GetDirectoryEntry().Properties["mail"].Value.ToString();
user.EmailConfirmed = true;
//user.PasswordHash = null;
//user.Department = GetDepartmentId(userInfo.GetDirectoryEntry().Properties["physicalDeliveryOfficeName"].Value.ToString());
//await Register(user);
var result = await UserManager.CreateAsync(user); //Asynchronous method
//If the User has succesfully been created
//if (result.Succeeded)
//{
// //var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// //await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link");
// //ViewBag.Link = callbackUrl;
// //return View("DisplayEmail");
//}
// Define user group (and roles)
var defaultGroup = "751b30d7-80be-4b3e-bfdb-3ff8c13be05e"; // Id of the ApplicationGroup for the Default roles
//groupManager.SetUserGroups(newUser.Id, new string[] { defaultGroup });
await groupManager.SetUserGroupsAsync(user.Id, new string[] { defaultGroup }); //Asynchronous method
//groupManager.SetGroupRoles(newGroup.Id, new string[] { role.Name });
}
// !!! THERE IS NO NEED TO ASSIGN ROLES AS IT IS ASSIGNED AUTOMATICALLY IN ASP.NET Identity 2.0
//else // If the User exists in the ASP.NET Identity table (AspNetUsers)
//{
// //##################### Some useful ASP.NET Identity 2.0 methods (for Info) #####################
// //ApplicationGroupManager gm = new ApplicationGroupManager();
// //string roleName = RoleManager.FindById("").Name; // Returns Role Name by using Role Id parameter
// //var userGroupRoles = gm.GetUserGroupRoles(""); // Returns Group Id and Role Id by using User Id parameter
// //var groupRoles = gm.GetGroupRoles(""); // Returns Group Roles by using Group Id parameter
// //string[] groupRoleNames = groupRoles.Select(p => p.Name).ToArray(); // Assing Group Role Names to a string array
// //###############################################################################################
// // Assign Default ApplicationGroupRoles to the User
// // As the default roles are already defined to the User after the first login to the system, there is no need to check if the role is NULL (otherwise it must be checked!!!)
// //var groupRoles = groupManager.GetGroupRoles("751b30d7-80be-4b3e-bfdb-3ff8c13be05e"); // Returns Group Roles by using Group Id parameter
// var groupRoles = await groupManager.GetGroupRolesAsync("751b30d7-80be-4b3e-bfdb-3ff8c13be05e"); // Returns Group Roles by using Group Id parameter (Asynchronous method)
// foreach (var role in groupRoles)
// {
// //Assign ApplicationGroupRoles to the User
// string roleName = RoleManager.FindById(role.Id).Name;
// UserManager.AddToRole(user.Id, roleName);
// }
//}
//Sign in the user
await SignInAsync(user, model.RememberMe);
if (this.Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return this.Redirect(returnUrl);
//return RedirectToLocal(returnUrl);
}
return this.RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "Wrong username or password");
return this.View(model);
}
}
catch (Exception ex)
{
TempData["ErrorMessage"] = ex.Message.ToString();
return View("Error", TempData["ErrorMessage"]);
}
}
/* Since ASP.NET Identity and OWIN Cookie Authentication are claims-based system, the framework requires the app to generate a ClaimsIdentity for the user.
ClaimsIdentity has information about all the claims for the user, such as what roles the user belongs to. You can also add more claims for the user at this stage.
The highlighted code below in the SignInAsync method signs in the user by using the AuthenticationManager from OWIN and calling SignIn and passing in the ClaimsIdentity. */
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
static SearchResult CreateDirectoryEntry(string sAMAccountName, string[] requiredProperties)
{
DirectoryEntry ldapConnection = null;
try
{
// Create LDAP connection object
//ldapConnection = new DirectoryEntry("alpha.company.com");
ldapConnection = new DirectoryEntry("LDAP://OU=Company_Infrastructure, DC=company, DC=mydomain", "******", "******");
//ldapConnection.Path = connectionPath;
ldapConnection.AuthenticationType = AuthenticationTypes.Secure;
DirectorySearcher search = new DirectorySearcher(ldapConnection);
search.Filter = String.Format("(sAMAccountName={0})", sAMAccountName);
foreach (String property in requiredProperties)
search.PropertiesToLoad.Add(property);
SearchResult result = search.FindOne();
//SearchResultCollection searchResultCollection = search.FindAll();
if (result != null)
{
//foreach (String property in requiredProperties)
// foreach (Object myCollection in result.Properties[property])
// Console.WriteLine(String.Format("{0,-20} : {1}",
// property, myCollection.ToString()));
// return searchResultCollection;
return result;
}
else
{
return null;
//Console.WriteLine("User not found!");
}
//return ldapConnection;
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return null;
}
Note: In order to force signout in LDAP authentication, add FormsAuthentication.SignOut() line to the LogOff() method as shown below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
FormsAuthentication.SignOut(); //In order to force logout in LDAP authentication
return RedirectToAction("Login", "Account");
}
Step 2: Update your LoginViewModel (or whatever your Account model class is named) to contain only this LoginModel class:
public class LoginViewModel
{
[Required]
public string UserName { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool RememberMe { get; set; }
}
On the other hand, add the custom properties i.e. Name, Surname, UserName, Department, etc. to the necessary model i.e. ApplicationUser, RegisterViewModel.
Step 3: Finally, update your Web.config file to include these elements:
<connectionStrings>
<!-- for LDAP -->
<add name="ADConnectionString" connectionString="LDAP://**.**.***:000/DC=abc,DC=xyz" />
</connectionStrings>
<system.web>
<!-- For LDAP -->
<httpCookies httpOnlyCookies="true" />
<authentication mode="Forms">
<forms name=".ADAuthCookie" loginUrl="~/Account/Login" timeout="30" slidingExpiration="true" protection="All" />
</authentication>
<membership defaultProvider="ADMembershipProvider">
<providers>
<clear />
<add name="ADMembershipProvider" type="System.Web.Security.ActiveDirectoryMembershipProvider" connectionStringName="ADConnectionString" attributeMapUsername="sAMAccountName" connectionUsername="******" connectionPassword="******" />
</providers>
</membership>
...
</system.web>
Update: Here is the ApplicationUser class used in the example:
// Must be expressed in terms of our custom Role and other types:
public class ApplicationUser : IdentityUser<int, ApplicationUserLogin,
ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
public string Name { get; set; }
public string Surname { get; set; }
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
{
var userIdentity = await manager
.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
}
I have used Active Directory Authetication at work.
I created application MVC with Windows Authetication and it was done. Application automatically displays AD login with domain.
Choose membership: [Authorize(Roles=#"DomainName\GroupName")]
Ye can see domain and groups in cmd: net user Username /domain
You haven't to use LDAP.
With LDAP see:
see here
i have a mixed system running. Users from a Database (external users) mixed with AD users (internal users) that can login to our system. to communicate with the AD i use a nuget package called LinqToLdap (https://github.com/madhatter22/LinqToLdap). this uses the LDAP protocol so it can be used for authenticating against Unix Ldap servers also.
this is the Authentication method
public bool AuthenticateUser(string userName, string password)
{
InitConfig();
using (var context = new DirectoryContext(_config))
{
var user = context.Query<LdapUserInfo>().FirstOrDefault(x => x.UserPrincipalName.Equals(userName));
var dn = user?.DistinguishedName;
if (string.IsNullOrWhiteSpace(dn))
return false;
using (var ldap = new LdapConnection(new LdapDirectoryIdentifier(_myConfig.Server)))
{
ldap.SessionOptions.ProtocolVersion = 3;
ldap.AuthType = AuthType.Basic;
ldap.Credential = _credentials;
ldap.Bind();
try
{
ldap.AuthType = AuthType.Basic;
ldap.Bind(new NetworkCredential(dn, password));
return true;
}
catch (DirectoryOperationException)
{ }
catch (LdapException)
{ }
}
return false;
}
}
private void InitConfig()
{
if (_config != null)
return;
_config = new LdapConfiguration();
_credentials = new NetworkCredential(_myConfig.Username, _myConfig.Password, _myConfig.Domain);
_config.AddMapping(new AutoClassMap<LdapGroupInfo>(), _myConfig.NamingContext, new[] { "*" });
_config.AddMapping(new AutoClassMap<LdapUserInfo>(), _myConfig.NamingContext, new[] { "*" });
_config.ConfigureFactory(_myConfig.Server).AuthenticateAs(_credentials).AuthenticateBy(AuthType.Basic);
}

asp.net mvc form authenticate lose cookie session

asp.net mvc project when publish, it always lose session after 15-20 minutes.
my global.asax
enter code protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
}
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (authTicket != null && !authTicket.Expired)
{
var roles = authTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authTicket), roles);
}
}
}
Login Method :
//clear any other tickets that are already in the response
Response.Cookies.Clear();
//set the new expiry date - to thirty days from now
DateTime expiryDate = DateTime.Now.AddDays(30);
//create a new forms auth ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, login.EmailID, DateTime.Now, expiryDate, true, "Kullanici Bilgisi");
//encrypt the ticket
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
//create a new authentication cookie - and set its expiration date
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authenticationCookie.Expires = ticket.Expiration;
authenticationCookie.HttpOnly = true;
//add the cookie to the response.
Response.Cookies.Add(authenticationCookie);
Please help me. Im control on google developer tools. I see timeout 2018 but session is always losing redirect to login page.
Web Config:
<authentication mode="Forms">
<forms cookieless="UseCookies" loginUrl="~/user/login" slidingExpiration="true"></forms>
</authentication>

FormsAuthentication and Ajax Requests

I have a problem knowing whether a user is authenticated or not when ajax requests are sent from jQuery.
HttpContext.User.Identity is not empty when a user does a regular request from their browser and the aspxauth cookie is set. When a user tries doing a ajax request from jQuery, the aspxauth is not set at all.
My Web.Config
<authentication mode="Forms">
<forms loginUrl="~/" />
</authentication>
Setting the FormsAuthentication Cookie
var cookie = new AuthCookie
{
UserId = user.UserId,
Email = user.Email,
Name = user.Name,
RememberMe = createPersistentCookie,
TimeZone = user.TimeZone,
CompanyId = user.CompanyId,
Roles = new List<string> { user.Role ?? "user" }
};
string userData = JsonConvert.SerializeObject(cookie);
var ticket = new FormsAuthenticationTicket(1, cookie.Email, DateTime.Now,
DateTime.Now.Add(FormsAuthentication.Timeout),
createPersistentCookie, userData);
string encTicket = FormsAuthentication.Encrypt(ticket);
var httpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = DateTime.Now.Add(FormsAuthentication.Timeout) };
_httpContext.Response.Cookies.Add(httpCookie);
When I make requests through my broser, the auth cookie appears:
Whenever I make a request through javascript using $.get() or loading javascript scripts / Any other request through javascript, I get:
The odd thing is that on another ASP application I am using WebSecurity and that works perfectly. The auth cookie is always being sent back from client to server. For this ASP MVC 5 application, when I try to use the FormAuthentication, I cannot get the AuthCookie to proceed through all requests.
you are still able to decorate your class/method with [Authorize] and the like. If you're looking to check inside the controller method you have access to the User Property inherited from System.Web.Mvc.Controller or System.Web.Http.ApiController depending on your controller flavor :
//
// Summary:
// Returns the current principal associated with this request.
//
// Returns:
// The current principal associated with this request.
public IPrincipal User { get; set; }
it can be used like so:
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
// user has access - process request
}
Edit:
Here is an example of an [Api]Controller with an ajax[able] method that uses the controller's User property instead of HttpContext's:
public class HelloController : ApiController
{
[HttpGet]
public IHttpActionResult HelloWorld()
{
try
{
if (User != null && User.Identity != null && User.Identity.IsAuthenticated)
{
return Ok("Hello There " + User.Identity.Name + "!");
}
else
{
return Ok("Hello There Anonymous!");
}
}
catch { throw; }
}
}

asp.net mvc authentication cookie issue

I'm trying to implement a "remember me" feature using ASP.NET MVC. It uses a customized authentication process as defined below.
Web.config:
<authentication mode="Forms">
<forms loginUrl="/Account/Login" defaultUrl="/Home/MyAccount" timeout="43200"/>
</authentication>
Code to persist cookie:
public void SignIn(string userName, bool createPersistentCookie) {
int timeout = createPersistentCookie ? 525600 : 120; // Timeout in minutes, 525600 = 365 days.
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(userName, createPersistentCookie, timeout);
string encrypted = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrypted);
cookie.Expires = System.DateTime.Now.AddMinutes(timeout);
HttpContext.Current.Response.Cookies.Add(cookie);
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);
}
Code to retrieve cookie:
if (System.Web.HttpContext.Current.Request.Cookies.AllKeys.Contains(FormsAuthentication.FormsCookieName)) {
cookie = System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
}
The current code checks for Session for authentication. I'd like to add the ability to get the userName from cookie as well. I have 2 questions:
What do I need to do in order to retrieve the cookie?
How do I decrypt the cookie to obtain the userName?
To get the cookie:
HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);
Decrypt it with:
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
var userName = ticket.UserData

Resources