3

We are trying to authenticate our Application users using dbms_ldap against Microsoft AD and we have no means of testing it in our offshore environment

We have three specific questions

1)How to verify the user exists in Microsoft Active directory

We use the below code to get the Distinguished name of the Application user

DBMS_LDAP.USE_EXCEPTION := FALSE;
retval := DBMS_LDAP.search_s(ld       => ldapSession,
                           base     => LDAP_BASE,
                           scope    => DBMS_LDAP.SCOPE_SUBTREE,
                           filter   => '(&(objectclass=USER)(SAMAccountName=' ||
                                       p_username || '))',
                           attrs    => attrList,
                           attronly => 0,
                           res      => ldapMessage);
  -- get the DN
if retval <> DBMS_LDAP_UTL.SUCCESS THEN
RAISE l_ldap_exception;
END IF;
userDN := DBMS_LDAP.get_dn(ldapSession, ldapMessage);

So the first question is what will be the value of

 userDN and ldapMessage

if the user doesn't exist in Microsoft AD

2)Suppose the user exists and has entered the wrong password in that case what will be the return value of retval

if p_password is null then
raise_application_error(-20000, 'Invalid Null password');
else
retval := DBMS_LDAP.simple_bind_s(ldapSession,userDN, p_password);
end if;

if retval <> DBMS_LDAP_UTL.SUCCESS THEN
RAISE l_ldap_exception;
and if;

3)My third question is suppose the user has logged in the system and ldapsession is still not unbind what will be the way to identify duplicate session

psaraj12
  • 4,772
  • 2
  • 21
  • 30

3 Answers3

5

WARNING WARNING WARNING

This is less an answer and more a warning to anyone who uses the following code to validate a user.

  retval := DBMS_LDAP.simple_bind_s(ldapSession, userDN, p_password);

By design (LDAP Design) this function call will always return success if the password is null. This was done to allow anonymous LDAP queries. This might be disabled on your specific server but not always.

So, if you want to use this function then make sure you wrap it with an if block that ensures the user provided password is not null. e.g.

  if p_password is null then
    raise_application_error(-20000, 'Invalid Null password');
  else
    retval := DBMS_LDAP.simple_bind_s(ldapSession,userDN, p_password);
  end if;

For more details see: http://www.inside-oracle-apex.com/dbms_ldapsimple_bind_s-apex_ldapauthenticate-and-null-password/

AnthonyVO
  • 3,821
  • 1
  • 36
  • 41
3

First, read the docs. It has almost everything you need to answer your questions: http://docs.oracle.com/cd/E23943_01/oid.1111/e10186/dbmsldap_ref.htm

1) Either NULL or get_dn_exception will be raised, I'm not sure. Anyway, another method to check is to count the search results, where you only need to check if the count is >0:

DBMS_LDAP.count_entries(ld => ldapSession, msg => ldapMessage)

2) retval can only be DMBS_LDAP.SUCCESS, an exception is raised on any error

3) If you have session id, call any procedure that requires a valid LDAP session, e.g. simple_bind_s and check if invalid_session is raised. If you don't have a session id, I'm not aware of a method to determine if there are any LDAP sessions open.

Kombajn zbożowy
  • 8,755
  • 3
  • 28
  • 60
  • kombajn i was able to handle the first two issues based on your solution and the third one i am not sure how to implement.thanks for providing the answer – psaraj12 Sep 01 '14 at 07:12
2

In my application I do it like this:

ld := DBMS_LDAP.INIT(LDAP_SERVER, 389);
retval := DBMS_LDAP.SIMPLE_BIND_S(ld, LDAP_USER, LDAP_PASSWORD);
DBMS_LDAP.USE_EXCEPTION := FALSE;

retval := DBMS_LDAP.SEARCH_S(
    ld => ld, 
    base => LDAP_BASE,
    SCOPE => DBMS_LDAP.SCOPE_SUBTREE,
    FILTER => '&(objectCategory=user)(sAMAccountName='||username ||')', 
    attrs => attrs,
    attronly => 0,
    res => ldapMessage);
retval := DBMS_LDAP.COUNT_ENTRIES(ld, ldapMessage);
ldapEntry := DBMS_LDAP.FIRST_ENTRY(ld, ldapMessage);

IF ldapEntry IS NULL THEN
    retval := DBMS_LDAP.MSGFREE(ldapMessage);
    retval := DBMS_LDAP.UNBIND_S(ld);
    RAISE_APPLICATION_ERROR(-20001, 'User does not exist');
ELSE
    userDN := DBMS_LDAP.GET_DN(ld, ldapEntry);
END IF;
retval := DBMS_LDAP.MSGFREE(ldapMessage);


IF p_password IS NULL THEN
    retval := DBMS_LDAP.UNBIND_S(ld);
    RAISE_APPLICATION_ERROR(-20000, 'Invalid Null password');
ELSE
    retval := DBMS_LDAP.SIMPLE_BIND_S(ldapSession, userDN, p_password);
    IF retval <> DBMS_LDAP_UTL.SUCCESS THEN
        retval := DBMS_LDAP.UNBIND_S(ld);
        RAISE_APPLICATION_ERROR(-20001, 'Wrong password');
    END IF;
END IF;
retval := DBMS_LDAP.UNBIND_S(ld);

Regarding your questions:

1) How to verify the user exists in Microsoft Active directory

See my code

So the first question is what will be the value of userDN and ldapMessage

userDN will be NULL, ldapMessage I don't care.

2) Suppose the user exists and has entered the wrong password in that case what will be the return value of retval

  • For valid password: DBMS_LDAP.SUCCESS (0)
  • For wrong paasword: DBMS_LDAP.INVALID_CREDENTIALS (49)

Note, you get DBMS_LDAP.INVALID_CREDENTIALS only when you set DBMS_LDAP.USE_EXCEPTION := FALSE;, otherwise you get an exception if the password is wrong.

3) My third question is suppose the user has logged in the system and ldapsession is still not unbind what will be the way to identify duplicate session

Ensure proper calling of DBMS_LDAP.UNBIND_S(ld); in your code.

Another warning:

When you provide wrong password at DBMS_LDAP.SIMPLE_BIND_S(ldapSession, userDN, p_password); then the badPwdCount property in Active Directory is not incremented! Thus you can do infinite attempts to enter (or brute force) a password.

Wernfried Domscheit
  • 54,457
  • 9
  • 76
  • 110