I don't know if you can do it directly from a Server Module, but you can using Integrator. Its how we do it at least.
Look into the OpenLDAPService.
https://docs.lansa.com/14/en/lansa093/i ... 7_3640.htm
We wrap this type of stuff up in a LDAP Process with LDAP Functions which makes them really easy to call from a Server Module.
This is our Auth function, the *LDAPCONNECTION and *LDAPCONNECTPWD are System Variables that contain the appropriate info.
In our case, when a user is authenticated, we also return certain attributes and membership.
Code: Select all
* ================================================================================
* Description : Connects to Active Directory to authenticate a user by SAMACCOUNTNAME
* Written By : JRYOUNG
* Exchange : INPUT - wk_Username wk_Password
* : OUTPUT - wk_Status
* Notes : Attributes are returned in the AttributesList
* : Errors are returned in the MessagesList
* : wk_Status will be OK if all commands succeed, otherwase it will be ER
* Usage : The calling program should pass the MessagesList and AttributesList
* : See the below definitions of the list for their structure
* ================================================================================
function options(*DIRECT) rcv_list(#MessagesList #AttributeList #MembershipList)
* ================================================================================
* INPUT/OUTPUT Fields
* ================================================================================
group_by name(#InputFields) fields(#wk_Username #wk_Password)
group_by name(#OutputFields) fields(#wk_Status)
* ================================================================================
* INPUT/OUTPUT Lists
* ================================================================================
def_list name(#MessagesList) fields(#STD_STRNG) type(*WORKING) entrys(*MAX)
def_list name(#AttributeList) fields(#STD_TEXTL #STD_STRNG) type(*WORKING) entrys(*MAX)
def_list name(#MembershipList) fields(#STD_TEXTL #STD_STRNG) type(*WORKING) entrys(*MAX)
* ================================================================================
* Components
* ================================================================================
define_com class(#ServerTraceHandler) scope(*APPLICATION)
* ================================================================================
* Working Fields
* ================================================================================
define field(#LDAPServer) type(*STRING)
define field(#DN) type(*STRING) length(512)
* ================================================================================
* Working Lists
* ================================================================================
def_list name(#WorkingList) fields(#DN) counter(#LISTCOUNT) type(*WORKING) entrys(*MAX)
* ================================================================================
* Default Values
* ================================================================================
#LDAPServer := "*****************"
* ================================================================================
* Main
* ================================================================================
exchange fields(#wk_Status) option(*ALWAYS)
#wk_Status := ER
if (#COM_OWNER.Connect <> OK)
return
endif
if (#COM_OWNER.Search <> OK)
#COM_OWNER.Disconnect
return
endif
if (#COM_OWNER.Authenticate <> OK)
#COM_OWNER.Disconnect
return
endif
if (#COM_OWNER.LoadAttributes <> OK)
#COM_OWNER.Disconnect
return
endif
if (#COM_OWNER.LoadMembership <> OK)
#COM_OWNER.Disconnect
return
endif
#COM_OWNER.Disconnect
#wk_Status := OK
* ================================================================================
* Routines
* ================================================================================
mthroutine name(Connect)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
* connect this JSMX client to the Java Services Manager, and to start a thread for the service.
use builtin(JSMX_OPEN) to_get(#JSMXSTS #JSMXMSG #JSMXHDLE)
if (#COM_OWNER.check( #JSMXSTS #JSMXMSG ) = False)
return
endif
* load and initialize the service using the values defined in the OpenLDAPService.properties file.
#JSMXCMD := 'SERVICE_LOAD SERVICE (OpenLDAPService) TRACE(*NO)'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
* establish a connection to the LDAP server.
#JSMXCMD := ('BIND HOST(&1) DN(&2) PASSWORD(&3)').Substitute( #LDAPServer *LDAPCONNECTDN *LDAPCONNECTPWD )
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
#status := OK
endroutine
mthroutine name(Search)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
* search the ldap entries for a user based on the samaccountname (username). This will return a distingished name (DN) in the list if found
#JSMXCMD := ("SEARCH DN(DC=************************,DC=com) FILTER(samaccountname=&1) SCOPE(*SUB) SERVICE_LIST(DN)").Substitute( #wk_Username )
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #workingList)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
if ((#JSMXSTS = OK) *And (#LISTCOUNT = 1))
get_entry number(1) from_list(#workingList)
if (#DN = *BLANKS)
* we found an entry but did not get the distinguished name
#STD_STRNG := ("Could not retrieve the DN for &1").Substitute( #wk_Username )
add_entry to_list(#MessagesList)
return
endif
else
* we did not get one and only one entry in the list, therefore something went wrong
#STD_STRNG := "Invalid Credentials"
add_entry to_list(#MessagesList)
return
endif
#status := OK
endroutine
mthroutine name(Authenticate)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
#JSMXCMD := ('BIND HOST(&1) DN(&2) PASSWORD("&3")').Substitute( #LDAPServer #DN #wk_Password )
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
#status := OK
endroutine
mthroutine name(LoadAttributes)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
* get the attributes for the DN
#JSMXCMD := ('GET DN(&1) ATTRIBUTES(DISTINGUISHEDNAME, CN, GIVENNAME, DISPLAYNAME) SERVICE_LIST(STD_TEXTL STD_STRNG)').Substitute( #DN )
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #AttributeList)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
#status := OK
endroutine
mthroutine name(LoadMembership)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
* get the attributes for the DN
#JSMXCMD := ('GET DN(&1) ATTRIBUTES(MEMBEROF) SERVICE_LIST(STD_TEXTL STD_STRNG)').Substitute( #DN )
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG #MembershipList)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
#status := OK
endroutine
mthroutine name(Disconnect)
define_map for(*RESULT) class(#wk_Status) name(#status)
#status := ER
* disconnect from the LDAP Server when we have completed.
#JSMXCMD := 'UNBIND'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
* unload the service and to remove the temporary directory.
#JSMXCMD := 'SERVICE_UNLOAD'
use builtin(JSMX_COMMAND) with_args(#JSMXHDLE #JSMXCMD) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
* finally close the service.
use builtin(JSMX_CLOSE) with_args(#JSMXHDLE) to_get(#JSMXSTS #JSMXMSG)
if (#COM_OWNER.Check( #JSMXSTS #JSMXMSG ) = False)
return
endif
#status := OK
endroutine
mthroutine name(Check)
define_map for(*INPUT) class(#JSMXSTS) name(#status)
define_map for(*INPUT) class(#JSMXMSG) name(#message)
define_map for(*RESULT) class(#PRIM_BOLN) name(#isOk)
#isOk := False
if (#status <> OK)
#STD_STRNG := #message
add_entry to_list(#MessagesList)
return
endif
#isOk := True
endroutine
Then in a Server Module, we call the function, exchanging the username, password and working lists
Code: Select all
* authenticate the user
exchange fields(#wk_Username #wk_Password)
call process(*DIRECT) function(LDAPN01) pass_lst(#MessageList #AttributeList #MembershipList)
Personally, Integrator is a bit of brain shock, while this works for us, if there is a way to query AD without going through Integrator, I would probably go that way. When I had to write this, there was no other way.
Hope this helps,
Joe