update active directory interface to sync to mssql and to sync custom attributes

This commit is contained in:
Jonathan Jenne 2019-04-17 16:29:44 +02:00
parent 32b000c947
commit 0374016cde
10 changed files with 437 additions and 133 deletions

View File

@ -8,12 +8,12 @@ Public Class ADSyncJob
Inherits JobBase
Implements IJob(Of ADSyncArgs)
Public Sub New(LogConfig As LogConfig, Firebird As Firebird)
MyBase.New(LogConfig, Firebird)
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, MSSQL As MSSQLServer)
MyBase.New(LogConfig, Firebird, MSSQL)
End Sub
Public Sub Start(Arguments As ADSyncArgs) Implements IJob(Of ADSyncArgs).Start
Dim oSync = New ActiveDirectoryInterface(_LogConfig, _Firebird, Arguments.RootPath)
Dim oSync = New ActiveDirectoryInterface(_LogConfig, _Firebird, _MSSQL, Arguments.RootPath)
Dim oJobName As String = [GetType]().Name
_Logger.Info("Running job {0}", oJobName)

View File

@ -5,10 +5,12 @@ Public Class JobBase
Protected _LogConfig As LogConfig
Protected _Logger As Logger
Protected _Firebird As Firebird
Protected _MSSQL As MSSQLServer
Public Sub New(LogConfig As LogConfig, Firebird As Firebird)
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, MSSQL As MSSQLServer)
_LogConfig = LogConfig
_Logger = LogConfig.GetLogger()
_Firebird = Firebird
_MSSQL = MSSQL
End Sub
End Class

View File

