PL/SQL 中的 Oracle DBMS_LDAP.open_ssl 显示错误:ORA-31202:SSL 握手失败

Posted

技术标签:

【中文标题】PL/SQL 中的 Oracle DBMS_LDAP.open_ssl 显示错误:ORA-31202:SSL 握手失败【英文标题】:Oracle DBMS_LDAP.open_ssl in PL/SQL shows error: ORA-31202: SSL handshake failed 【发布时间】:2017-01-15 19:14:51 【问题描述】:

我们已切换到新的 Microsoft ADFS 服务器,现在我们必须使用 LDAPS(端口 636 上的 LDAP over SSL)。但是在 PL/SQL 包中通过添加 DBMS_LDAP.open_ssl (基于 here )我得到:

ORA-31202: DBMS_LDAP: LDAP client/server error: SSL handshake failed

我的故障排除指导我对连接进行 tcpdump 调试,我发现 Oracle (12.1.0.2) DBMS_LDAP 在 SSL 握手上仅使用以下三个密码套件,这些密码套件都非常旧且不安全,并且不受最新的 Microsoft AD 支持。即使我用 ldap.google.com:636 尝试了另一个 12c db (12.1.0.2.0) 并收到相同的错误和相同的密码套件。

Version: TLS 1.2 (0x0303)
Cipher Suite: TLS_DH_anon_WITH_3DES_EDE_CBC_SHA (0x001b)
Cipher Suite: TLS_DH_anon_WITH_RC4_128_MD5 (0x0018)
Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)

Oracle 知识表明,很多人都曾遇到过这个问题(文档 ID 19285025.8,文档 ID 1561121.1),唯一的建议是补丁“19285025”。我们已经完成了这个补丁,但仍然没有进展。我们找到了 Oracle 文档 (here) 来展示如何通过“netmagr”配置安全套接字层和添加密码套件,但最后我知道这仅适用于 oracle DB 连接,但没有影响。 现在的问题是? 1. DBMS_LDAP.open_ssl 这个“SSL 握手失败”如何解决?我们如何为 DBMS_LDAP.open_ssl 设置不同的密码套件? 2. 使用 LDAPS 的任何替代 PL/SQL 包?或者我们必须使用 Java 包并将其加载到 DB 中?

【问题讨论】:

恕我直言,我认为这是一个编程问题,因为整个故事都是关于在PL/SQL 编程中使用LDAPS。我还询问了我使用 Java 过程找到的替代解决方案,并将很快作为我的答案。 【参考方案1】:

我已切换到 java 程序而不是 Oracle DBMS_LDAP。它运行良好,不再存在 SSL 问题(除了 java 的扩展功能之外)。

    SET SERVEROUTPUT ON SIZE 5000;
CALL dbms_java.set_output(5000);

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED LDAP AS
import javax.naming.*;
import javax.naming.directory.*;
import java.util.Hashtable;
/**
 * Java LDAP Package by ATK, 9/9/2016
 */
class ldap 
    public static int ldap_auth(String username, String my_password, String ldap_server) 

    Hashtable env = new Hashtable(11);
    env.put(Context.INITIAL_CONTEXT_FACTORY, 
        "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldap_server ); //example "ldap://ldap.yourcompany.com:636"

    env.put(Context.SECURITY_PROTOCOL, "ssl");

    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    env.put(Context.SECURITY_PRINCIPAL, "uid=" + username + ",OU=users,DC=company,DC=com");
    env.put(Context.SECURITY_CREDENTIALS, my_password);

    try 
        // Create initial context
        DirContext ctx = new InitialDirContext(env);

        System.out.println("Connection Successful.");

        ctx.close();
      return 0;
     catch (NamingException e) 
        System.out.println("LDAP Connection: FAILED"); 
        e.printStackTrace();
      return -1;
    
    
;

--show errors java source ldap ; -- to check class compile

CREATE OR REPLACE FUNCTION ldap_auth (username in varchar2, my_password in varchar2, ldap_server in varchar2) RETURN NUMBER
AS LANGUAGE JAVA 
NAME 'ldap.ldap_auth (java.lang.String, java.lang.String, java.lang.String) return int';


call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', 'ldap.companyDomain.com', 'resolve' );
call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', 'ldapqa.companyDomain.com', 'resolve' );
call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', 'ldapdev.companyDomain.com', 'resolve' );
call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', '10.14.10.53:636', 'connect,resolve' );
call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', '10.14.10.54:636', 'connect,resolve' );
call dbms_java.grant_permission( 'MySchema', 'SYS:java.net.SocketPermission', '10.14.10.55:636', 'connect,resolve' );

现在您可以使用以下方法对其进行测试:

SET SERVEROUTPUT ON SIZE 5000
CALL dbms_java.set_output(0);
declare 
  l_ret int ;
begin
  l_ret := ldap_auth ('myUser', 'myPassword', 'ldap://lds.companyDomain.com:636');
  DBMS_OUTPUT.put_line('Return = ' || l_ret );
end;

【讨论】:

【参考方案2】:

我很欣赏这是一篇旧帖子,但作为参考,事实证明 DBMS_LDAP 所宣传的密码套件依赖于 open_ssl 函数的 sslauth 参数。

sslauth 设置为1(无身份验证)时,将只通告TLS_DH_anon_xxx 密码套件。 当使用 23(1 或 2 路身份验证)时,所有密码套件都将被宣传(OCI 中的 vanilla 19c ATP 数据库中的 25 个套件)

【讨论】:

以上是关于PL/SQL 中的 Oracle DBMS_LDAP.open_ssl 显示错误:ORA-31202:SSL 握手失败的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQL:ORACLE 中的感叹号

Oracle:使用 SQL 或 PL/SQL 查找动态 SQL 中的错误位置

Oracle Apex:PL/SQL 块中的 Javascript 代码

Oracle 12c - PL/SQL 中的问题

用于 oracle 11g 的 PL/SQL 中的嵌入式脚本 [重复]

从 PL/SQL 调用另一个 Oracle 数据库中的过程