Validate ASP.NET membership Username and Password when IsApproved is false - asp.net

How can I check if the password entered by the user matches the password stored in the database when the IsApproved value is FALSE?
What I hope to do is as follows...
User registers - details saved and IsApproved is set to false
User recieves welcome email with membership confiirmation link
User clicks link in email - IsApproved is set to True at this point
User can NOW login
Okay everyting is fine with all of the above and i dont percieve any problems.
Where I'm having issues is...
When the user attempts to login and his/her IsApproved flag is FALSE
I need to cross reference his/her password wih the one stored in DB
And thats where i'm stuck.
The idea was to cross check the password, and if the user entered VALID credentials then to show a message to the user to say ACTIVATE your membership by clicking in the email blah blah blah.
But even if the password entered matches, because I cannot check it in the code the ValidateUser function always returns false because IsApproved is set to false!
Can anyone point me in the right direction please?
ALSO I dont actually need to see the password, so even if theres a sealed function I can call that simply confirms if the pasword matches thats fine too...
Below is my code block..
Public Function ValidateUser(ByVal Username As String, ByVal Password As String, ByRef PwdMatches As Boolean, ByRef Approved As Boolean) As Boolean Implements IMembershipService.ValidateUser
'
Dim ThisMember As MembershipUser = Nothing
Dim ThisResult As Boolean = Nothing
'
Approved = False
ThisResult = False
PwdMatches = False
If String.IsNullOrEmpty(Username) Then
Throw New ArgumentException("Value cannot be null or empty.", "Username")
ElseIf String.IsNullOrEmpty(Password) Then
Throw New ArgumentException("Value cannot be null or empty.", "Password")
ElseIf _Provider.ValidateUser(Username, Password) Then
ThisResult = True
Else
Try
ThisMember = _Provider.GetUser(Username, False)
Try
If (ThisMember Is Nothing) = False Then
Approved = ThisMember.IsApproved
Try
<!-- This is the point im stuck on -->
If Password_Matches_With_Password_In_Db Then
PwdMatches = True
Else
PwdMatches = False
End If
Catch ex As Exception
ThisResult = False
End Try
Else
ThisResult = False
End If
Catch ex As Exception
ThisResult = False
End Try
Catch ex As Exception
ThisResult = False
End Try
End If
Return ThisResult
ThisMember = Nothing
ThisResult = Nothing
End Function

I think one way to do it create a table that stores user accounts pending for approval. When user registers, populate this table with the userID or userName or set some flags indicating users who account has not been activated and who mails have been sent. Check this table when user logs in, if exist or flag not set, display "Activate your account to user"
Write a function that connects to the DB and use the userId to get the approval status from Aspnet_Membership table. The column name is IsApproved which is true or false
Dim user As MembershipUser = Membership.GetUser(userName);
Dim isApproved As Boolean = myMethodCheckIfUserIsApproved(user.ProviderUserKey); //userID

