I can't seem to find an answer for this anywhere. I'm using a custom membership provider and membership user with my own tables, which is appearing to be far too much hassle than it's worth. When updating a user record it appears that I need to update it's membership user instance as well, otherwise where I'm relying on data from membership user it isn't corresponding to the updated database.
I've created my own update membership user method, as the existing one only accepted it's own MembershipUser class:
public static void UpdateAccountUser(AccountUser accountUser)
{
// Custom MembershipUser
ToMembershipUser user = new ToMembershipUser(
"AccountUserMembershipProvider",
accountUser.FirstName + " " + accountUser.LastName,
accountUser.ID,
accountUser.Email,
"",
"",
true,
false,
DateTime.Now,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue);
// Fill additional properties
user.ID = accountUser.ID;
user.Email = accountUser.Email;
user.FirstName = accountUser.FirstName;
user.LastName = accountUser.LastName;
user.Password = accountUser.Password;
user.MediaID = accountUser.MediaID;
user.Media = accountUser.Media;
user.Identity = accountUser.Identity;
user.CreatedAt = accountUser.CreatedAt;
user.UpdatedAt = accountUser.UpdatedAt;
UpdateCookie(user.Email);
}
private static void UpdateCookie(string email)
{
HttpCookie cookie = FormsAuthentication.GetAuthCookie(email, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
// Store UserData inside the Forms Ticket with all the attributes
// in sync with the web.config
var newticket = new FormsAuthenticationTicket(ticket.Version,
ticket.Name,
ticket.IssueDate,
ticket.Expiration,
true, // always persistent
email,
ticket.CookiePath);
// Encrypt the ticket and store it in the cookie
cookie.Value = FormsAuthentication.Encrypt(newticket);
cookie.Expires = newticket.Expiration.AddHours(24);
HttpContext.Current.Response.Cookies.Set(cookie);
}
Now obviously this is just creating a new instance and not updating the existing one, which doesn't allow me to see the updated details without logging out and logging back in. Any ideas?
Edit
So I managed to find an example of someone else using their own custom update method, but all they appear to be doing is updating the database not the MembershipUser itself. I'm already doing this?!
I attempted to instead just update the FormsAuthenticationCookie and then when calling Membership.GetUser() I at least pass an updated User.Identity.Name, but to no avail, still old data even though database is updated. I've ran out of ideas...
This could possibly be a repeat of yesterday's question MembershipUser not getting updated result from database
I eventually found out the MembershipUser wasn't updating due to every time I calling GetUser() the query involved was using FirstOrDefault(). Turns out this caches the result rather than retrieving a fresh result. By adding AsNoTracking() to the query itself I now get the updated result, without having to even call UpdateUser().
Related
I am very new to c# and asp.net mvc. I'm building a HR portal for our company where a user can submit a leave form among other things... So I'm using mssql as the database server and using Entity Frame work to communicate with it. I have 3 entities, user (Containing user details), permissions (the user permissions for allowing actions in the app) and then the leave form table (where the leave form details are stored). There is a one to many relationship between user - permission and then a one to many relationship between user-leave. I am not fazed about the permissions as that gets created when the user account is being created.
The problem I am facing is, how do I add a leave form for a specific user? Below is my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Leave(MasterViewModel model)
{
DocSubViewModel mv = model.DSModel;
int userId = Convert.ToInt32(Session["userID"]);
try
{
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.dateFrom = mv.DateFrom;
leave.dateSubmitted = DateTime.Now;
leave.dateTo = mv.DateTo;
leave.nrDays = mv.NrDays;
leave.reason = mv.SpecialLeave;
leave.TLApproval = null;
leave.TLApprovalDate = null;
leave.TLApprovalID = mv.TeamLeaderID;
leave.DMApprovalDate = null;
leave.DMApprovalID = mv.DepManagerID;
leave.DMApproval = null;
leave.type = mv.Type;
leave.user = userId;
db.leaves.Add(leave);
db.SaveChanges();
}
ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
catch (Exception ex)
{
ViewBag.Message = ex;
//ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
The problem comes in leave.user = userId;. It says:
Cannot implicitly convert int to Portal.Model.user
I can't seem to find out how to do this...
You're telling it to put the UserId where your leave model is asking for a User.
Your relationship requires a User to go in there, so you'll have to update your code a little bit:
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.user = db.users.First(x => x.Id == userId);
}
This will put reference to the actual user in the new leave record. If you go later and check it out you'll see a column in the leave table called user_Id that has an integer value in it and is set as a foreign key to the users table.
Note that this will error if no user exists having the specified Id value. If you anticipate this to be a problem, rather use .FirstOrDefault() instead of .First() and then account for the value being null before you add it to your new leave object.
That's expected since User is a object and not int. What you should be doing probably is leave.user.UserId = userId; instead [Assuming leave.user is of type User which has a UserId property]
Well I am using DirectoryEntry and LdapConnection to reset password in a scenario where we have password minimum age and history policy enforced. When someone forgets their password, you want them to be able to reset their password to something which doesn't violate password history. As an alternative solution, it would be possible to use "SetPassword" and reset the password to a generated value and then force the user to change it on their next login. This is not possible in our scenario. Hence, I was following this blog post in technet and trying out LDap extended controls to reset password by honoring password history. In brief, it's just changing to the same password again and again without complaints. My code is as follows:
private static void PasswordChanger(DirectoryConnection ldapCon,
string distinguishedName,
string passwordToSet = null)
{
// the 'unicodePWD' attribute is used to handle pwd handling requests
// modification control for the replace operation
var damReplace = new DirectoryAttributeModification
{
Name = "unicodePwd"
};
// value to be send with the request
damReplace.Add(Encoding.Unicode.GetBytes(String.Format("\"{0}\"", passwordToSet)));
// this is a replace operation
damReplace.Operation = DirectoryAttributeOperation.Replace;
// combine modification controls
var damList = new DirectoryAttributeModification[]
{
damReplace
};
// init modify request
var modifyRequest = new ModifyRequest(distinguishedName, damList);
// the actual extended control OID
const string ldapServerPolicyHintsOid = "1.2.840.113556.1.4.2239";
// build value utilizing berconverter
var value = BerConverter.Encode("{i}", new object[] { 0x1 });
// init exetnded control. The variable name represts the actual extended control name.
var LDAP_SERVER_POLICY_HINTS_OID = new DirectoryControl(ldapServerPolicyHintsOid,
value, false, true);
// add extended control to modify request
modifyRequest.Controls.Add(LDAP_SERVER_POLICY_HINTS_OID);
/* send the request into the LDAPConnection and receive the response */
var result = ldapCon.SendRequest(modifyRequest);
}
The call to Password changer is enclosed as follows,
using (var domain = Domain.GetDomain(new DirectoryContext(
DirectoryContextType.DirectoryServer,
ActiveDirectoryInstance,
request.ServiceAccountName,
request.ServiceAccountPassword)))
using (var directoryEntry = domain.GetDirectoryEntry())
using (var directorySearcher = new DirectorySearcher(directoryEntry))
using (var conn = new LdapConnection(new LdapDirectoryIdentifier(ActiveDirectoryInstance),
new NetworkCredential(request.ServiceAccountName,
request.ServiceAccountPassword,
ActiveDirectoryInstance),
AuthType.Ntlm))
{
...
...
PasswordChanger(....)
...
...
}
EDIT:
This is to do with the scenario explained here
https://support.microsoft.com/en-us/kb/2386717/
RE my comment re "As an alternative solution, it would be possible to use "SetPassword" and reset the password to a generated value and then force the user to change it on their next login."
We can't do that in our scenario as we have password history and minimum age restrictions (24h) enabled. Hence I can't use ChangePassword in user context and SetPassword in admin context (as that wouldn't respect password history).
The LDAP_SERVER_POLICY_HINTS_OID control only enforces password history constraints, meaning that you're only preventing password reuse which should be a non-issue if you generate random passwords in the first place.
To test new passwords against password complexity settings, you would need access to the password filters installed on Domain Controllers.
Otherwise you'll need to use SetPassword - it will enforce complexity requirements, but not password history.
i am new to asp.net. my question is that how one can save login userid in asp.net webform?
code i am writing in asp.net webform is:
foreach (var s in db.Users)
{
if (tbUserName.Text==s.user_name && tbPassword.Text == s.user_password)
{
if (string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
{
FormsAuthentication.SetAuthCookie(tbUserName.Text, false);
Response.Redirect("~/");
}
else
{
FormsAuthentication.RedirectFromLoginPage(tbUserName.Text, false);
}
flag = 1;
break;
}
else
flag=0;
}
if(flag==0)
{
tbUserName.ErrorText = "Invalid user";
tbUserName.IsValid = false;
}
}
As Tim said, you can get the authenticated user with
User.Identity.Name
You can also get the AuthenticationType and IsAuthenticated properties from the same object.
A suggestion would be to NOT query your DB for all of the users and then loop through them for the correct one. Based off of the user input, you should query the db for the one and only user which matches the form post.
Based off of what you wrote, it looks like the passwords are in clear text and not encrypted, which is a huge security issue. Being new to .Net, take a look at the .Net Membership Providers or SimpleMembership or a comparable pattern.
Good luck!
I would suggest you look at using the Session object to store the user ID. A Session will be available throughout that user's session on the site. Thus, you can call Session anywhere in your site's code to reference that user ID.
For example, to store the id, simply do this, pretend we're in Page_Load()
Session["UserId"] = userID // Or wherever you get the ID from.
then in your code behind, you can do this:
string userId = Session["UserId"]
If the user ID is a number, say an int, then you will need to cast the userID:
int userId = 0;
int.TryParse(Session["UserID"], out userID)
Quick dirty link to a Session example :
http://asp.net-tutorials.com/state/sessions/
I tried remember me with session but I can not succeed. First of all is it possible?
in CheckedChanged method
if (CheckBox1.Checked)
{
Session["email"] = TextBox1.Text;
Session["pass"] = TextBox2.Text;
}
in pageload method
if (Session["email"].ToString() !=null && Session["pass"].ToString() !=null)
{
TextBox1.Text = Session["email"].ToString();
TextBox2.Text = Session["pass"].ToString();
}
but it doesnt work.
You can't use Session for this purpose. You should have to use Cookie to save the Remember Me status.
"Remember me" functionality is implemented by using persistent cookie.
You can't use Session object, because it will be automatically deleted after certain period of user inactivity.
Security note: Never store user password in plaintext format!
Btw: its better that you create a user class with two properties email and pass, and store that in one session element:
User myUser = new User();
myUser.Email = "test#test.com";
myUser.Pass = "123456";
session["user"] = myUser;
and you store the Remember me inside a cookie, with some credentials highly encrypted or salted hash, so when your user visits again you match the name and salted hash with the info you have in your database
change like this. as you are checking for the value. you cant access ToString() method , when null object is there .
if (!string.IsNullOrEmpty(Session["email"]) && string.IsNullOrEmpty(Session["pass"])) )
// then do with session objects.
I have the following scenario:
the below 2 global variables in my page:
MainContext db = new MainContext();
User user = new User();
A method to fill the properties that is called on the button update:
private void FillProperties()
{
user.FirstName = txtFirstName.Text;
user.LastName = txtLastName.Text;
user.Email = txtEmail.Text;
}
on the button update i am doing the following:
FillProperties();
user.ID = Request.QueryString("userid");
db.SaveChanges();
but the record isn't been updated which i think is logical since the user variable isn't related to db object, but i a, not being able to do this:
db.Users.AddObject(user);
since AddObject isn't found in the db properties.
What can I do to update user?
Your answers are appreciated.
If you are using the DbContext API simply use
db.Entry(user).State = EntityState.Modified;
Where do you add your user to the DB?
If the user exists in the DB, in order to update it, you should do, for example:
user = db.Users.Where(x => x.ID == Request.QueryString("userid")).Single();
FillProperties();
db.SaveChanges();