@ -6,9 +6,11 @@ Imports DigitalData.Modules.Logging
Public Class ActiveDirectoryInterface
Private _logConfig As LogConfig
Private _logger As Logger
Private _firebird As Firebird
Private _rootPath As String
Private ReadOnly _firebird As Firebird
Private ReadOnly _mssql As MSSQLServer
Private ReadOnly _rootPath As String
Private _rootNode As DirectoryEntry
Private Const SEARCH_LIMIT = 50000
@ -21,10 +23,11 @@ Public Class ActiveDirectoryInterface
Private Const NAME = "name"
Private Const OBJECTCATEGORY = "objectCategory"
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, Optional RootPath As String = Nothing)
Public Sub New(LogConfig As LogConfig, Firebird As Firebird, MSSQL As MSSQLServer, Optional RootPath As String = Nothing)
_logConfig = LogConfig
_logger = _logConfig.GetLogger()
_firebird = Firebird
_mssql = MSSQL
If RootPath Is Nothing Then
_rootPath = $"LDAP://{Environment.UserDomainName}"
@ -34,13 +37,21 @@ Public Class ActiveDirectoryInterface
End Sub
Public Function SyncUsersForGroup(GroupName As String) As List(Of ADUser)
Return SyncUsersForGroup(GroupName, New List(Of AttributeMapping))
End Function
Public Function SyncUsersForGroup(GroupName As String, AttributeMappings As List(Of AttributeMapping)) As List(Of ADUser)
Dim oUsers As New List(Of ADUser)
Dim oSyncedUsers As New List(Of ADUser)
Dim oGroupId As Int64 = Nothing
Dim oFirebirdSync As New SyncUsers.Firebird(_logConfig, _firebird)
Dim oSQLSync As New SyncUsers.MSSQL(_logConfig, _mssql)
Dim oSyncedUsersFirebird, oSyncedUsersMSSQL As List(Of ADUser)
Try
_logger.Debug("Fetching users from ActiveDirectory")
oUsers = ListUsers(GroupName)
oUsers = ListUsers(GroupName, AttributeMappings)
_logger.Debug("Found {0} users", oUsers.Count)
Catch ex As Exception
_logger.Error(ex)
@ -49,66 +60,22 @@ Public Class ActiveDirectoryInterface
If oUsers.Count = 0 Then
_logger.Debug("Group {0} does not contain any users.", GroupName)
Return oSyncedUsers
Return oUsers
End If
Try
_logger.Debug("Getting group Id for group {0}", GroupName)
oGroupId = GetGroupId(GroupName)
' Do the actual sync into firebird
If _firebird IsNot Nothing Then
oSyncedUsersFirebird = oFirebirdSync.SyncUsers(GroupName, oUsers, AttributeMappings)
_logger.Info("Synced {0} users to Firebird", oSyncedUsersFirebird.Count)
End If
If oGroupId = 0 Then
_logger.Warn("Group {0} does not exist in database. Exiting", GroupName)
Return Nothing
End If
' Do the actual sync into MSSQL
If _mssql IsNot Nothing Then
oSyncedUsersMSSQL = oSQLSync.SyncUsers(GroupName, oUsers, AttributeMappings)
_logger.Info("Synced {0} users to MSSQLServer", oSyncedUsersMSSQL.Count)
End If
_logger.Debug("Using group Id {0}", oGroupId)
Catch ex As Exception
_logger.Error(ex)
Return Nothing
End Try
For Each oUser In oUsers
Dim oUserId As Int64
Dim oUserExists As Boolean = False
' Check if user already exists
Try
_logger.Debug("Checking if user {0} exists", oUser)
oUserId = GetUserId(oUser.samAccountName)
oUserExists = Not IsNothing(oUserId)
_logger.Debug("User {0} exists in database: ", oUser, oUserExists)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not get UserId for user. Skipping")
Continue For
End Try
' I user does not exist, create a new user
Try
If Not oUserExists Then
_logger.Debug("Creating new user for {0}", oUser)
oUserId = CreateUser(oUser)
_logger.Debug("User created with Id {0}", oUserId)
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not create user. Skipping")
Continue For
End Try
' Add the user to group
Try
AddUserToGroup(oUserId, oGroupId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not add user to group. Skipping")
Continue For
End Try
oSyncedUsers.Add(oUser)
Next
Return oSyncedUsers
Return oUsers
End Function
Public Function Authenticate() As Boolean
@ -162,6 +129,10 @@ Public Class ActiveDirectoryInterface
End Function
Public Function ListUsers(GroupName As String) As List(Of ADUser)
Return ListUsers(GroupName, New List(Of AttributeMapping))
End Function
Public Function ListUsers(GroupName As String, AttributeMappings As List(Of AttributeMapping)) As List(Of ADUser)
Dim oUsers As New List(Of ADUser)
Try
@ -176,15 +147,33 @@ Public Class ActiveDirectoryInterface
For Each oMember As Principal In oMembers
If TypeOf oMember Is UserPrincipal Then
Dim oUser As UserPrincipal = DirectCast(oMember, UserPrincipal)
Dim oUserEx As UserPrincipalEx = UserPrincipalEx.FindByIdentity(oContext, oUser.SamAccountName)
Dim oCustomAttributes As New List(Of ADUser.CustomAttribute)
For Each oMap As AttributeMapping In AttributeMappings
Dim oAttributeValue = oUserEx.GetAttributeValue(oMap.AttributeName)
If oAttributeValue <> String.Empty Then
_logger.Debug("Attribute {0} is not empty.", oMap.AttributeName)
oCustomAttributes.Add(New ADUser.CustomAttribute() With {
.Name = oMap.AttributeName,
.Value = oAttributeValue,
.FirebirdSyskey = oMap.FirebirdSyskey,
.MSSQLColumn = oMap.MSSQLColumn
})
End If
Next
oUsers.Add(New ADUser() With {
.GUID = oUser.Guid,
.SId = oUser.Sid,
.samAccountName = oUser.SamAccountName,
.Surname = oUser.Surname,
.Middlename = oUser.MiddleName,
.GivenName = oUser.GivenName,
.Email = oUser.EmailAddress
.GUID = oUserEx.Guid,
.SId = oUserEx.Sid,
.samAccountName = oUserEx.SamAccountName,
.Surname = oUserEx.Surname,
.Middlename = oUserEx.MiddleName,
.GivenName = oUserEx.GivenName,
.Email = oUserEx.EmailAddress,
.CustomAttributes = oCustomAttributes
})
End If
Next
@ -199,68 +188,6 @@ Public Class ActiveDirectoryInterface
End Try
End Function
Private Function GetGroupId(GroupName As String) As Integer
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{GroupName}','002-NAME') from RDB$DATABASE"
Dim oGroupId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oGroupId) OrElse oGroupId = 0 Then
_logger.Debug("Group {0} not found in database", GroupName)
Return Nothing
End If
Return oGroupId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetUserId(UserName As String) As Integer
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{UserName}','001-USRNAME') from RDB$DATABASE"
Dim oResult = _firebird.GetScalarValue(oSQL)
If IsDBNull(oResult) Then
Return Nothing
End If
Return oResult
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function CreateUser(User As ADUser) As Int64
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER('{User.GivenName}', '{User.Surname}', '{User.samAccountName}', 'AD-Sync') from RDB$DATABASE"
Dim oUserId As Integer = _firebird.GetScalarValue(oSQL)
Return oUserId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function AddUserToGroup(UserId As Integer, GroupId As Integer) As Int64
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER2GROUP({UserId}, {GroupId}, 'AD-Sync') from RDB$DATABASE"
Dim oRecordId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oRecordId) Then
_logger.Warn("UserId {0} - GroupId {1} relation already exists.", UserId, GroupId)
Return Nothing
End If
Return oRecordId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetRootNode() As DirectoryEntry
Dim oEntry As New DirectoryEntry(_rootPath) With {
.AuthenticationType = AuthenticationTypes.Secure,

View File

@ -9,10 +9,19 @@ Public Class ADUser
Public Middlename As String
Public Email As String
Public CustomAttributes As List(Of CustomAttribute)
Public Overrides Function Equals(obj As Object) As Boolean
Return DirectCast(obj, ADUser).samAccountName
End Function
Public Overrides Function ToString() As String
Return samAccountName
End Function
Public Class CustomAttribute
Public Name As String
Public Value As Object
Public MSSQLColumn As String
Public FirebirdSyskey As String
End Class
End Class

View File

@ -0,0 +1,5 @@
Public Class AttributeMapping
Public AttributeName As String
Public FirebirdSyskey As String
Public MSSQLColumn As String
End Class

View File

@ -0,0 +1,8 @@
Public Interface ISyncUsers
Function SyncUsers(GroupName As String, Users As List(Of ADUser), PropertyMapping As List(Of AttributeMapping)) As List(Of ADUser)
Function GetGroupId(GroupName As String) As Integer
Function GetUserId(UserName As String) As Integer
Function CreateUser(User As ADUser) As Integer
Sub AddUserToGroup(UserId As Integer, GroupId As Integer)
Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer)
End Interface