You should be able to call the Membership GetPassword method, passing Nothing in as the passwordAnswer parameter, which should just cause the password to be returned.
A disclaimer on this approach, however: we have implemented our own membership provider and SQL, and I don't have the original code to validate this against, so there may be something in the default provider that would prevent this approach, but it is worth trying.
EDIT:
In the case that the password is hashed, a possible solution to the problem is to perform a direct database query against the users table to get the state of the IsApproved flag. You could do this either before or after the call to GetUser, depending on how much you trust your end users (if you don't trust them, I would call it after in order to prevent someone from trying multiple users to see which are active).

UPDATE & ANSWER TO MY QUESTION
Hello everyone who replied to my question and thank you for your help,
It seems I was barking up the wrong tree by trying to validate the PASSWORD before trying to see if the account membership had been approved.
I have resolved the issue in a VERY SIMPLE WAY indeed.
This is how I did and I did not need to DIRECTLY interogate the database password field nor did i have to worry about hashing the password.
First of all I modified the default VALIDATELUSER call declaration....
in the SERVICES region of the ACCOUNTS MODEL
from...
Function ValidateUser(ByVal Username As String, ByVal Password As String) As Boolean
To...
Function ValidateUser(ByVal Username As String, ByVal Password As String, ByRef IsApproved As Boolean) As Boolean
This enabled me to call my newly modfied validation process also in the SERVICES region of the Accounts model where the ORGINIAL CODE was as follows...
Public Function ValidateUser(ByVal userName As String, ByVal password As String) As Boolean Implements IMembershipService.ValidateUser
If String.IsNullOrEmpty(userName) Then Throw New ArgumentException("Value cannot be null or empty.", "userName")
If String.IsNullOrEmpty(password) Then Throw New ArgumentException("Value cannot be null or empty.", "password")
Return _provider.ValidateUser(userName, password)
End Function
And the MODIFIED function which is now as follows...
Public Function ValidateUser(ByVal Username As String, ByVal Password As String, ByRef Approved As Boolean) As Boolean Implements IMembershipService.ValidateUser
Dim ThisMember As MembershipUser = Nothing
Dim ThisResult As Boolean = Nothing
'
Approved = False
ThisResult = False
If String.IsNullOrEmpty(Username) Then
Throw New ArgumentException("Value cannot be null or empty.", "Username")
ElseIf String.IsNullOrEmpty(Password) Then
Throw New ArgumentException("Value cannot be null or empty.", "Password")
ElseIf _Provider.ValidateUser(Username, Password) Then
ThisResult = True
Else
ThisMember = _Provider.GetUser(Username, False)
If (ThisMember Is Nothing) = False Then
Approved = ThisMember.IsApproved
End If
End If
Return ThisResult
ThisMember = Nothing
ThisResult = Nothing
End Function
I'm much happier with this prcoedure than with messing about with direct manipulation of the DB and also hashing the password.
So in effect, it was more about the original sequence of processing being back to front....
IE.
Not (1)validate login credentials then (2)check if email confirmed? (via link in welcome message)
but rather...
(1)Email Confirmed then (2)validate login credentials

Related

How do I log a user back in after change of Email/Username? - Asp.net/VB.Net

I found this code on a site which was written for me and works, and I'm trying to use it on a new site. The code checks that a emailAddress doesn't already exist when a user edits their account details, and because the emailAddress is also used as the underlying .NET membership username it needs to change that too. So far I've managed to get it to change the email address in tblAccounts which is done with this call:
acc.UpdateUsername(txtEmailAddress.Text, lblEmailAddress.Text)
Then it needs to check if the user changing the email is the logged in user and re-log them back in. This doesn't seem to work as I get this error from the siteMaster when it tries to redirect to the homepage:
System.NullReferenceException: Object reference not set to an instance of an object.
The error is caused in the siteMaster when it tries to check messages for logged in user and it flags up the last line of this as where the error occurs:
If HttpContext.Current.User.Identity.IsAuthenticated Then
hypSettings.visible=true
Dim counter As Integer = messaging.CheckUnreadMessages(Membership.GetUser.ProviderUserKey)
It therefore looks like the email address is being updated where it should, but the site isn't logging the user back in correctly. As I say, it works on the site where I took the code from and there isn't much difference between the sites, but I don't understand memberships and cookies too well so I'm not sure if something needs altering elsewhere?
Here's the code for changing the users email address:
'Check if the Role has been changed
Membership.ApplicationName = "/OCBS"
Dim userID As Guid = Guid.Parse(Request.QueryString("aID"))
Dim usr As MembershipUser = Membership.GetUser(userID, False)
'Now check if the email address has been changed, because the email address is used for the username then the underlying .NET membership username needs changing
If txtEmailAddress.Text <> lblEmailAddress.Text Then
'Email has been changed, update the username for this user
Dim acc As New accounts(Guid.Empty)
acc.UpdateUsername(txtEmailAddress.Text, lblEmailAddress.Text)
'Check if the user changing the email is the logged in user and re-log them back in
If User.Identity.Name = lblEmailAddress.Text Then
'FormsAuthentication.SetAuthCookie(txtEmailAddress.Text, False)
Response.Cookies.Clear()
Dim expiryDate As DateTime = DateTime.Now.AddDays(100)
Dim ticket As New FormsAuthenticationTicket(2, txtEmailAddress.Text, DateTime.Now, expiryDate, True, [String].Empty)
Dim encryptedTicket As String = FormsAuthentication.Encrypt(ticket)
Dim authenticationCookie As New HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
authenticationCookie.Expires = ticket.Expiration
Response.Cookies.Add(authenticationCookie)
End If
End If
Oooh, I've managed it.. I added this..
Session.Abandon()
FormsAuthentication.SignOut()
after line: Response.Cookies.Clear()

AD Authentication Login page

I am creating a helpdesk as a side project and have made a small login page with 'usernameTXT' and 'passwordTXT' textboxes.
I would like the username and password to authenticate against my AD server on my domain:
domain - home.local
dc - home-serv
I have tried all of the LDAP examples online with no luck. Could I be doing something wrong?
Please could someone help me to get ms site to authenticate with the domain? I would like all users to be able to login to the system.
Thanks!
Try something like this
Public Function Authenicate(ByVal username As String, ByVal password As String) As Boolean
Dim isValid As Boolean = False
Try
Dim de As New DirectoryServices.DirectoryEntry("LDAP://local.home", username, password, _
DirectoryServices.AuthenticationTypes.Secure Or _
DirectoryServices.AuthenticationTypes.Sealing Or _
DirectoryServices.AuthenticationTypes.Signing)
de.RefreshCache()
isValid = True
Catch
End Try
Return isValid
End Function

ASP application using the saved credentials even after the user cleared the username and password textboxes and hits submit

Could anyone please help, I have an asp application that asks for username and password in the login.aspx page and after logging in with the correct credentials, it prompts me whether to save the credentials. I clicked yes and after some time I logged out, then it takes me to the login.aspx page with the (saved) username and password already filled automatically in the boxes(because I saved previously above). Now my problem is that, now I cleared the username and password that are filled automatically in the boxes and hit submit. Then it should ask for username and password, but now actually it is using the old saved username and password and logging into the application !!!!
*To make it more brief and clear, this is the problem :-
"I am able to login even though I have removed the username and password. I logged out. Erased the content of both fields and then clicked 'Submit'. I was able to get into the Application."
Could anyone help please . Thanks in Advance !!!!
Here's my code for the 'Submit' button 'OnClick' Event :-
Protected Sub SignIn(sender As Object, e As EventArgs)
StatusText.Text = String.Empty
Dim Name As String = UserName.Text
Dim Password As String = UserPassword.Text
If IsValid Then
Try
Dim userStore = New UserStore(Of IdentityUser)()
Dim userManager = New UserManager(Of IdentityUser)(userStore)
userManager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(10)
userManager.MaxFailedAccessAttemptsBeforeLockout = 7
Dim user = userManager.FindByName(Name)
If user IsNot Nothing Then
If userManager.IsLockedOut(user.Id) Then
StatusText.Text = String.Format("Your account is locked. please contact administrator.")
Else
If userManager.CheckPassword(user, Password) Then
userManager.ResetAccessFailedCount(user.Id)
If Not userManager.GetLockoutEnabled(user.Id) Then
userManager.SetLockoutEnabled(user.Id, True)
End If
Dim tkt As FormsAuthenticationTicket
Dim cookiestr As String
Dim ck As HttpCookie
'Add Session to 5 Hours
tkt = New FormsAuthenticationTicket(1, user.UserName, DateTime.Now, DateTime.Now.AddHours(5), RememberMe.Checked, "")
cookiestr = FormsAuthentication.Encrypt(tkt)
ck = New HttpCookie(FormsAuthentication.FormsCookieName, cookiestr)
If RememberMe.Checked Then
ck.Expires = tkt.Expiration
End If
ck.Path = FormsAuthentication.FormsCookiePath
Response.Cookies.Add(ck)
Dim strRedirect As String
strRedirect = Request("ReturnUrl")
If strRedirect Is Nothing Then
strRedirect = "default.aspx"
End If
Response.Cookies.Add(New HttpCookie("adjusterId", New ContextProvider().GetAdjusterId(user.Id)))
Response.RedirectPermanent(strRedirect)
Else
userManager.AccessFailed(user.Id)
If userManager.IsLockedOut(user.Id) Then
StatusText.Text = String.Format("Your account is locked. please contact administrator.")
Else
StatusText.Text = String.Format("Invalid username or password, you have {0} more login attempt(s) left before account is locked out.", (3 - userManager.GetAccessFailedCount(user.Id)))
StatusText.Visible = True
End If
End If
End If
Else
StatusText.Text = String.Format("Invalid username or password.")
StatusText.Visible = True
End If
Catch ex As Exception
StatusText.Text = String.Format("Unable to login, please contact administrator.")
End Try
Else
StatusText.Text = String.Format("Enter username or password.")
End If
End Sub
Likely the authentication cookie is being remembered, after the initial login, and that still exists.
Somehow when you attempt to login with empty fields, it just uses the cookie instead of the empty fields. That would be my guess.
my best guess is that this method is where you will find the culprit code:
userManager.AccessFailed(user.Id)
It could also be a redirect problem. That you simply attempt to redirect the user back to a page on an invalid login, and since the cookie is still set, you are allow to see whatever page you are getting redirected too.
Main problem, your logout function doesn't remove the authentication cookie.
after a lot of banging, I found out a simple change that fulfilled my requirement, I just added the below properties for my 'username' textbox in .aspx as below :-
<asp:TextBox ID="UserName" runat="server" Width="295px" AutoCompleteType="None" EmptyMessage=" "></asp:TextBox>
(added AutoCompleteType and EmptyMessage).
Not sure whether that's the right approach, but that helps !!!! ThankYou.

Why does my if else return false?

In my Appcode folder as seen above I have a Class called BaseClass. In BaseClass I have a function called CheckWAN() that defines IP ranges so that later I can auto authenticate local users to my site via their IP address range.
Public Function CheckWAN() As Boolean
Try
Dim url As String = Request.Url.ToString()
'Get the client ip address
Dim RemoteAddress As String = Request.UserHostAddress
Dim strRemoteAddress As String = RemoteAddress
Dim myWAN As String = "192.168.254.254"
'add Some other ips
Dim SOther001 As String = "192.168.254.1"
Dim SOther002 As String = "192.168.254.2"
Dim SOther003 As String = "192.168.254.3"
If strRemoteAddress.Contains(myWAN) Then
Return True
ElseIf strRemoteAddress.Contains(SOther001) Then
Return True
ElseIf strRemoteAddress.Contains(SOther002) Then
Return True
ElseIf strRemoteAddress.Contains(SOther003) Then
Return True
Else
Return False
End If
Catch
Return False
End Try
End Function
Finally I have a set up a login on the site default.aspx that Checks the IP address of the user connecting if the If CheckWAN() returns true then I get passed along to the content page however if it is false then it shows me the login with a message that it is returning false
Public Class BaseClass
Inherits System.Web.UI.Page
If CheckWAN() = True Then
Response.Redirect("/content.aspx")
Else
Response.Write("The CheckWAN is returning False")
'this else also causes a redirect loop if its changed to
'Response.Write(/default.aspx) not sure why
End If
I have also checked with networking to verify the IP's used in my code and they all are valid.
Edited!
here is what Request.UserHostAdress returns
debug
First of all, this should not even compile. Apparently it does, so you must have Option Strict Off. Request.UserHostAdress returns a complex object, and you declared your variable as a string. I suspect that what you actually want is some property of that object, although I don't know which one.

Log out asp.net user if user does not exist or is inactive / disabled

How would I go about adding to the code below in checking to see that the user exists in the database, and if the account does exist to check if it is inactive or disabled? If either of those are true .. then sign off and redirect the user to the login page.
I am running into an issue that if the aspx auth cookie is saved .. but the user account is deleted or set inactive .. the user can still login.
Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init
If User.Identity.IsAuthenticated Then
Response.Redirect("~/homepage")
End If
End Sub
Thanks for your help.
Your Question ::
I am running into an issue that if the aspx auth cookie is saved .. but the user
account is deleted or set inactive .. the user can still login.
IsAuthenticated will return true for a user even after they've been removed. This happens because it only checks the authentication cookie, which is still on their system.
You need to remove the Authentication cookie inside your Signout function as below. SUppose for example you put a logout button. Add the below code in the Logout button click.
Protected Sub btnLogOutAction_Click(sender As Object, e As EventArgs)
FormsAuthentication.Signout()
' check your own supplied cookie name. Default name is .ASPXAUTH
If Request.Cookies(".ASPXAUTH") IsNot Nothing Then
Dim myCookie As New HttpCookie(".ASPXAUTH")
myCookie.Expires = DateTime.Now.AddDays(-1.0)
myCookie.Domain = "test.com"
Response.Cookies.Add(myCookie)
End If
End Sub
2.) Question::
to see that the user exists in the database, and if the account does exist to
check if it is inactive or disabled
This question can have many possible cases. Lets see 3 of them
CASE I:: if the user is loggedIn but not active for say few minutes, by default after 20 minutes, ASP.NET will clean up the users session, and when it does, it will fire a Session_End event that can be handled in Global.asax. You can then be able to mark this user as inactive in database, or execute any code you want to run as per the requirement.
Case II::
I use to set IsApproved to False to disable users.
Dim user As MembershipUser = Membership.GetUser("Yourusername")
If user IsNot Nothing Then
user.IsApproved = False
Membership.UpdateUser(user)
End If
Now you can check this as:
Dim check As New SqlCommand("SELECT Count(*) FROM [Users] WHERE Username='" & username & "'", Connect)
Dim exist As Integer = CInt(check.ExecuteScalar())
' greater than zero means user exists in database
If exist > 0 Then
' Now check if user is disabled OR not approved
Dim user As MembershipUser = Membership.GetUser("Yourusername")
If user IsNot Nothing Then
If user.IsApproved = False Then
FormsAuthentication.RedirectToLoginPage()
End If
End If
End If
CASE III: Using ProfileManager class
Use below sample code as a reference. We can check if user is inactive since a date using the ProfileManager class methods. Read MSDN
Dim check As New SqlCommand("SELECT Count(*) FROM [Users] WHERE Username='" & username & "'", Connect)
Dim exist As Integer = CInt(check.ExecuteScalar())
' greater than zero means user exists in database
If exist > 0 Then
' Now check if user is marked inactive
ProfileInfoCollection profiles;
profiles = ProfileManager.FindInactiveProfilesByUserName
(ProfileAuthenticationOption.Authenticated,UserName, userInactiveSinceDate)
If profiles("UserName") IsNot Nothing Then
FormsAuthentication.RedirectToLoginPage()
Else
' Code to run if user exists in database and is also active
End If
End If
Try this
If User.Identity.IsAuthenticated Then
MembershipUser currentuser = Membership.GetUser()
If currentuser IsNot Nothing And currentuser.IsApproved = True Then
Response.Redirect("~/homepage")
End If
End If

Resources