Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 神谕使用LDAP进行身份验证始终返回-16_Java_Oracle_Plsql_Active Directory_Ldap - Fatal编程技术网

Java 神谕使用LDAP进行身份验证始终返回-16

Java 神谕使用LDAP进行身份验证始终返回-16,java,oracle,plsql,active-directory,ldap,Java,Oracle,Plsql,Active Directory,Ldap,我们正在使用Oracle数据库中的LDAP进行用户身份验证。然而,身份验证结果总是-16,在我看到的一些示例中,它被转换为无效凭据。我已经用DBMS_LDAP.search_搜索了Active directory,并确保输入的DN是正确的。有趣的是,DBMS_LDAP.SIMPLE_BIND_无法绑定密码不正确的DBMS_LDAP.SIMPLE_BIND_绑定密码正确的DBMS_。但是,当使用DBMS\u LDAP\u UTL.AUTHENTICATE\u USER执行相同操作时,如果密码不正确

我们正在使用Oracle数据库中的LDAP进行用户身份验证。然而,身份验证结果总是-16,在我看到的一些示例中,它被转换为无效凭据。我已经用DBMS_LDAP.search_搜索了Active directory,并确保输入的DN是正确的。有趣的是,DBMS_LDAP.SIMPLE_BIND_无法绑定密码不正确的DBMS_LDAP.SIMPLE_BIND_绑定密码正确的DBMS_。但是,当使用DBMS\u LDAP\u UTL.AUTHENTICATE\u USER执行相同操作时,如果密码不正确,DN不正确,则它总是返回-16。以下是身份验证示例:

DECLARE
 ldap_host      VARCHAR2(256);
 ldap_port      PLS_INTEGER;
 ldap_user      VARCHAR2(256);
 ldap_passwd    VARCHAR2(256);
 ldap_base      VARCHAR2(256);

 retval              PLS_INTEGER;
 my_session          DBMS_LDAP.session;

 subscriber_handle   DBMS_LDAP_UTL.HANDLE;
 sub_type            PLS_INTEGER;
 subscriber_id       VARCHAR2(2000);

 my_pset_coll        DBMS_LDAP_UTL.PROPERTY_SET_COLLECTION;
 my_property_names   DBMS_LDAP.STRING_COLLECTION;
 my_property_values  DBMS_LDAP.STRING_COLLECTION;

 user_handle         DBMS_LDAP_UTL.HANDLE;
 user_id             VARCHAR2(2000);
 user_type           PLS_INTEGER;
 user_password       VARCHAR2(2000);

 my_mod_pset         DBMS_LDAP_UTL.MOD_PROPERTY_SET;


 my_attrs            DBMS_LDAP.STRING_COLLECTION;

 locate raw(4000);

