Question

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

  1. With user logged into Windows as a domain user, they login to the HMI using the same windows credentials - everything goes smoothly.

  2. Network connection goes down and the user restarts the computer.

  3. The user can login to Windows as before using the same domain logon (with the Windows cached user allowing this)

  4. 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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top