View File

@ -0,0 +1,142 @@
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Interfaces
Imports DigitalData.Modules.Logging
Namespace SyncUsers
Public Class Firebird
Implements ISyncUsers
Private ReadOnly _logConfig As LogConfig
Private ReadOnly _logger As Logger
Private ReadOnly _firebird As Database.Firebird
Public Sub New(LogConfig As LogConfig, Firebird As Database.Firebird)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_firebird = Firebird
End Sub
Public Function SyncUsers(GroupName As String, Users As List(Of ADUser), PropertyMapping As List(Of AttributeMapping)) As List(Of ADUser) Implements ISyncUsers.SyncUsers
Dim oGroupId As Integer
Dim oSyncedUsers As New List(Of ADUser)
Try
_logger.Debug("Getting group Id for group {0}", GroupName)
oGroupId = GetGroupId(GroupName)
If oGroupId = 0 Then
_logger.Warn("Group {0} does not exist in database. Exiting", GroupName)
Return oSyncedUsers
End If
_logger.Debug("Using group Id {0}", oGroupId)
Catch ex As Exception
_logger.Error(ex)
Return oSyncedUsers
End Try
For Each oUser In Users
Dim oUserId As Int64
Dim oUserExists As Boolean = False
' Check if user already exists
Try
_logger.Debug("Checking if user {0} exists", oUser)
oUserId = GetUserId(oUser.samAccountName)
oUserExists = Not IsNothing(oUserId)
_logger.Debug("User {0} exists in database: ", oUser, oUserExists)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not get UserId for user. Skipping")
Continue For
End Try
' I user does not exist, create a new user
Try
If Not oUserExists Then
_logger.Debug("Creating new user for {0}", oUser)
oUserId = CreateUser(oUser)
_logger.Debug("User created with Id {0}", oUserId)
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not create user. Skipping")
Continue For
End Try
' Add the user to group
Try
AddUserToGroup(oUserId, oGroupId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not add user to group. Skipping")
Continue For
End Try
oSyncedUsers.Add(oUser)
Next
Return oSyncedUsers
End Function
Private Sub AddUserToGroup(UserId As Integer, GroupId As Integer) Implements ISyncUsers.AddUserToGroup
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER2GROUP({UserId}, {GroupId}, 'AD-Sync') from RDB$DATABASE"
Dim oRecordId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oRecordId) Then
_logger.Warn("UserId {0} - GroupId {1} relation already exists.", UserId, GroupId)
End If
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Sub
Private Function GetGroupId(GroupName As String) As Integer Implements ISyncUsers.GetGroupId
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{GroupName}','002-NAME') from RDB$DATABASE"
Dim oGroupId = _firebird.GetScalarValue(oSQL)
If IsDBNull(oGroupId) OrElse oGroupId = 0 Then
_logger.Debug("Group {0} not found in database", GroupName)
Return Nothing
End If
Return oGroupId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetUserId(UserName As String) As Integer Implements ISyncUsers.GetUserId
Try
Dim oSQL As String = $"SELECT FNICM_GET_RECORD4SYSKEY('{UserName}','001-USRNAME') from RDB$DATABASE"
Dim oResult = _firebird.GetScalarValue(oSQL)
If IsDBNull(oResult) Then
Return Nothing
End If
Return oResult
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function CreateUser(User As ADUser) As Integer Implements ISyncUsers.CreateUser
Try
Dim oSQL = $"SELECT FNICM_RADM_NEW_USER('{User.GivenName}', '{User.Surname}', '{User.samAccountName}', 'AD-Sync') from RDB$DATABASE"
Dim oUserId As Integer = _firebird.GetScalarValue(oSQL)
Return oUserId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer) Implements ISyncUsers.AddCustomAttributesToUser
Throw New NotImplementedException()
End Sub
End Class
End Namespace