BEGIN


 -- Please customize the following variables as needed

 ldap_host  := 'host' ;
 ldap_port     :=   389;
 ldap_user  := 'CN=UserName1,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
 ldap_passwd   :=   'SamePassword';

 sub_type      :=   DBMS_LDAP_UTL.TYPE_DN;
 subscriber_id :=   'OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
 user_type     :=   DBMS_LDAP_UTL.TYPE_DN;
 user_id       :=   'CN=UserName2,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';;
 user_password :=   'SamePassword';
 -- Choosing exceptions to be raised by DBMS_LDAP library.
 DBMS_LDAP.USE_EXCEPTION := TRUE;

 -----------------------------------------------
 -- Connect to the LDAP server 
 -- and obtain and ld session.
 -----------------------------------------------

 my_session := DBMS_LDAP.init(ldap_host,ldap_port);

 -----------------------------------------------
 -- Bind to the directory
 -- 
 -----------------------------------------------

 retval := DBMS_LDAP.simple_bind_s(my_session,
                                ldap_user, 
                                ldap_passwd);

 ---------------------------------------------------------------------
 -- Create Subscriber Handle
 -- 
 ---------------------------------------------------------------------

 retval := DBMS_LDAP_UTL.create_subscriber_handle(subscriber_handle,
                                            sub_type,
                                            subscriber_id);

 IF retval != DBMS_LDAP_UTL.SUCCESS  THEN
    -- Handle Errors
    DBMS_OUTPUT.PUT_LINE('create_subscriber_handle returns : ' || to_char(retval));
 END IF;

 ---------------------------------------------------------------------
 -- Create User Handle
 -- 
 ---------------------------------------------------------------------

 retval := DBMS_LDAP_UTL.create_user_handle(user_handle,user_type,user_id);

 IF retval != DBMS_LDAP_UTL.SUCCESS  THEN
    -- Handle Errors
    DBMS_OUTPUT.PUT_LINE('create_user_handle returns : ' || to_char(retval));
 END IF;

  ---------------------------------------------------------------------

 dbms_output.put_line(dbms_ldap_utl.locate_subscriber_for_user(
   ld                => my_session,
   user_handle       => user_handle,
   subscriber_handle => locate));

   dbms_output.put_line(DBMS_LDAP_UTL.SUCCESS);


 ---------------------------------------------------------------------
 -- Set user handle properties
 -- (link subscriber to user )
 ---------------------------------------------------------------------

 retval := DBMS_LDAP_UTL.set_user_handle_properties(user_handle,
                                          DBMS_LDAP_UTL.SUBSCRIBER_HANDLE,
                                          subscriber_handle);

 IF retval != DBMS_LDAP_UTL.SUCCESS  THEN
    -- Handle Errors
    DBMS_OUTPUT.PUT_LINE('set_user_handle_properties returns : ' || to_char(retval));
 END IF;

 ---------------------------------------------------------------------
 -- Authenticate User
 ---------------------------------------------------------------------

 retval := DBMS_LDAP_UTL.authenticate_user(my_session,
                                           user_handle,
                                           DBMS_LDAP_UTL.AUTH_SIMPLE,
                                           user_password,
                                           NULL);

 IF retval != DBMS_LDAP_UTL.SUCCESS  THEN
    -- Handle Errors
    DBMS_OUTPUT.PUT_LINE('authenticate_user returns : ' || to_char(retval));
 END IF;

 ---------------------------------------------------------------------
 -- Free handles
 ---------------------------------------------------------------------

 DBMS_LDAP_UTL.free_handle(subscriber_handle);
 DBMS_LDAP_UTL.free_handle(user_handle);


  -- unbind from the directory  
 retval := DBMS_LDAP.unbind_s(my_session);

 IF retval != DBMS_LDAP_UTL.SUCCESS  THEN
    -- Handle Errors
    DBMS_OUTPUT.PUT_LINE('unbind_s returns : ' || to_char(retval));
 END IF;


-- Handle Exceptions
 EXCEPTION
  WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE(' Error code    : ' || TO_CHAR(SQLCODE));
   DBMS_OUTPUT.PUT_LINE(' Error Message : ' || SQLERRM);
   DBMS_OUTPUT.PUT_LINE(' Exception encountered .. exiting');

  END;
/

如果您只是想根据LDAP对用户进行身份验证,那么这相当简单:

DECLARE

    ret NUMBER;     
    ld DBMS_LDAP.SESSION;
    SUCCESS INTEGER;

    ldap_host VARCHAR2(100) := 'host';
    ldap_port INTEGER := 389;

    userDn VARCHAR2(100) := 'OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
    userPassword VARCHAR2(100) := 'secret';
    
BEGIN
    DBMS_LDAP.USE_EXCEPTION := TRUE;
    ld := DBMS_LDAP.INIT(ldap_host, ldap_port);
    DBMS_LDAP.USE_EXCEPTION := FALSE;

    SUCCESS := DBMS_LDAP.SIMPLE_BIND_S(ld, userDn, userPassword);
    IF SUCCESS = DBMS_LDAP.SUCCESS AND userPassword IS NOT NULL THEN
        DBMS_OUTPUT.PUT_LINE('Password is valid');
    ELSE
        DBMS_OUTPUT.PUT_LINE('Wrong password');
    END IF;

    ret := DBMS_LDAP.UNBIND_S(ld);

