0

I have used Ben Clothier's suggestion from his Office Blog Power Tip (http://blogs.office.com/2011/04/08/power-tip-improve-the-security-of-database-connections/) to create a DSN-less connection with cached credentials so that users' UID and PWD aren't saved, or required multiple times, when working in the Access interface. Have others done this? If so, what has been your approach when you need to use an ADO connection instead of DOA to reach SQL from Access via VBA? How do you open a adodb connection without having to provide the User ID and Password again, or having to put it in the code? (I'm using Access 2013 frontend, SQL 2008 R2 backend, SQL Server Security) Thanks in advance!

My Cached Connection code works like this:

Public Function InitConnect(strUserName As String, strPassword As String) As Boolean
' Description:  Is called in the application’s startup 
'               to ensure that Access has a cached connection
'               for all other ODBC objects’ use.

    Dim dbs As DAO.Database
    Dim qdf As DAO.QueryDef
    Dim rst As DAO.Recordset
    Dim strConnection As String


    strConnection = "ODBC;DRIVER=sql server;" & _
             "SERVER=******;" & _
             "APP=Microsoft Office 2010;" & _
             "DATABASE=******;" & _
             "Network=DBMSSOCN;"

    Set dbs = DBEngine(0)(0)
    Set qdf = dbs.CreateQueryDef("")
    With qdf
        .Connect = strConnection & _
             "UID=" & strUserName & ";" & _
             "PWD=" & strPassword & ";"
        .SQL = "Select Current_User;"

        Set rst = qdf.OpenRecordset(dbOpenSnapshot, dbSQLPassThrough)

   End With
    InitConnect = True

ExitProcedure:
    On Error Resume Next
        Set rst = Nothing
        Set qdf = Nothing
        Set dbs = Nothing
    Exit Function
End Function

Then when I need to access data I can do this (Note the UID and PWD are not required):

Dim dbs As DAO.Database 
Set dbs = OpenDatabase("", False, False, "ODBC;DRIVER=sql server;SERVER=*****;APP=Microsoft Office 2010;DATABASE=*****;Network=DBMSSOCN")

I can also set the ODBC connection to pass-through queries as well in Access or VBA. But these connections work only when the connection string is IDENTICAL to what was originally used in my Cached Connection code. So, when I need an ADODB connection (as it seems sometimes ADO is needed?), the string obviously isn't going to be identical.
For Example:

 Dim cn As New ADODB.Connection
 cn.Open "Provider = sqloledb;Data Source=*same as "SERVER"*;Initial Catalog=*same as "DATABASE"*;User Id=****;Password=****"

This type of connection only works if I supply a User Id and Password. How can I write it so that I don't need them? ~Thanks!

Erik A
  • 31,639
  • 12
  • 42
  • 67