View File

@ -0,0 +1,170 @@
Imports DigitalData.Modules.Database
Imports DigitalData.Modules.Logging
Namespace SyncUsers
Public Class MSSQL
Implements ISyncUsers
Private _logConfig As LogConfig
Private _logger As Logger
Private _mssql As MSSQLServer
Public Sub New(LogConfig As LogConfig, MSSQL As Database.MSSQLServer)
_logConfig = LogConfig
_logger = LogConfig.GetLogger()
_mssql = MSSQL
End Sub
Public Function SyncUsers(GroupName As String, Users As List(Of ADUser), PropertyMapping As List(Of AttributeMapping)) As List(Of ADUser) Implements ISyncUsers.SyncUsers
Dim oGroupId As Integer
Dim oSyncedUsers As New List(Of ADUser)
Try
_logger.Debug("Getting group Id for group {0}", GroupName)
oGroupId = GetGroupId(GroupName)
If oGroupId = 0 Then
_logger.Warn("Group {0} does not exist in database. Exiting", GroupName)
Return oSyncedUsers
End If
_logger.Debug("Using group Id {0}", oGroupId)
Catch ex As Exception
_logger.Error(ex)
Return oSyncedUsers
End Try
For Each oUser In Users
Dim oUserId As Int64
Dim oUserExists As Boolean = False
' Check if user already exists
Try
_logger.Debug("Checking if user {0} exists", oUser)
oUserId = GetUserId(oUser.samAccountName)
oUserExists = oUserId > 0
_logger.Debug("User {0} exists in database: ", oUser, oUserExists)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not get UserId for user. Skipping")
Continue For
End Try
' I user does not exist, create a new user
Try
If Not oUserExists Then
_logger.Debug("Creating new user for {0}", oUser)
oUserId = CreateUser(oUser)
_logger.Debug("User created with Id {0}", oUserId)
End If
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not create user. Skipping")
Continue For
End Try
' Add custom attributes to user
Try
AddCustomAttributesToUser(oUser, oUserId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not add custom attributes to user {0}. Continuing", oUser)
End Try
' Add the user to group
Try
AddUserToGroup(oUserId, oGroupId)
Catch ex As Exception
_logger.Error(ex)
_logger.Warn("Could not add user {0} to group {1}. Skipping", oUser, GroupName)
Continue For
End Try
oSyncedUsers.Add(oUser)
Next
Return oSyncedUsers
End Function
Private Sub AddUserToGroup(UserId As Integer, GroupId As Integer) Implements ISyncUsers.AddUserToGroup
Try
Dim oSQL As String = $"INSERT INTO TBDD_GROUPS_USER (USER_ID, GROUP_ID) VALUES ({UserId}, {GroupId})"
Dim oResult = _mssql.NewExecutenonQuery(oSQL)
If oResult = False Then
Throw New Exception("Error while adding user to group!")
End If
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Sub
Private Function GetGroupId(GroupName As String) As Integer Implements ISyncUsers.GetGroupId
Try
Dim oSQL As String = $"SELECT GUID FROM TBDD_GROUPS WHERE NAME = '{GroupName}'"
Dim oGroupId = _mssql.NewExecuteScalar(oSQL)
If IsDBNull(oGroupId) OrElse oGroupId = 0 Then
_logger.Debug("Group {0} not found in database", GroupName)
Return 0
End If
Return oGroupId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function GetUserId(UserName As String) As Integer Implements ISyncUsers.GetUserId
Try
Dim oSQL As String = $"SELECT GUID FROM TBDD_USER WHERE USERNAME = '{UserName}'"
Dim oUserId = _mssql.NewExecuteScalar(oSQL)
If IsDBNull(oUserId) OrElse oUserId = 0 Then
Return 0
End If
Return oUserId
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Private Function CreateUser(User As ADUser) As Integer Implements ISyncUsers.CreateUser
Try
Dim oSQL As String = $"INSERT INTO TBDD_USER (PRENAME, NAME, USERNAME, EMAIL) VALUES ('{User.GivenName}', '{User.Surname}', '{User.samAccountName}', '{User.Email}')"
Dim oResult = _mssql.NewExecutenonQuery(oSQL)
If oResult = True Then
Dim oUserId = _mssql.NewExecuteScalar("SELECT MAX(GUID) FROM TBDD_USER")
Return oUserId
Else
Throw New Exception("Error while inserting user!")
End If
Catch ex As Exception
_logger.Error(ex)
Throw ex
End Try
End Function
Public Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer) Implements ISyncUsers.AddCustomAttributesToUser
Dim oCustomAttributes = User.CustomAttributes
For Each oAttribute In oCustomAttributes
Dim oSQL As String = $"UPDATE TBDD_USER SET {oAttribute.MSSQLColumn} = '{oAttribute.Value}' WHERE GUID = {UserId}"
Dim oResult = _mssql.NewExecutenonQuery(oSQL)
If oResult = False Then
_logger.Warn("Custom Attribute {0} could not be added to user {1}", oAttribute.Name, User.samAccountName)
Continue For
End If
Next
End Sub
End Class
End Namespace