END;
如果要查询给定用户的属性,可以查看以下示例:

DECLARE

    SUBTYPE T_USER_ACCOUNT_CONTROL IS INTEGER;
    -- see https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
    SKRIPT                                  CONSTANT T_USER_ACCOUNT_CONTROL := 1;
    ACCOUNTDISABLE                          CONSTANT T_USER_ACCOUNT_CONTROL := 2;
    HOMEDIR_REQUIRED                        CONSTANT T_USER_ACCOUNT_CONTROL := 8;
    LOCKOUT                                     CONSTANT T_USER_ACCOUNT_CONTROL := 16;
    PASSWD_NOTREQD                          CONSTANT T_USER_ACCOUNT_CONTROL := 32;
    PASSWD_CANT_CHANGE                  CONSTANT T_USER_ACCOUNT_CONTROL := 64;
    ENCRYPTED_TEXT_PWD_ALLOWED          CONSTANT T_USER_ACCOUNT_CONTROL := 128;
    TEMP_DUPLICATE_ACCOUNT              CONSTANT T_USER_ACCOUNT_CONTROL := 256;
    NORMAL_ACCOUNT                          CONSTANT T_USER_ACCOUNT_CONTROL := 512;
    INTERDOMAIN_TRUST_ACCOUNT           CONSTANT T_USER_ACCOUNT_CONTROL := 2048;
    WORKSTATION_TRUST_ACCOUNT           CONSTANT T_USER_ACCOUNT_CONTROL := 4096;
    SERVER_TRUST_ACCOUNT                    CONSTANT T_USER_ACCOUNT_CONTROL := 8192;
    DONT_EXPIRE_PASSWORD                    CONSTANT T_USER_ACCOUNT_CONTROL := 65536;
    MNS_LOGON_ACCOUNT                   CONSTANT T_USER_ACCOUNT_CONTROL := 131072;
    SMARTCARD_REQUIRED                  CONSTANT T_USER_ACCOUNT_CONTROL := 262144;
    TRUSTED_FOR_DELEGATION              CONSTANT T_USER_ACCOUNT_CONTROL := 524288;
    NOT_DELEGATED                           CONSTANT T_USER_ACCOUNT_CONTROL := 1048576;
    USE_DES_KEY_ONLY                        CONSTANT T_USER_ACCOUNT_CONTROL := 2097152;
    DONT_REQ_PREAUTH                        CONSTANT T_USER_ACCOUNT_CONTROL := 4194304;
    PASSWORD_EXPIRED                        CONSTANT T_USER_ACCOUNT_CONTROL := 8388608;
    TRUSTED_TO_AUTH_FOR_DELEGATION  CONSTANT T_USER_ACCOUNT_CONTROL := 16777216;
    PARTIAL_SECRETS_ACCOUNT             CONSTANT T_USER_ACCOUNT_CONTROL := 67108864;
    
    LDAP_USER CONSTANT VARCHAR2(255) := 'CN=UserName1,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
    LDAP_PASSWORD CONSTANT VARCHAR2(30) := 'secret';
    LDAP_SERVER CONSTANT VARCHAR2(30) := 'host';
    LDAP_PORT INTEGER := 389;

    userDn VARCHAR2(100) := 'CN=UserName2,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';


    ld DBMS_LDAP.SESSION;
    ret NUMBER; 
    ldapEntry DBMS_LDAP.MESSAGE;    
    attrs DBMS_LDAP.STRING_COLLECTION;  
    ldapMessage DBMS_LDAP.MESSAGE;
    attribName VARCHAR2(256);
    berEelement DBMS_LDAP.BER_ELEMENT;
    info DBMS_LDAP.STRING_COLLECTION;
    
    pwdLastSet TIMESTAMP;
    expireDate TIMESTAMP
    
