At my company we have a custom HMI. This HMI can login using the domain of the computer if the user would like to. Here's the scenario we're currently trying to solve
With user logged into Windows as a domain user, they login to the HMI using the same windows credentials - everything goes smoothly.
Network connection goes down and the user restarts the computer.
The user can login to Windows as before using the same domain logon (with the Windows cached user allowing this)
The user tries to login to our HMI and they can't because I haven't figured out how to access these cached active directory users.
Here's the code I'm using right now to detect if the user is member of one of the groups allowed to login to the HMI. These groups are stored in our SQL database, and are stored as Strings like SERVER\BUILDER
for example
If DuplicateToken(token, 2, tokenDuplicate) <> 0 Then
tempWindowsIdentity = New WindowsIdentity(tokenDuplicate)
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal)
WinPrincipal = New WindowsPrincipal(tempWindowsIdentity)
End If
If WinPrincipal.IsInRole(user.Group) Then
'Success - obviously there's more code after this
End If
The problem is that when the user is not connected to the domain I get an exception on the IsInRole
method. I took a look at the overloading in the method and tried using the SID equivalent of the user.Group instead of the literal String. This seems to work, but now another problem comes up. When the user is not on the network I can't translate the Group Name (string from SQL) into these SIDs.
My current workaround is that when the user is connected to the domain, I save the SIDs and the groups into a lookup table (encrypted), then when the network is not connected, I take the group name from the database and literally lookup the SID string in the table.
The code I'm using to convert the group name to SID is the following
'' Get all groups available to the user
For i As Integer = 0 To WindowsIdentity.GetCurrent.Groups.Count - 1
Dim ir As IdentityReference = WindowsIdentity.GetCurrent.Groups(i)
sid(i) = New SecurityIdentifier(ir.Value)
sidName(i) = CType(ir.Translate(GetType(NTAccount)), NTAccount).Value
' Write to file as csv
writer.WriteLine(sidName(i) + "," + sid(i).ToString)
Next
Then I lookup the group name like so
If File.Exists(FILEPATH) = True Then
Dim reader As New StreamReader(FILEPATH)
While Not reader.EndOfStream
Dim sTemp() As String = reader.ReadLine.Split(",")
If groupName.Equals(sTemp(0)) Then
Return New SecurityIdentifier(sTemp(1))
End If
End While
End If
The reason I can't translate the group name to a SID when not on the network is because the IdentityReference.Translate
throws an exception because it can't see the domain.
So, finally after all this explanation, here's what I'm looking for. I'm thinking that there must be access somewhere for me to get the SID from a group name, because windows MUST be storing it somewhere, otherwise I wouldn't be able to login to windows when not connected to the network.
I've done a lot of searching and I haven't been able to figure out where these cached credentials are stored. Any help would be appreciated and if I haven't been clear enough let me know and I'll try to explain as best I can.
I know it is old, but it was actual for me. As a familiar post I will link this: Determine User Active Directory Groups from Local Machine off Network
The proposed solution was to store the SID in a local space which seems to be the best idea.