1

I'm developping an application within our small company environment. This is our setup in a nutshell:

  • Employees log into their PCs via their Active Directory login
  • The application I'm developing uses MS Access as the front end and MS SQL Server 2019 as the back end (Windows authentication mode)

I want to be able to authenticate users in the application without the need to entering their AD login, just based on the fact that they are logged into their PC. Then I want to be able to grant users permissions in the application as I see fit.

This is what I came up with:

tblEmployees:

EmployeeID EmployeeName ADLogin
1 John Doe COMPANY\john.doe
2 Peter Wilson COMPANY\peter.wilson

When any user starts the MS Access application, it will do something like this on start-up:

Private Sub Form_Load()

    Dim rsUser As Recordset
    Dim intEmployeeID As Integer
    Dim strEmployeeName As String
    
    Set rsUser = CurrentDb.OpenRecordset("SELECT * FROM tblEmployees", dbOpenSnapshot, dbReadOnly)
    rsUser.FindFirst "ADLogin='" & Environ("USERDOMAIN") & "\" & Environ("USERNAME") & "'"
    
    If rsUser.NoMatch Then
    
        ' User does not have access to the application
        rsUser.Close
        Set rsUser = Nothing
        
        Application.Quit
        
    Else
    
        ' User with this AD Login has been found and that means that he does have access
        intEmployeeID = rsUser("EmployeeID")
        strEmployeeName = rsUser("EmployeeName")
        
        TempVars("EmployeeID") = intEmployeeID
        TempVars("EmployeeName") = strEmployeeName
        
        
        DoCmd.OpenForm "frm_MainMenu"
        Forms!frm_MainMenu.Requery
        DoCmd.Close acForm, Me.Name, acSaveYes
        
        Forms!frm_MainMenu!txtLoggedUser = TempVars("EmployeeName")
        
    End If

    rsUser.Close
    Set rsUser = Nothing
    
End Sub

Then I will use TempVars("EmployeeID") throughout the application to make forms and buttons available and so on.

My question is: Is this a good practice to do? Is it secure? Is there perhaps a better way to do this? Thanks for any tips.

braX
  • 11,506
  • 5
  • 20
  • 33
ThomassoCZ
  • 73
  • 6
  • 1
    Certainly not secure (imagine what happens if a user disables VBA). Why not just handle authentication on the SQL server backend?\ – Erik A Apr 20 '23 at 12:21
  • The idea here is to have security enforced on both front end and back end. Back end security won't allow me to grant user access to Access functionality, only to data itself. Pardon me, but what do you mena by "user disables VBA"? – ThomassoCZ Apr 20 '23 at 12:36
  • In registry, you can disable VBA, then open Access databases. Any VBA contained in them won't run. – Erik A Apr 20 '23 at 12:37
  • I can disable access to registry via GPO – ThomassoCZ Apr 20 '23 at 12:44
  • 1
    Then they can modify the registry via VBA. Or move it to a different computer using USB sticks/mail/etc, then take out the VBA part. You really need to take care of data protection on the server side, in VBA it will always be partially secure at best (and the environ route is a famous really insecure one since these variables are easily modifiable) – Erik A Apr 20 '23 at 13:01

1 Answers1

2

First of all let me start by saying Access is not secure, but it depends on your colleagues knowledge and how far are they willing to go.

In terms of your solution, I believe there's no need to load the entire table to the recordset and then try to find the desired record when you can filter it directly at source. In addition, string concatenation is (most of the times) bad practice, instead create a query (since its usage will be frequent) and pass the inputs as parameters.

See an example:

The query (your fields might be different but you get the idea)

PARAMETERS [Domain] Text (50), [Username] Text (50);
SELECT *
FROM T
WHERE T.Domain=[Domain] AND T.Username=[Username];

You can also create a temporary query from code.

Const SQL As String = "The SQL command above"

'No query name means it's temporary and will be deleted once the method runs.
Dim q As DAO.QueryDef
Set q = CurrentDb().CreateQueryDef("", SQL) 

To call it and check the logged user:

Dim q As DAO.QueryDef
Dim r As DAO.Recordset

Set q = CurrentDb().QueryDefs("YourQueryName")

'Using the Environ() method.
q.Parameters("[Domain]").Value = Environ("USERDOMAIN")
q.Parameters("[Username]").Value = Environ("USERNAME")

'OR alternative method to get the username/domain from @Andre in comments
'This is more secure than the Environ() method.
With CreateObject("WScript.Network")
    q.Parameters("[Domain]").Value = .UserDomain
    q.Parameters("[Username]").Value = .UserName
End With

'read-only, no need for changes.    
Set r = q.OpenRecordset(dbOpenSnapshot)

'Not found
If r.EOF Then
    DoCmd.Quit acQuitPrompt
    Exit Sub
End If

'Found
'The recordset now contains whatever fields the query selected.
'Do what needs to be done.
'...

'Clean up
If Not r Is Nothing Then r.Close
If Not q Is Nothing Then q.Close

Lastly, I would change the intEmployeeID variable to be of type Long and add error handling to the method.

Kostas K.
  • 8,293
  • 2
  • 22
  • 28
  • At a minimum, you could not use `Environ` for retrieving the username and domain, but something more secure, as noted [here](https://stackoverflow.com/q/3573586/7296893). – Erik A Apr 20 '23 at 13:53
  • Sure, but personally I find it unnecessary inside a company domain. I could be wrong of course. – Kostas K. Apr 20 '23 at 14:01
  • 4
    You don't need an API call, see https://stackoverflow.com/a/32565953/3820271 – Andre Apr 20 '23 at 14:31
  • Thank you Kostas, this makes sense. However can I ask what is the benefit of having an Access query in comparison with getting the data via recordset? I'm trying to keep the front end as clean as possible, I currently have no local queries. Everything is handled through SQL Server Views at this point. Thanks in advance for clarification :) – ThomassoCZ Apr 21 '23 at 07:32
  • String concatenation vs parameters and you return only the desired record at once (or nothing). You don't need to have a static query, but create one on-the-fly from code. See this: https://stackoverflow.com/questions/74078962/ms-access-vba-sql-append-query-returns-syntax-error-when-appending-string-with-s/74079504#74079504 – Kostas K. Apr 21 '23 at 08:18
  • @ThomassoCZ Added the the temporary query example. – Kostas K. Apr 21 '23 at 08:32