BEGIN
    
    attrs(1) := 'displayName';
    attrs(2) := 'userAccountControl';
    attrs(3) := 'pwdLastSet';

    ld := DBMS_LDAP.INIT(LDAP_SERVER, LDAP_PORT);
    ret := DBMS_LDAP.SIMPLE_BIND_S(ld, LDAP_USER, LDAP_PASSWORD);
    DBMS_LDAP.USE_EXCEPTION := FALSE;
    
    ret := DBMS_LDAP.SEARCH_S(
        ld => ld, 
        base => 'DC=pan,DC=int',
        SCOPE => DBMS_LDAP.SCOPE_SUBTREE,
        FILTER => '&(objectCategory=user)(distinguishedName='||userDn||')', 
        attrs => attrs,
        attronly => 0,
        res => ldapMessage);
    ldapEntry := DBMS_LDAP.FIRST_ENTRY(ld, ldapMessage);
    IF ldapEntry IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('User "'||userDn||'" does not exist');
    ELSE
        WHILE ldapEntry IS NOT NULL LOOP        
            attribName := DBMS_LDAP.FIRST_ATTRIBUTE(ld, ldapEntry, berEelement);
            WHILE attribName IS NOT NULL LOOP     
                info := DBMS_LDAP.GET_VALUES(ld, ldapEntry, attribName);
                CASE attribName
                WHEN 'displayName' THEN 
                    DBMS_OUTPUT.PUT_LINE('Display Name = ' || info(info.FIRST));
                WHEN 'userAccountControl' THEN
                    IF SIGN(BITAND(ACCOUNTDISABLE, info(info.FIRST))) = 1 THEN
                        DBMS_OUTPUT.PUT_LINE('Account is disabled');
                    END IF;
                    
                    IF SIGN(BITAND(PASSWORD_EXPIRED, info(info.FIRST))) = 1 THEN
                        DBMS_OUTPUT.PUT_LINE('Password is expired');
                    END IF;                 
                WHEN 'pwdLastSet' THEN
                    pwdLastSet := (TIMESTAMP '1601-01-01 00:00:00 UTC' + info(info.FIRST)/1000/1000/10/60/60/24 * INTERVAL '1' DAY) AT LOCAL;
                    DBMS_OUTPUT.PUT_LINE('Password was changed at ' || TO_CHAR(pwdLastSet, 'yyyy-mm-dd hh24:mi:ss'));

                    -- Password life time is not available in LDAP. Check your company policy and calculate expire date accordingly, for example:
                    expireDate := pwdLastSet + INTERVAL '6' MONTH;
                    DBMS_OUTPUT.PUT_LINE('Your password will expire at ' || TO_CHAR(expireDate, 'yyyy-mm-dd hh24:mi:ss'));                  
                END CASE;       
                attribName := DBMS_LDAP.NEXT_ATTRIBUTE(ld, ldapEntry, berEelement);
            END LOOP;
            ldapEntry := DBMS_LDAP.NEXT_ENTRY(ld, ldapEntry);
        END LOOP;
        DBMS_LDAP.BER_FREE(berEelement, freebuf => 0);  
    END IF;
    ret := DBMS_LDAP.MSGFREE(ldapMessage);
    ret := DBMS_LDAP.UNBIND_S(ld);

end;
更新

我犯了一个错误,我说“LDAP中没有密码生存时间”。您可以这样查询:

BEGIN

   dn := 'DC=pan,DC=int';
   attrs(1) := 'maxPwdAge';

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

    ret := DBMS_LDAP.SEARCH_S(
        ld => ld, 
        base => 'DC=pan,DC=int',
        SCOPE => DBMS_LDAP.SCOPE_SUBTREE,
        FILTER => '&(objectCategory=domain)(distinguishedName='||dn||')', 
        attrs => attrs,
        attronly => 0,
        res => ldapMessage);
    -- You do not need a loop because you have only one single entry and one single attribute. Otherwise a loop would be required, see above.
    ldapEntry := DBMS_LDAP.FIRST_ENTRY(ld, ldapMessage);
    attribName := DBMS_LDAP.FIRST_ATTRIBUTE(ld, ldapEntry, berEelement);
    info := DBMS_LDAP.GET_VALUES(ld, ldapEntry, attribName);    

    DBMS_OUTPUT.PUT_LINE('Password life time = ' || -info(info.FIRST)/1000/1000/10/60/60/24 || ' days');

    DBMS_LDAP.BER_FREE(berEelement, freebuf => 0);  
    ret := DBMS_LDAP.MSGFREE(ldapMessage);
    ret := DBMS_LDAP.UNBIND_S(ld);