LauraNorth
  • 182
  • 3
  • 11
  • The best way to hide a user name and password is to not use a user name and password :-) If possible, consider using a [trusted connection](http://stackoverflow.com/a/1250556/772086) (Windows authentication). – Mike Nov 15 '14 at 00:49
  • I agree wholeheartedly Mike! The problem is that I work remotely from Wisconsin and I have 20+ users in Illinois who are also working both from "work" and remotely either from home or a work computer on the road. So, the logistics of keeping all those authentications strait gets tricky. Also, I'm just the DBA for a couple of the databases on the server - people above me don't want to deal with managing authentications. – LauraNorth Nov 15 '14 at 21:03
  • I may have a working solution, but does anyone see danger in this approach before I put it as an answer? I created two public variables "strUID" and "strPWD" that get set when a user clicks my login screen (ex, "strUID ' Forms!FRM_login!txtUserID"). Then I reference these whenever I need to use an ADO connection string. I'm fairly new in this coding world so I just don't want to compromise my user's security with any "newbie's" mistakes! Thanks all! – LauraNorth Nov 15 '14 at 21:46
  • When I set public variables like my above example, are the values stored in plain text anywhere? Do I need to "erase" the public variables when the application closes? Thanks again! :) – LauraNorth Nov 15 '14 at 21:49
  • I've read using TempVars (in Access 2007 and later) is better than using public/global variables because public/global variables loose their value if Access encounters an error. TempVars do not. – LauraNorth Nov 22 '14 at 04:59
  • I'm not familiar with krish KM's suggestion below, and not sure what how compiling the DB to ACCDE affects your ability to edit the VBA project later. I just thought I'd comment on another option such as using encryption/decryption functions in VB6 (VBA) to mask the UID and Password. These could be stored in a public variable, but would not be readable. [Here's a link to an SO discussion on this topic](http://stackoverflow.com/questions/7025644/vb6-encrypt-text-using-password) if interested. – CBRF23 Nov 22 '14 at 22:42

1 Answers1

1

Although ACCESS has some weak points regarding security, you can do few things to minimize the risks. One of them would be compile the DB to ACCDE. This way VBA is compiled and not visible.

You can create a public function that returns a string

Public Function GET_CONNECTION_STRING() as STRING
' construct your connection string here with server name and password
    GET_CONNECTION_STRING = "DRIVER={" & Driver & "};PORT=" & mPort & ";DATABASE=" & mDatabase & ";SERVER={" & mServer & "};UID=" & mUser & ";PWD={" & mPassword & "};"
End Function

then create an AutoExe macro that runs when the application is opened. in your AutoExe perform refreshing links to your linked tables. something similar to what you have.

For Each tdf In db.TableDefs
   If tdf.connect <> vbNullString Then
       tdf.connect = GET_CONNECTION_STRING & ";TABLE=" & tdf.name
       tdf.RefreshLink
    End If
Next tdf

you can do the same for existing pass through queries:

For Each myQuerydef In MyDB.QueryDefs
    If Left(myQuerydef.connect, 4) = "ODBC" Then
        myQuerydef.connect = "ODBC;" & GET_CONNECTION_STRING
        myQuerydef.Close
    End If
   Next

in addition you can have some other public functions to get current logged in username. something like

public function getCrruserID() as int
   'check your public variable crr_user_id if its empty redirect to login
   if nz(crr_user_id,0) = 0 then
     'go to login and save the user id after successful login
   else
      getCrruserID = crr_user_id
   end if
end function

use simple DAO to execute sql code like

dim db as DAO.Database
set db = currentdb
dim rs as Dao.Recordset
set rs = db.openrecordset("select something from your linked table")

or

db.execute "update command", dbfailonerror

to your last question. if you save something in memory it will be destroyed once your application is closed.

EDIT: if you have more than 50 linked tables it might be not a good idea to refresh them at every startup. Instead you can create a Local table containing your [local_Appversion, isFreshInstall] and some other variables as per your need. Every time your user receives an update the freshInstall will be true and code your App to connect and refresh all tables. (just to make sure client will get uninterrupted connection)

so in your autoExe code: if its freshInstall then connect and refreshlinks if not just set the connectionString. (usually a splash screen after login to perform this action) After successful connection just update the local isFreshInstall value to false for a quicker start next time.

you can also have a dedicated menu where user can click and refresh links manually.(in case if the connection get dropped) something like custom menu for access

if your organisation has a domain you can allow trusted connection using windows login name good luck.

Krish
  • 5,917
  • 2
  • 14
  • 35
  • Thank you Krish! I did not know about the option to compile to an ACCDE - I will definitely take that advice. It seems that if I do that, then the public variables I use won't be visible and will be destroyed when the application is destroyed. – LauraNorth Nov 22 '14 at 04:49
  • Also, per your code suggestion, that's what I started out with before I read Clothier's Blog referenced above (see also http://stackoverflow.com/questions/23249865/how-to-link-and-odbc-table-to-ms-access-database-using-vb-and-without-connecting/23252890#23252890). I don't know if one is better than the other, but it seems that not having to re-link everything on log-in maybe quicker. – LauraNorth Nov 22 '14 at 04:57
  • @LauraNorth have added few more suggestions to the answer post. – Krish Nov 22 '14 at 11:53