Welcome Serena Central users! CLICK HERE
The migration of the Serena Central community is currently underway. Be sure to read THIS MESSAGE to get your new login set up to access your account.
Steen Bjerge Absent Member.
Absent Member.
2066 views

Active Directory

Hi all 🙂

Does anyone have a COBOL example of a user validation in Active Directory they´d like to share?

Regards

Steen

0 Likes
11 Replies
davide_stfc Absent Member.
Absent Member.

RE: Active Directory

Hi.

We did something like that but using external (non COBOL) module.

I don't really know if it's possible to do it differently.
--
Davide
0 Likes
Steen Bjerge Absent Member.
Absent Member.

RE: Active Directory

Hi
Yes I'm aware that I might have do do some ActiveX / DLL calls but I what I ment was if there's anyone who already did some COBOL code for this and would like to share?
Steen
0 Likes
GeorgeK Absent Member.
Absent Member.

RE: Active Directory

You can use Call "C$SYSTEM" to call the microsoft user exe just like you would in C++, C#, VB.Net.
0 Likes
Micro Focus Expert
Micro Focus Expert

RE: Active Directory

What do you mean by "user validation"?

If you have a username and password, and you're running on Windows, you're probably better off just calling the standard Windows LogonUser function. It's simpler and almost always faster.

Here's the thing: There are essentially two ways to validate user credentials against an LDAP server such as AD. (I'm omitting proprietary, non-LDAP interfaces to AD, because they're basically equivalent for this purpose.) You can try to bind to the server using the credentials and see if that succeeds; or you can do a search against the server for the object representing the user, and then do something with the returned information.

Binding to AD as the user is equivalent to doing a domain signon in most cases, except:

  • Some users may not have permission to bind to AD
  • You don't get the benefits of local credential caching, such as:
    • Better performance (saves a network round trip and processing in AD)
    • Offline support

Looking up the user in AD generally isn't a good way to go, because:

  • Unless AD is configured to allow anonymous binds and then let the anonymous client search successfully for user records (which would be bad), you'll have to bind to AD first using some credentials.
    • If you use the credentials you're trying to validate, then you've just validated them, so why do anything more?
    • Otherwise, you have to get credentials from somewhere:
      • You can use the thread token (if you're running on Windows), but are you sure that account has appropriate permissions?
      • You can store a username and password somewhere. Now you have a security vulnerability.
  • Say you get the user information out of LDAP. How do you plan to validate the credentials you have against it?

So, if all you want to do is confirm the user's credentials, talking directly to AD probably isn't the way to go - if you're running on Windows.

If you're not running on Windows, you have a few choices:

  1. Use the bind-to-AD method described above.
  2. Use a remote mechanism for signing into a Windows domain, such as Samba. Or write your own (though I don't recommend this).
  3. Use Kerberos instead.

It'd help to know what problem you're actually trying to solve, in some detail.

0 Likes
Steen Bjerge Absent Member.
Absent Member.

RE: Active Directory

I see what you mean, and I simply just want to check if the user is a "known user" and the user account isn't disabled / expired. So the best solution properly is to call the Windows LogonUser function as you suggest. Do you have an example of thsi?

And yes I'm running Windows.
0 Likes
Micro Focus Expert
Micro Focus Expert

RE: Active Directory

I don't have an ACU version - I'm not running ACU COBOL / Extend (so many MF products, so little time). I do have an old sample for this, for some now-forgotten reason, that I wrote in MF COBOL. I think that should work in ACU with relatively little massaging.

 

      $set mf sourceformat"variable"
       identification division.
       program-id. logon.

       data division.
       working-storage section.
       77 userid           pic x(40).
       77 password         pic x(40).
       77 strpos           pic x(4) comp-5.
      $if USEPTR defined
       77 token            pointer.
      $else
      $if P64 set
       77 token            pic x(8) comp-5.
      $else
       77 token            pic x(4) comp-5.
      $end
      $end
       77 result           pic x(4) comp-5.
       77 loadlib          procedure-pointer.
       77 errcode          pic x(4) comp-5.
       77 errdisp          pic z(4)9 display.

       procedure division.
       *> Load Windows DLLs
       set loadlib to entry "advapi32"
       set loadlib to entry "kernel32"

       perform until exit
           *> Get username and password
           display "Userid: " with no advancing
           accept userid
           if userid = spaces
               exit perform
           end-if
           display "Password: " with no advancing
           accept password

           *> Nul-terminate strings
           move 0 to strpos
           inspect userid tallying strpos for characters before initial space
           add 1 to strpos
           move low-values to userid(strpos:1)

           move 0 to strpos
           inspect password tallying strpos for characters before initial space
           add 1 to strpos
           move low-values to password(strpos:1)

           *> Try the logon
      $if USEPTR defined
           set token to null
      $else
           move 0 to token
      $end
           call "LogonUserA" using
               by reference userid
               by reference z"."
               by reference password
               by value     3
               by value     0
               by reference token
               returning    result
           end-call
           call "GetLastError" returning errcode

      $if USEPTR defined
           if token = null
      $else
           if token = 0
      $end
               display "No token returned"
           else
               display "Token returned"
               *>call "CloseHandle" using by value token
               call "CloseHandle" using by reference token
           end-if
           if result = 0
               display "LogonUser returned false"
               move errcode to errdisp
               display "Error code was " errdisp
           else
               display "LogonUser returned true"
           end-if

       end-perform

       move 0 to return-code
       stop run.
0 Likes
Steen Bjerge Absent Member.
Absent Member.

RE: Active Directory

Hi Michael
Thanks a lot for your example 🙂
I do however get an error compiling the code:

call "LogonUserA" using
by reference userid
by reference z"."
by reference password
by value 3
by value 0
by reference token
returning result
end-call

There's an error in the

by reference z"."

line. Should it just be by reference "."

Or?

Regards
Steen
0 Likes
Chuck Edgin Absent Member.
Absent Member.

RE: Active Directory

The z"somevalue" notation is used by various flavors of Micro Focus COBOL to indicate a null-terminated string literal; unfortunately, ACUCOBOL doesn't support this notation. However, you can use hexadecimal notation: ... by reference x"2e00". (2e is the hex value of the "dot" character, and 00 is a null byte).
0 Likes
RobertRedekop Trusted Contributor.
Trusted Contributor.

RE: Active Directory

Chuck is correct, but while the x in front of the quotes can be lower case, I believe the "e" in 2e should be in caps. eg) x"2E00".
0 Likes
Steen Bjerge Absent Member.
Absent Member.

RE: Active Directory

Thanks all - but the call to LogonUserA returns a zero result. And the subsequently call to GetLastError returns an Errcode = 1326
Any ideas?
0 Likes
Micro Focus Expert
Micro Focus Expert

RE: Active Directory

Windows error codes are documented by Microsoft and readily available online.

See for example msdn.microsoft.com/.../ms681381(v=vs.85).aspx.

1326 is ERROR_LOGON_FAILURE.

Either the username or the password is incorrect, or the username needs to be domain-qualified, or you're calling LogonUser wrong. Note that all strings passed to LogonUser must be C strings (terminated with ASCII NUL). And this code calls LogonUserA, so they must be ASCII; that also means it can't be used with usernames or passwords that contain non-ASCII characters. For that you'd need to call LogonUserW and pass NUL-terminated UTF-16 strings.

If you're not familiar with calling Windows APIs I'd suggest doing some background reading.
0 Likes
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.