END;

如果您只是想根据LDAP对用户进行身份验证,那么这相当简单:

DECLARE

    ret NUMBER;     
    ld DBMS_LDAP.SESSION;
    SUCCESS INTEGER;

    ldap_host VARCHAR2(100) := 'host';
    ldap_port INTEGER := 389;

    userDn VARCHAR2(100) := 'OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
    userPassword VARCHAR2(100) := 'secret';
    
BEGIN
    DBMS_LDAP.USE_EXCEPTION := TRUE;
    ld := DBMS_LDAP.INIT(ldap_host, ldap_port);
    DBMS_LDAP.USE_EXCEPTION := FALSE;

    SUCCESS := DBMS_LDAP.SIMPLE_BIND_S(ld, userDn, userPassword);
    IF SUCCESS = DBMS_LDAP.SUCCESS AND userPassword IS NOT NULL THEN
        DBMS_OUTPUT.PUT_LINE('Password is valid');
    ELSE
        DBMS_OUTPUT.PUT_LINE('Wrong password');
    END IF;

    ret := DBMS_LDAP.UNBIND_S(ld);

END;
如果要查询给定用户的属性,可以查看以下示例:

DECLARE

    SUBTYPE T_USER_ACCOUNT_CONTROL IS INTEGER;
    -- see https://support.microsoft.com/en-us/help/305144/how-to-use-the-useraccountcontrol-flags-to-manipulate-user-account-pro
    SKRIPT                                  CONSTANT T_USER_ACCOUNT_CONTROL := 1;
    ACCOUNTDISABLE                          CONSTANT T_USER_ACCOUNT_CONTROL := 2;
    HOMEDIR_REQUIRED                        CONSTANT T_USER_ACCOUNT_CONTROL := 8;
    LOCKOUT                                     CONSTANT T_USER_ACCOUNT_CONTROL := 16;
    PASSWD_NOTREQD                          CONSTANT T_USER_ACCOUNT_CONTROL := 32;
    PASSWD_CANT_CHANGE                  CONSTANT T_USER_ACCOUNT_CONTROL := 64;
    ENCRYPTED_TEXT_PWD_ALLOWED          CONSTANT T_USER_ACCOUNT_CONTROL := 128;
    TEMP_DUPLICATE_ACCOUNT              CONSTANT T_USER_ACCOUNT_CONTROL := 256;
    NORMAL_ACCOUNT                          CONSTANT T_USER_ACCOUNT_CONTROL := 512;
    INTERDOMAIN_TRUST_ACCOUNT           CONSTANT T_USER_ACCOUNT_CONTROL := 2048;
    WORKSTATION_TRUST_ACCOUNT           CONSTANT T_USER_ACCOUNT_CONTROL := 4096;
    SERVER_TRUST_ACCOUNT                    CONSTANT T_USER_ACCOUNT_CONTROL := 8192;
    DONT_EXPIRE_PASSWORD                    CONSTANT T_USER_ACCOUNT_CONTROL := 65536;
    MNS_LOGON_ACCOUNT                   CONSTANT T_USER_ACCOUNT_CONTROL := 131072;
    SMARTCARD_REQUIRED                  CONSTANT T_USER_ACCOUNT_CONTROL := 262144;
    TRUSTED_FOR_DELEGATION              CONSTANT T_USER_ACCOUNT_CONTROL := 524288;
    NOT_DELEGATED                           CONSTANT T_USER_ACCOUNT_CONTROL := 1048576;
    USE_DES_KEY_ONLY                        CONSTANT T_USER_ACCOUNT_CONTROL := 2097152;
    DONT_REQ_PREAUTH                        CONSTANT T_USER_ACCOUNT_CONTROL := 4194304;
    PASSWORD_EXPIRED                        CONSTANT T_USER_ACCOUNT_CONTROL := 8388608;
    TRUSTED_TO_AUTH_FOR_DELEGATION  CONSTANT T_USER_ACCOUNT_CONTROL := 16777216;
    PARTIAL_SECRETS_ACCOUNT             CONSTANT T_USER_ACCOUNT_CONTROL := 67108864;
    
    LDAP_USER CONSTANT VARCHAR2(255) := 'CN=UserName1,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';
    LDAP_PASSWORD CONSTANT VARCHAR2(30) := 'secret';
    LDAP_SERVER CONSTANT VARCHAR2(30) := 'host';
    LDAP_PORT INTEGER := 389;

    userDn VARCHAR2(100) := 'CN=UserName2,OU=SERVICE_ACCOUNTS,OU=Users,OU=LT,OU=PB,DC=pan,DC=int';


    ld DBMS_LDAP.SESSION;
    ret NUMBER; 
    ldapEntry DBMS_LDAP.MESSAGE;    
    attrs DBMS_LDAP.STRING_COLLECTION;  
    ldapMessage DBMS_LDAP.MESSAGE;
    attribName VARCHAR2(256);
    berEelement DBMS_LDAP.BER_ELEMENT;
    info DBMS_LDAP.STRING_COLLECTION;
    
    pwdLastSet TIMESTAMP;
    expireDate TIMESTAMP
    