View File

@ -0,0 +1,36 @@
Imports System.DirectoryServices.AccountManagement
<DirectoryRdnPrefix("CN")>
<DirectoryObjectClass("Person")>
Public Class UserPrincipalEx
Inherits UserPrincipal
Public Sub New(Context As PrincipalContext)
MyBase.New(Context)
End Sub
Public Sub New(Context As PrincipalContext, samAccountName As String, Password As String, Enabled As Boolean)
MyBase.New(Context, samAccountName, Password, Enabled)
End Sub
Public Overloads Shared Function FindByIdentity(ByVal Context As PrincipalContext, ByVal IdentityValue As String) As UserPrincipalEx
Return CType(FindByIdentityWithType(Context, GetType(UserPrincipalEx), IdentityValue), UserPrincipalEx)
End Function
Public Overloads Shared Function FindByIdentity(ByVal Context As PrincipalContext, ByVal IdentityType As IdentityType, ByVal IdentityValue As String) As UserPrincipalEx
Return CType(FindByIdentityWithType(Context, GetType(UserPrincipalEx), IdentityType, IdentityValue), UserPrincipalEx)
End Function
Public Function GetAttributeValue(AttributeName As String) As String
Return TryGetAttribute(AttributeName)
End Function
Private Function TryGetAttribute(AttributeName As String) As String
Dim oAttribute = ExtensionGet(AttributeName)
If oAttribute.Length <> 1 Then
Return String.Empty
End If
Return CStr(oAttribute(0))
End Function
End Class

View File

@ -77,7 +77,12 @@
<Compile Include="ActiveDirectoryInterface.vb" />
<Compile Include="ActiveDirectoryInterface\ActiveDirectoryGroup.vb" />
<Compile Include="ActiveDirectoryInterface\ActiveDirectoryUser.vb" />
<Compile Include="ActiveDirectoryInterface\AttributeMap.vb" />
<Compile Include="ActiveDirectoryInterface\ISyncUsers.vb" />
<Compile Include="ActiveDirectoryInterface\SyncUsers.Firebird.vb" />
<Compile Include="ActiveDirectoryInterface\SyncUsers.MSSQL.vb" />
<Compile Include="ActiveDirectoryInterface\UserEqualityComparer.vb" />
<Compile Include="ActiveDirectoryInterface\UserPrincipalEx.vb" />
<Compile Include="ZUGFeRDInterface\Exceptions.vb" />
<Compile Include="My Project\AssemblyInfo.vb" />
<Compile Include="My Project\Application.Designer.vb">