Written by

Sr Application Development Analyst at The Ohio State University Wexner Medical Center
Question Scott Roth · Apr 6, 2018

Delegated Sign On Bypass

Is there a way to make the system users like _SYSTEM and ensadm bypass the Delegated sign-on and not cause it to fill up the Audit trail with "Programmer mode login failure"?? I figured I still had to leave password login enabled for the background users to run. How would I script if username = "_SYSTEM" then don't do the Delegated sign on?

Here is my ZAUTHENTICATE

s $zt="Error"
  s Status = 0
  i Password="" {
    s Status= $SYSTEM.Status.Error($$$InvalidUsernameOrPassword)
    g Error
  }
  i $$$WindowsLDAPServer {
    s AdminDN=$Get(^OSUMCLDAP("User"))
    s AdminPW=$Get(^OSUMCLDAP("Pass"))
  }
  //Connect to the LDAP server
  s LD=##Class(%SYS.LDAP).Init($$$LDAPServer)
  i LD=0 {
    s Status=##Class(%SYS.LDAP).GetLastError()
    s Status="Init error: "_Status_" - "_##Class(%SYS.LDAP).Err2String(Status) 
    g Error
  }
  //Authenticate the passed in user by using the Binds command 
  //s Domain="OSUMC.EDU"
  #; Begin Binding Process"
  s Status=##Class(%SYS.LDAP).SimpleBinds(LD,AdminDN,AdminPW)
  i Status'=$$$LDAPSUCCESS  {
    s Status = Status_", ldap_Simple_Bind(AdminDN) - "_##Class(%SYS.LDAP).Err2String(Status) 
    #;w !,Status
    g Error
  }
  i $$$WindowsLDAPServer {
    s Filter=$$$WindowsFilter_"="_Username
  }
  i $$$WindowsLDAPServer {
    s AttributeList=$$$WindowsAttributeList
  } 
  i $$$WindowsLDAPServer {
    s BaseDN=$$$WindowsBaseDN
  } 
  s SearchScope=$$$LDAPSCOPESUBTREE
  s Timeout=30
  s SizeLimit=1
  s Status=##Class(%SYS.LDAP).SearchExts(LD,BaseDN,SearchScope,Filter,AttributeList,0,"","",Timeout,"",.SearchResult)
  i Status'=$$$LDAPSUCCESS {
    i Status=$$$XLDAPFILTERERROR {
      s Status="1,User "_Username_" does not exist"
      w !,Status
    } else {
      s Status=Status_",ldap_Search_Ext - "_##Class(%SYS.LDAP).Err2String(Status)
    }
    g Error
  }
  s NumEntries=##Class(%SYS.LDAP).CountEntries(LD,SearchResult)
  i NumEntries=-1 {
    s Status=##Class(%SYS.LDAP).GetError(LD)
    s Status=Status_",ldap_Count_Entries - "_##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  i NumEntries=0 {
    s Status="1,User "_Username_" does not exist"
    g Error
  }
  i NumEntries>1 {
    s Status="1,LDAP Filter is not unique"
    g Error
  }
  s CurrentEntry=##Class(%SYS.LDAP).FirstEntry(LD,SearchResult)
  i CurrentEntry=0 {
    s Status=##Class(%SYS.LDAP).GetError(LD) 
    s Status=Status_",ldap_FirstEntry - "_##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  s DN=##Class(%SYS.LDAP).GetDN(LD,CurrentEntry) 
  i Password="" {
    s Status="1,ldap_Simple_Bind("_DN_") - password cannot be null"
    g Error
  }
  s Status=##Class(%SYS.LDAP).SimpleBinds(LD,DN,Password)
  i Status'=$$$LDAPSUCCESS {
    s Status=Status_",ldap_Simple_Bind("_DN_") - "_##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  s Attribute=##Class(%SYS.LDAP).FirstAttribute(LD,CurrentEntry,.Ptr)
  while (Attribute'="") {
    s Values=##Class(%SYS.LDAP).GetValuesLen(LD,CurrentEntry,Attribute)
    #;Values:"_Values
    s Properties("Attributes",Attribute)=Values
    s Attribute=##Class(%SYS.LDAP).NextAttribute(LD,CurrentEntry,.Ptr)
  }
  s Properties("Username")=Username
  s Properties("FullName")=$li(Properties("Attributes","displayName"))
  k Properties("Attributes","displayName")
  s Properties("Comment")=$li(Properties("Attributes","department"))
  k Properties("Attributes","department")
  s Properties("EmailAddress")=$li(Properties("Attributes","mail"))
  k Properties("Attributes","mail")
  s GroupFilter="(&(objectClass=group)(member:1.2.840.113556.1.4.1941:="_DN_"))"
  s GroupAttributes=""
  s Status=##Class(%SYS.LDAP).SearchExts(LD,BaseDN,$$$LDAPSCOPESUBTREE,GroupFilter,GroupAttributes,0,"","",10,0,.GroupSearchResult)
  #;GroupSearch Status: "_Status
  i Status'=$$$LDAPSUCCESS {
    w !,"SearchExts error: "_Status_" - "_##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  s GroupNumEntries=##Class(%SYS.LDAP).CountEntries(LD,GroupSearchResult)
  i GroupNumEntries=-1 {
    s Status=##Class(%SYS.LDAP).GetError(LD)
    s Status=##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  w !
  i GroupNumEntries=0 {
    w !,"No nested groups for "_Username_" found"
    g Done
  }
  i GroupNumEntries>0 {
  }
  s GroupCurrentEntry=##Class(%SYS.LDAP).FirstEntry(LD,GroupSearchResult)
  i GroupCurrentEntry=0 {
    s Status=##Class(%SYS.LDAP).GetError(LD)
    w !,"FirstEntry error: "_Status_" - "_##Class(%SYS.LDAP).Err2String(Status)
    g Error
  }
  s Groups=""
  While (GroupCurrentEntry'=0) {
    s GroupDN=##Class(%SYS.LDAP).GetDN(LD,GroupCurrentEntry)
    i GroupDN="" {
      s Status=##Class(%SYS.LDAP).GetError(LD)
      w !,"GetDN Group error: "_Status_" - "_##Class(%SYS.LDAP).Err2String(Status)
      g Error
    }
    s CN=$p(GroupDN,",",1)
    s AD=$p(CN,"=",2)
    s AD=$zcvt(AD,"L") 
    s exists=''$d(^|"%SYS"|SYS("Security","RolesD",AD))
    i exists{
      s Properties("Roles") = AD
      #;w !,Properties("Roles")
    }
    s GroupCurrentEntry=##Class(%SYS.LDAP).NextEntry(LD,GroupCurrentEntry)
  }
Done
  i $d(SearchResult) d ##Class(%SYS.LDAP).MsgFree(SearchResult)
  i +$d(LD) d ##Class(%SYS.LDAP).UnBinds(LD)
  q $SYSTEM.Status.OK()
Error s $zt=""
  i $d(SearchResult) d ##Class(%SYS.LDAP).MsgFree(SearchResult)
  i +$d(LD) s Status=##class(%SYS.LDAP).UnBinds(LD)
  i $ze'=""{
    q $SYSTEM.Status.Error($$$CacheError,$ze)
  } else {  
    q $SYSTEM.Status.Error($$$GeneralError,"LDAP error: "_Status_" - "_##Class(%SYS.LDAP).Err2String(Status))
  }

Comments

Scott Roth · Apr 10, 2018

Just adding a bump to see if anyone has a way to have the system users bypass the delegated sign on without having to hard code the system.

THanks

Scott

0
Eduard Lebedyuk  Apr 11, 2018 to Scott Roth

System users are logging fine via user/pass, but before that they try delegated and fail there so Audit gets a new record?

0
Katherine Reid · Apr 11, 2018

There isn't currently a way to avoid running ZAUTHENTICATE before password logins.  Running the routine is deliberate behavior because it's used by some sites as part of their login process.  You could ask for a change, such as a configuration option to control the behaviour, to be added but that won't fix your issue right now.

Have you considered changing the existing password users to being delegated users?  This would remove the extra login failure event for them.  You would have to update your ZAUTHENTICATE code to handle the accounts, or create matching accounts on your AD server.

You can change user account types by editing the user objects.  Here's an example of how you can do it:

%SYS>s status=##class(Security.Users).Get("Admin",.prop)

%SYS>w prop("Flags")  ; This is the property which states this is a password user account                                   
1
%SYS>s prop("Flags")=4   ; This value says this is a delegated user                 

%SYS>s status=##class(Security.Users).Modify("Admin",.prop)
 

0