BEGIN
    
    attrs(1) := 'displayName';
    attrs(2) := 'userAccountControl';
    attrs(3) := 'pwdLastSet';

    ld := DBMS_LDAP.INIT(LDAP_SERVER, LDAP_PORT);
    ret := DBMS_LDAP.SIMPLE_BIND_S(ld, LDAP_USER, LDAP_PASSWORD);
    DBMS_LDAP.USE_EXCEPTION := FALSE;
    
    ret := DBMS_LDAP.SEARCH_S(
        ld => ld, 
        base => 'DC=pan,DC=int',
        SCOPE => DBMS_LDAP.SCOPE_SUBTREE,
        FILTER => '&(objectCategory=user)(distinguishedName='||userDn||')', 
        attrs => attrs,
        attronly => 0,
        res => ldapMessage);
    ldapEntry := DBMS_LDAP.FIRST_ENTRY(ld, ldapMessage);
    IF ldapEntry IS NULL THEN
        DBMS_OUTPUT.PUT_LINE('User "'||userDn||'" does not exist');
    ELSE
        WHILE ldapEntry IS NOT NULL LOOP        
            attribName := DBMS_LDAP.FIRST_ATTRIBUTE(ld, ldapEntry, berEelement);
            WHILE attribName IS NOT NULL LOOP     
                info := DBMS_LDAP.GET_VALUES(ld, ldapEntry, attribName);
                CASE attribName
                WHEN 'displayName' THEN 
                    DBMS_OUTPUT.PUT_LINE('Display Name = ' || info(info.FIRST));
                WHEN 'userAccountControl' THEN
                    IF SIGN(BITAND(ACCOUNTDISABLE, info(info.FIRST))) = 1 THEN
                        DBMS_OUTPUT.PUT_LINE('Account is disabled');
                    END IF;
                    
                    IF SIGN(BITAND(PASSWORD_EXPIRED, info(info.FIRST))) = 1 THEN
                        DBMS_OUTPUT.PUT_LINE('Password is expired');
                    END IF;                 
                WHEN 'pwdLastSet' THEN
                    pwdLastSet := (TIMESTAMP '1601-01-01 00:00:00 UTC' + info(info.FIRST)/1000/1000/10/60/60/24 * INTERVAL '1' DAY) AT LOCAL;
                    DBMS_OUTPUT.PUT_LINE('Password was changed at ' || TO_CHAR(pwdLastSet, 'yyyy-mm-dd hh24:mi:ss'));

                    -- Password life time is not available in LDAP. Check your company policy and calculate expire date accordingly, for example:
                    expireDate := pwdLastSet + INTERVAL '6' MONTH;
                    DBMS_OUTPUT.PUT_LINE('Your password will expire at ' || TO_CHAR(expireDate, 'yyyy-mm-dd hh24:mi:ss'));                  
                END CASE;       
                attribName := DBMS_LDAP.NEXT_ATTRIBUTE(ld, ldapEntry, berEelement);
            END LOOP;
            ldapEntry := DBMS_LDAP.NEXT_ENTRY(ld, ldapEntry);
        END LOOP;
        DBMS_LDAP.BER_FREE(berEelement, freebuf => 0);  
    END IF;
    ret := DBMS_LDAP.MSGFREE(ldapMessage);
    ret := DBMS_LDAP.UNBIND_S(ld);

