I'm encountering a very strange problem with MS Access. I have some VBA code used on a password reset form. The code hashes the input password and then saves the hash to a table of users. Here's a relevant snippit:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
the MSGboxes are my debugging notes. I know the hash generates properly as a long string of numbers, all well and good. When I go into the datasheet for the Users table though, the number has always been converted into scientific notation.
Here's a screenshot of the data sheet. bob.smith is an example of what I end up with after the code runs, the other two are gibberish I entered manually. The field is formatted as a string, so I'm not sure why it would even try to convert the number into SN when as far as I can tell the item is always a string.
I'm thinking the error must creep in around the SQL query? If there's a better way of doing this then I'm all ears.
Thanks in advance for your help!
datasheet
design view
Complete code, just in case:
Option Compare Database
Private Sub Command84_Click()
Dim hashPW As String
Dim updatePW As String
Dim checkName As String
checkName = Nz(DLookup("Username", "Users", "Username = pwChangeUsrnm"), "aaa")
MsgBox ("checkName set to " & checkName)
If pwChangeUsrnm = checkName Then
MsgBox ("Username Found")
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
Else
MsgBox ("Passwords Do Not Match!")
End If
Else
MsgBox ("Username not found")
End If
End Sub
I think Andre has the right of it. I tried adjusting the hashing code to add a letter character and this worked, but then I needed to go back and add the single quote around the hashed PW value- which probably would have made the code work even without adding the letter:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = '" & hashPW & "' WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
A thanks to Zaph's second comment on security as well, I'll take that all into account. For the purposes of this database security isn't too much of a concern as it will be sitting behind existing security measures. The hashing of passwords is more just to avoid ever displaying the passwords in plain text. Nevertheless it's useful to know about these extra functions.
Related
In the form that I create new users, I would like it to validate if the username already existed or not, then in the register button I put the following code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
Dim Inserir As String = "INSERT INTO `techstorehunter`.`utilizadores`(`Username`,`Password`,`pergunta`,'resperg')VALUES('" & TextBox1.Text & "','" & TextBox2.Text & "','" & TextBox3.Text & "','" & ComboBox1.Text & "')"
ExecuteQuery(Inserir)
Catch
MessageBox.Show("Username already exists")
End Try
If TextBox1.Text = "" Then
MessageBox.Show("Insert a username")
End If
If TextBox2.Text = "" Then
MessageBox.Show("Insert a password")
End If
If TextBox3.Text = "" Then
MessageBox.Show("You need to answer a question")
End If
If ComboBox1.Text = "" Then
MessageBox.Show("You need to select a question")
End If
End Sub
But everytime I create a user it says that it already exists, even if not, what i can do? Thanks.
PS : "Inserir" means "Insert" but my language is Portuguese.
There are several issues with your code :
First, you validate the input after running the sql query : you should validate first, and if everything goes well then do the INSERT, otherwise you are exposing to either inserting dumb data to database, or getting the « User already exists » warning on incomplete input
Also, you catch all database errors and interpret them as « User already exists » ; by proceeding this way you are potentially hiding other database errors than duplicate user record. The proper way to proceed is to :
after form validation, check for per-existing user with a query like follows, where the question mark should be replaced by the submitted user name. If the query returns anything, then you know that you have a duplicated user for sure, and you can raise the appropriate warning and stop the processing.
SELECT 1 FROM `techstorehunter`.`utilizadores` WHERE `Username` = ?
if the first query returns nothing, you can run the INSERT statement
everytime your run a query, you want to catch errors, report them with the full error message, and abort the processing
I have a combobox that builds it's list upon first usage. I know that the way I want "NotInList" to behave isn't conventional - I don't want to waste adding the item to a table separate from the needed entry, but I'd like to still warn about an item that hasn't been used yet, so that the user has to think twice before accepting the entry.
Once the user adds the item, it will automatically appear in the list next time because the data source for the combo box is as follows:
SELECT tbl_SP.PROGRAM
FROM tbl_SP
GROUP BY tbl_SP.PROGRAM
HAVING (((tbl_SP.PROGRAM) Is Not Null And (tbl_SP.PROGRAM)<>""));
I tried this:
Private Sub cmbPROGRAM_NotInList(NewData As String, Response As Integer)
If MsgBox("'" & Chr(34) & NewData & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & NewData & "?") = vbYes Then
Response = acDataErrAdded
End If
End Sub
but of course, Access wants the item to actually exist before it will release the error. And...if I set LimitToList to "No" then the user doesn't get a warning.
How can I achieve this behavior?
Ok, I tried this which works fine if the user selects YES, but becomes more complicated when the user selects "NO"
Public Function ReturnsRecords(strSQL As String) As Boolean
Dim d As DAO.Database
Dim arr(1 To 3) As DAO.Recordset
'Dim rs As DAO.Recordset
'assume 3 items in array above
Set d = CurrentDb
Set arr(1) = d.OpenRecordset(strSQL)
' MsgBox "Record Count is " & arr(1).RecordCount
If arr(1).RecordCount > 0 Then
ReturnsRecords = True
Else
ReturnsRecords = False
End If
Set d = Nothing
End Function
Private Sub cmbPROGRAM_BeforeUpdate(Cancel As Integer)
Dim strSQL As String
strSQL = "Select * from LU_PROGRAM where PROGRAM ='" & Me.cmbPROGRAM & "'"
If ReturnsRecords(strSQL) = False Then
If MsgBox("'" & Chr(34) & Me.cmbPROGRAM & Chr(34) & " hasn't been used yet. Add to list? ", vbQuestion + vbYesNo, "Add - " & Me.cmbPROGRAM & "?") = vbNo Then
Cancel = True
' how do I reset this? Me.cmbPROGRAM.Text = Null
End If
End If
End Sub
How do I clear the combobox if the user selects NO? If I select me.undo, that will undo all of the entries, but I just want to clear the combobox.
Incidentally, the form is totally unbound and doesn't accept an entry until the user selects "Save"
First, I'm not quite sure what you wish to achieve ...
Then, educate the users to press Escape to cancel. This is mandatory wisdom when operating an Access application.
For your code to work, you can't change the content of a control in the BeforeUpdate event. So try the AfterUpdate event with either:
Me!cmbPROGRAM.Text = ""
or:
Me!cmbPROGRAM.Value = Null
First off I'd like to make perfectly clear that my knowledge of Access and VBA is extremely limited at best. I have an employee database system that due to it's age has been prone to small data corruption issues and controls breaking due to differences between 2003/2007 and 2010. While I've managed to hash out the bulk of the problems, one that has me especially concered is the script we're using to manage access to the database. The system is split between two files, a frontend where users can access the database and a backend file that contains all of the tables.
The issue I have is in the frontend form that handles the logon for the users. The way the access system is set up is the user enters their SSN, then the script finds their SSN in the table and if it exists looks if an access checkbox is checked. If they have access, they're directed to the main menu, if not they get a denied message. What I've found though is for some reason or another, if an entry in the personnel table has an incomplete SSN, the script breaks and anyone can gain access to the database.
There's a query that runs in the frontend that looks at the master personnel table and pulls just the first two columns, SSAN and Access.
The form itself has a visible text box, "Text8", and a hidden Combo Box "Combo4". Combo4 uses the previously mentioned query for the row source (SELECT qryAccess.SSAN FROM qryAccess;), while Text8 is where the user enters their SSN.
Here's the code right now:
Option Compare Database
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
Like I said before, as long as every entry for the SSNs is a full 9-digits, this system works. However, if for some reason the entry is not the full 9 like I just found in my database (and no, I have no idea what caused that to happen, there is an input mask in place, 000-00-0000;;_), this system breaks. You could type in "abc" for the SSN and gain access to the database.
How can I write a small script that pre-checks the table for SSN entries that don't fit the 9-digit format that is set, and if it finds them, resets them to an unused number, such as 000000000, 000000001, etc?
Also, if you have any suggestions on how to streamline the existing code, I'd be more than happy to take them.
Add this function to you application
Public Function IsValidSSN(ByVal SSN As String) As Boolean
'Determines if SSN is a valid social security number
'requires SSN to be in either "#########" or "###-##-####" format
IsValidSSN = (SSN Like "###-##-####") Or _
SSN Like ("#########")
End Function
Also change your function to this:
Private Sub Combo4_AfterUpdate()
' Find the record that matches the control.
If IsValidSSN(Me![Combo4]) Then
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End IF
End Sub
Private Sub Text8_AfterUpdate()
Me![Combo4] = Me![Text8]
If IsValidSSN(Me![Text8]) Then
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst "[SSAN] = '" & Me![Combo4] & "'"
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
If Me![Access] = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
EDIT
Also why are you using a combobox to enter a SSN? You can use input mask on text box. Also I would highly suggest that you convert your system to some other identification other than SSN because it is easily passable to get past this code to look at the table containing everyones SSN, by holding down shift when opening the application. As for streamlining your code just remove that combobox altogether. If they are typing it into a textbox there is no need to put it into a hidden combobox.
You have a text field, SSAN, and with that input mask the dashes are not included in the stored values. So valid values would be 9 digit strings.
If that is correct, you can use a query to identify any invalid stored values.
SELECT y.SSAN, Len(SSAN) AS LenghtOfSSAN
FROM YourTable AS y
WHERE Len(SSAN)<>9 OR y.SSAN ALike '%[!0-9]%';
That query will return rows where SSAN includes < or > 9 characters, and any values which include characters other than digits.
Note the ALike keyword tells the db engine to expect ANSI wild card characters. If you prefer Access' * wild card instead, change it to Like '*[!0-9]*'
Once you fix the stored values, add a Validation rule for that SSAN field (Like "#########") to require all values consist of 9 digits.
Since it looks like this became more of a "How do I find the user" than "How do I fix the existing entries", let me throw my hat into the ring.
Unless I completely misunderstand this, the existing (and accepted answer) function is HORRIBLE. You can do this all much more efficiently and with less code. First of all, delete Combo4. No need for it. Then do this:
Private Sub Text8_AfterUpdate()
Dim X as Integer
X = DLookup("Access", "qryAccess", "SSAN = '" & Me!Text8 & "'")
If Nz(X) = True Then
DoCmd.RunMacro "Access"
Else
DoCmd.OpenForm "frmDenied"
End If
End Sub
That's all you need. If the user's SSN was stored incorrectly, he's gonna be denied. 7 digits, 8 digits, doesn't make a difference. Only exact matches get through. That is, assuming 0 = False and 1 = True, which should be the default anyway.
I work on Access Project, but I think there is nothing specific to Access in this question.
I have a form and it's possible to open it only if you are in the table of authenticated users (and I authenticate user by his windows username) - I know it is lame authentication.
Here's the code I've put into form open event:
Private Sub Form_Open(Cancel As Integer)
If DCount("User_Id", "Users", "[username]='" & (Environ$("Username")) & "'") Then
Else
MsgBox "Access Denied!"
DoCmd.Quit
End If
End Sub
What I want to accomplish is that when MsgBox "Access Denied!" is displayed, if I type certain word (something as password) before clicking on OK button, that DoCmd.Quit is not executed. I don't want to display anything, just type in the password.
I don't need this desperately, I just want to make this for fun. And I think it would be really cool if it's possible with VBA.
I tested this in Access 2007 and I think the logic is what you want, or at least it's close. Please consider using something like the WindowsUser() function below to get the Windows user name. I get that this is just for fun, so you don't care now. However, keep this point in mind for anything you do care about in the future. Environ("USERNAME") as a security measure is trivially easy to defeat.
Const cstrYourPassword As String = "let me in"
Dim blnGoodbye As Boolean
Dim lngButtons As Long
Dim strPrompt As String
Dim strPassword As String
strPrompt = "Access Denied!" & vbCrLf & vbCrLf & _
"Click Retry to try with password" & vbCrLf & _
"or Cancel to quit."
lngButtons = vbCritical + vbRetryCancel
If MsgBox(strPrompt, lngButtons) = vbRetry Then
strPassword = InputBox("Password:")
If strPassword = cstrYourPassword Then
MsgBox "Welcome " & WindowsUser
Else
blnGoodbye = True
End If
Else
blnGoodbye = True
End If
If blnGoodbye = True Then
MsgBox "That's all folks."
'DoCmd.Quit ' <- enable this when ready.
End If
Use this instead of Environ("USERNAME").
Public Function WindowsUser() As String
Static strUserName As String
If Len(strUserName) = 0 Then
strUserName = CreateObject("WScript.Network").Username
End If
WindowsUser = strUserName
End Function
The following should work, but you may want to modify it to set the password to something better or if you want more than one password. Anyone who knows how to read the code will be able to find out the password as well, so maybe it would be better to put it in the database somewhere?
Const sPassword As String = "PASSWORD"
Const sMESSAGE As String = "Please enter your password"
Const sTITLE As String = "Enter Password"
Dim sInput As String
sInput = InputBox(sMESSAGE, sTITLE)
If sInput <> Password Then
MsgBox "Access Denied!"
DoCmd.Quit
End If
I've looked around for ages and I haven't found an answer to my problem so I was hoping someone here could help me.
I am creating a system using Microsoft Access where I have a members table containing a username and password and various other fields such as date of birth, etc.
I want to create a form where users can enter a username and password. By clicking a button on this form, these details will then be checked against the usernames and passwords in the members table. If the details match, a message will be displayed saying they have logged in. If the details are not found in the table, a message saying the details are incorrect will show.
How can I do this without using VBA?
I have started by creating a form called loginform with two text boxes loginusername and loginpassword.
Where should I go from here?
The VBA solution shouldn't be that complicated. A quick and dirty solution:
Dim Result as Variant
Result=Dlookup("Password","tblMembers","UserName='" & nz(loginusername.value,"") & "'")
If nz(Result,"")<>nz([login password].value,"") Then
MsgBox "Invalid password"
Else
MsgBox "Password correct"
End If
'set the variables
Dim UN As String
Dim PW As String
Dim user, pass As Boolean
'make sure none of the fields are null, or blank
UN = Text
PW = Text
If IsNull(Username) Then
MsgBox "You must enter a username."
Username.SetFocus
Else
'assign true to user
user = True
End If
If IsNull(Password) Then
MsgBox "You must enter a password."
Password.SetFocus
Else
pass = True
End If
If user = True And pass = True Then
UN = DLookup("[Username]", "LoginTable", "[Username]= '" & Me.Username & "'")
PW = DLookup("[Password]", "LoginTable", "[Password] = '" & Me.Password & "'")
End If
If Me.DummyUser = Me.Username And Me.DummyPass = Me.Password Then
MsgBox "Access granted."
Else
MsgBox "Access denied."
End If