Question
· Mar 31, 2017

Programatic User Authentication against windows AD

Hi,

Does calling the BIND method of %SYS.LDAP, with the username, domain and password of the user that  needs to be authenticated- the right way to authenticate him/her ?

Also - am I correct in assuming that something like this is independant to (and I don't  need to specify setting for),  System Security -> LDAP Options 

Thanks

Steve

Discussion (3)2
Log in or sign up to continue

Writing your own authentication code using the %SYS.LDAP class is independent of the LDAP authentication settings in the portal, yes.

%SYS.LDAP.Binds is the correct authentication method only if you're coming from a Windows machine (and going to a Windows AD server, which you said you are.)  If you're running Cache on Linux or any other non-Windows OS, you should use SimpleBinds instead.

The arguments to Binds aren't quite as you've listed them - I'd recommend looking at the class documentation on them.  I'd also recommend using the StartTLSs method first, to protect the user's credentials.

Steve,

Here is some sample code that should help get you going in the right direction.  NOTE - the byRef LD argument is a handle for the connection to the LDAP server and it needs to be cleaned up when you're done if you're going to fetch any attributes.  

(sorry for the messed up indentation)

 /// Authenticates against the configured domain, with username/password, passing a resulting a status ByRef and a returning success/failure value
ClassMethod Authenticate(username As %String, password As %String, ByRef Status As %Status, ByRef LD As %Integer) As %Boolean
{
Set Status=$$$OK, ret=0
If ('$data(username))||('$data(password)) 
    Set Status=$$$ERROR($$$GeneralError,"Both fields are required") 
    Quit 0
}

Set sc=$$$OK
Try {
//Connect to the LDAP server
Set LDAPServer="myldapserver.mydomain.com"
Set sc=$$$OK
Set LD=##class(%SYS.LDAP).Init(LDAPServer)
If LD=0 {
        Set LDAPStatus=##class(%SYS.LDAP).GetLastError()
        Set sc=$$$ERROR($$$GeneralError,"LDAP Init Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
Else {
    //Authenticate the passed in user by using the Binds command 
    Set Domain=..GetDomain()
    If ($$$isWINDOWS) {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    Else {
        Set LDAPStatus=##Class(%SYS.LDAP).Binds(LD,"",$lb(username,Domain,password),$$$LDAPAUTHNEGOTIATE)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP Binds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    } 
}
ElseIf ($$$isUNIX) {
    Set cert = ..GetCert()
    Set LDAPStatus=##Class(%SYS.LDAP).SetOption(LD,$$$LDAPOPTXTLSCACERTFILE,cert)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SetOption Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
        Do ..RotateOnFailure(sc)
Else {
        Set LDAPStatus=##Class(%SYS.LDAP).StartTLSs(LD)
        If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP StartTLSs Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
If LDAPStatus=$$$LDAPSUCCESS {
    Set LDAPStatus=##Class(%SYS.LDAP).SimpleBinds(LD,username_"@"_Domain,password)
    If LDAPStatus'=$$$LDAPSUCCESS {
        Set sc=$$$ERROR($$$GeneralError,"LDAP SimpleBinds Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
    }
}
Else {
    Set LDAPStatus=$$$LDAPAUTHMETHODNOTSUPPORTED
}
If (LDAPStatus'=$$$LDAPSUCCESS)&&($$$ISOK(sc)) {
    Set sc=$$$ERROR($$$GeneralError,"LDAP API Error: "_##class(%SYS.LDAP).Err2String(LDAPStatus))
}
} 
Catch err {
    Set sc = $$$ERROR($$$GeneralError,err.Data) 
}
If $$$ISOK(sc) {
     Set ret = 1
Else {
    Set Status = sc 
}

Quit ret
}