end;
更新

我犯了一个错误,我说“LDAP中没有密码生存时间”。您可以这样查询:

BEGIN

   dn := 'DC=pan,DC=int';
   attrs(1) := 'maxPwdAge';

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

    ret := DBMS_LDAP.SEARCH_S(
        ld => ld, 
        base => 'DC=pan,DC=int',
        SCOPE => DBMS_LDAP.SCOPE_SUBTREE,
        FILTER => '&(objectCategory=domain)(distinguishedName='||dn||')', 
        attrs => attrs,
        attronly => 0,
        res => ldapMessage);
    -- You do not need a loop because you have only one single entry and one single attribute. Otherwise a loop would be required, see above.
    ldapEntry := DBMS_LDAP.FIRST_ENTRY(ld, ldapMessage);
    attribName := DBMS_LDAP.FIRST_ATTRIBUTE(ld, ldapEntry, berEelement);
    info := DBMS_LDAP.GET_VALUES(ld, ldapEntry, attribName);    

    DBMS_OUTPUT.PUT_LINE('Password life time = ' || -info(info.FIRST)/1000/1000/10/60/60/24 || ' days');

    DBMS_LDAP.BER_FREE(berEelement, freebuf => 0);  
    ret := DBMS_LDAP.MSGFREE(ldapMessage);
    ret := DBMS_LDAP.UNBIND_S(ld);

END;

创建订户句柄的目的是什么?您只是想根据LDAP对用户进行身份验证吗?我真的不能说,我从某个地方复制了它,只是稍微修改了一下。我们将使用它对用户的LDAP进行身份验证,并返回不同的代码(如果有),以让用户知道密码是否需要更改、过期、不正确等等,-16 is
DBMS\u LDAP\u UTL.AUTH\u FAILURE\u EXCEPTION
。请参阅函数返回代码:-16身份验证失败。这并不能说明什么正如我所说,我进入了良好的PSW和良好的DN,但仍然得到这个。什么导致身份验证失败?嗯。其他人也有同样的问题。创建订户句柄的目的是什么?您只是想根据LDAP对用户进行身份验证吗?我真的不能说,我从某个地方复制了它,只是稍微修改了一下。我们将使用它对用户的LDAP进行身份验证,并返回不同的代码(如果有),以让用户知道密码是否需要更改、过期、不正确等等,-16 is
DBMS\u LDAP\u UTL.AUTH\u FAILURE\u EXCEPTION
。请参阅函数返回代码:-16身份验证失败。这并不能说明什么正如我所说,我进入了良好的PSW和良好的DN,但仍然得到这个。什么导致身份验证失败?嗯。其他人也有同样的问题。谢谢,这很有帮助。但是,为什么dbms\u ldap\u utl.authenticate\u用户不能工作呢?在我看来,只使用它会更容易、更干净,除非它是为其他目的而设计的?检查DBMS_LDAP_UTL body并查看在身份验证中到底有什么失败会很有趣。也许广告中的一些属性配置不好。谢谢,这很有帮助。但是,为什么dbms\u ldap\u utl.authenticate\u用户不能工作呢?在我看来,只使用它会更容易、更干净,除非它是为其他目的而设计的?检查DBMS_LDAP_UTL body并查看在身份验证中到底有什么失败会很有趣。可能AD中的某些属性配置不正确。