After upgrading to 8.3, one functionality that broke for me was my LDAP script that enable users to search for users and share resources with them (trends, messages, etc). This post helped shape my 8.1 code. The new LDAPHelper requirements are documented in the 8.3 javadoc - which now requires adding a context to to the LDAPHelper, the password needs to be a SecreteConfig type, and you need to define getReturnedAttributes function.
I have my 8.1 LDAP script updated to with with 8.3 using a plain text password but ideally this code could be modified to work with the secrets provider. Currently Im getting a type incompatibility between what the secrets library provides; com.inductiveautomation.ignition.common.secrets.PyPlaintext and what LDAPHelper needs: com.inductiveautomation.ignition.gateway.secrets.Plaintext. Any help here would be appreciated
from com.inductiveautomation.ignition.gateway.authentication.impl import LDAPHelper
from com.inductiveautomation.ignition.common.util import LoggerEx
from com.inductiveautomation.ignition.gateway import IgnitionGateway
from com.inductiveautomation.ignition.gateway.secrets import Plaintext, SecretConfig
class mySearchHandlerClass(LDAPHelper.SearchHandler):
"""Custom LDAP search handler class used to manage results from LDAP queries in Ignition.
"""
def __init__(self):
self.ctx = None
self.result = None
self.results = []
return
def create(self, ctx, result):
self.ctx = ctx
self.result = result
return self.result
def getNoun(self):
return 'LDAP'
def getReturnedAttributes(self):
# New required for 8.3
# Return None or [] to fetch all, or specify subset like:
return ["sAMAccountName", "cn", "mail", "givenName", "sn"]
class search(object):
"""
LDAP interface class that configures a secure connection and provides helper functions
to query Active Directory for users, emails, and roles.
Initializes connection settings, credentials, and logging for use with Ignition's LDAPHelper class.
ex:
LDAP = LDAP.search() # create LDAP search class instance
results = LDAP.getUserByName('Test name') # return results given search string
"""
builder = LoggerEx.newBuilder()
search_handler = mySearchHandlerClass()
logger = builder.build('LDAP_INTEGRATION')
PRIMARY_DOMAIN_CONTROLLER = "SERVERNAME"
DC_PORT_PRIMARY = "636"
ROLE_ID = "CN"
ROLE_ATTR = "memberOf"
USER_ATTR = "sAMAccountName"
CONTACT_ATTR = ["mail","proxyAddresses","phone"]
def __init__(self):
context = IgnitionGateway.get() # New required for 8.3
self.instance = LDAPHelper(context, self.logger)
self.instance.setLdapHost(self.PRIMARY_DOMAIN_CONTROLLER)
self.instance.setLdapPort(self.DC_PORT_PRIMARY)
self.instance.setUseSSL(True)
self.instance.setProfileUsername("username@Domain.com")
password = "plain text pass"
systemEncryptionService = IgnitionGateway.getSystemEncryptionService(context)
plaintext = Plaintext.fromString(password)
ciphertext = systemEncryptionService.encryptToJson(plaintext)
secret_config = SecretConfig.Embedded.embedded(ciphertext)
self.instance.setProfilePassword(secret_config) # new for 8.3
self.instance.setReadTimeout(60000)
self.instance.setPageSize(1000)
def getReadTimeout(self):
"""
Returns the configured LDAP read timeout value.
Returns:
int: Timeout duration in milliseconds.
"""
return self.instance.getReadTimeout()
def getUserByName(self, searchUser = ''):
"""
Searches for a user in Active Directory by matching their name or username.
Supports inputs in the format of 'lastname,firstname', 'firstname lastname', or a simple username.
Builds a flexible LDAP query accordingly and executes it.
Args:
searchUser (str): Input string to search (username or name format).
Returns:
list: LDAP search results matching the given user input.
"""
if ',' in searchUser: #account for "lastname,firstname" format
names = searchUser.replace(' ','').split(',')
query = "(&(objectClass=user)(!(objectClass=computer))(&(givenName=" + names[1] + "*)(sn=" + names[0] + "*)))"
elif ' ' in searchUser: #account for "firstname lastname" format
names = searchUser.split(' ')
query = "(&(objectClass=user)(!(objectClass=computer))(&(givenName=" + names[0] + "*)(sn=" + names[1] + "*)))"
else:
query = "(&(objectClass=user)(!(objectClass=computer))(|(sAMAccountName=" + searchUser + "*)(givenName=" + searchUser + "*)(sn=" + searchUser + "*)))"
attrs = []
base = ['DC=DOMAIN,DC=PATH']
results = self.instance.search(base, query, attrs,self.search_handler)
#results2 = self.instance.parseBasePatternString(str(results))
return results