【问题标题】:Oracle PL/SQL LDAP - Unable to open walletOracle PL/SQL LDAP - 无法打开钱包
【发布时间】:2021-03-31 21:48:53
【问题描述】:

我正在尝试使用 PL/SQL 对在 Windows 服务器上的 Oracle 11g 上运行的应用程序在内部针对 SSL 安全 LDAP 服务器进行身份验证。我已将证书加载到钱包中并存储在 d:\wallets\ 中,并且可以验证它是否有效/加载到 oracle 钱包管理器中(ewallet.p12 使用我正确配置的密码打开)。但是,无论我做什么,我都无法使用 PL/SQL 函数让它工作。代码如下:

create or replace FUNCTION ldap_auth(
    p_username IN VARCHAR2,
    p_password IN VARCHAR2
)
RETURN varchar2 IS
    l_ldap_host         VARCHAR2(256) := 'ldapserver.internal.net';
    l_ldap_port         number := 636;
    l_dn                        VARCHAR2(512);

    l_retval                PLS_INTEGER;
    l_session               DBMS_LDAP.session;

    l_wallet_loc        varchar2(256) := 'file:D:\wallets';
    l_wallet_pwd        varchar2(256) := 'pa55w0rd';
    l_wallet_ssl        number := 3;

BEGIN
    DBMS_LDAP.USE_EXCEPTION := TRUE;
    l_dn := 'cn='||p_username||',ou=People,dc=internal,dc=net';

    BEGIN
        l_session := DBMS_LDAP.init(l_ldap_host, l_ldap_port);
    EXCEPTION
        when others then
        raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
        RETURN 'exception1';
    END;

    BEGIN
        l_retval := DBMS_LDAP.open_ssl (l_session, l_wallet_loc, l_wallet_pwd, l_wallet_ssl);
    EXCEPTION
        when others then
        raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
        RETURN 'exception2';
    END;

    BEGIN
        l_retval := DBMS_LDAP.simple_bind_s(l_session, l_dn, p_password);
  EXCEPTION
    when others then
    raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
    RETURN 'exception3';
  END;

    return 'pass';
END;

当我运行它时会发生以下情况:

select ldap_auth('userID','userPassword') as results1 from dual

ORA-20001:遇到错误 - -31202 -ERROR- ORA-31202:DBMS_LDAP:LDAP 客户端/服务器错误:无法打开钱包 ORA-06512:在“DBUSERNAME.LDAP_AUTH”,第 33 行

我被困在这一点上,我在网上找不到任何关于如何完成这项工作的参考资料。

【问题讨论】:

    标签: windows oracle plsql oracle11g ldap


    【解决方案1】:

    您可以尝试在l_wallet_ssl 的声明中使用pls_integer 而不是number。此外,请考虑删除when others exception,看看是否可以从open_ssl 函数调用中获得更有用的错误(参见表4-86,了解this link 的错误范围)。

    【讨论】:

      【解决方案2】:

      IDK 如果您设法解决了这个问题,但这里是我基于深入分析和大量谷歌搜索相同问题的答案。我正在尝试为与 AD 服务器的 SSL 连接创建 PL/SQL 函数。

      1)我认为您所说的问题将通过以下方式解决:

      CREATE DIRECTORY mydir AS 'D:\wallets';
      

      在这种情况下授予 READ 和 WRITE 是不必要的,因为您会自动获得这些授权。 但是在此之后您将面临另一个问题。会是

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

      2) 如果您使用的是 11g DB 和最新版本的 Microsoft AD 服务器,您将无法通过 SSL 连接连接到 AD,因为 Oracle DB 中使用了密码。它们必须在 DB 和 AD 服务器中匹配,但 Oracle 使用的是旧的且恕我直言不安全的密码。 他们修复了这个问题,部分在 12c link 到 12c 的文档中

      2) 我设法在 11g 中解决此问题的唯一方法是通过 Java。 解决办法是这样的:

      SET SERVEROUTPUT ON;
      CALL dbms_java.set_output(1000);
      
      CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED LDAP AS
      import java.net.InetAddress;
      import java.net.UnknownHostException;
      import java.sql.*;
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;
      import java.util.Arrays;
      import java.util.Hashtable;
      import java.util.List;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      
      import javax.naming.Context;
      import javax.naming.NamingException;
      import javax.naming.directory.DirContext;
      import javax.naming.directory.InitialDirContext;
      
      public class ldap {
          public static boolean ldap_auth(String username, String password, String ldap_server, String application) throws SQLException, ClassNotFoundException, UnknownHostException{
      
      
              String keystore = "D:\\wallets";
              System.setProperty("javax.net.ssl.trustStore", keystore);
              System.setProperty("javax.net.ssl.trustStorePassword", "password");
      
              Class.forName("oracle.jdbc.driver.OracleDriver");
      
              Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:SID", "USER", "password");
      
              Hashtable env = new Hashtable(11);
              env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
              env.put(Context.PROVIDER_URL, ldap_server);
              env.put(Context.SECURITY_PROTOCOL, "ssl");
              env.put(Context.SECURITY_AUTHENTICATION, "simple");
              env.put(Context.SECURITY_PRINCIPAL, username);
              env.put(Context.SECURITY_CREDENTIALS, password);
      
              InetAddress addr;
              addr = InetAddress.getLocalHost();
              String ip = addr.getHostAddress();
      
      
      
              try {
                  DirContext ctx = new InitialDirContext(env);
      
                  System.out.println("Connection Successful!");
                  ctx.close();
      
                  return true;
              } catch (Exception e) {
                  String errorMsg = e.toString();
                  String[] errorCode = {"data 525", "data 773", "data 52e", "data 775", "data 701", "data 533", "data 532"};
                  String returnErrorCode = null;
      
                  List<String> list = Arrays.asList(errorCode);
                  for(String word : list){
                     if(errorMsg.contains(word)) {
                         returnErrorCode = word;
                     }
                  }
                  CallableStatement procin = conn.prepareCall("begin prc_log_action_java (:1,:2,:3,:4); end;");
                  username = username.substring(0, username.indexOf('@'));
                  procin.setString(1, username);
                  procin.setString(2, returnErrorCode);
                  procin.setString(3, ip);
                  procin.setString(4, application);
                  procin.execute();
                  procin.close();
      
                  System.out.println(errorMsg);
                  return false;
              }
      
          }
      };
      

      Try catch 部分用于记录我正在捕获并调用匿名块并插入到表中的 AD 服务器生成的错误消息,我认为您不需要此代码,但只是以防万一。 errorCode字段列出了AD服务器link to AD error codes生成的部分错误代码。

      之后,您需要像这样在 DB 中创建 PL/SQL 函数:

      create or replace function ldap_auth (p_username in varchar2, p_password in varchar2, p_ldap_server in varchar2)return boolean
      as language java
      name 'ldap.ldap_auth (java.lang.String, java.lang.String, java.lang.String, java.lang.String) return boolean';
      

      最后一件至关重要的事情是在 DB 中授予权限。

      call dbms_java.grant_permission( 'USER', 'SYS:java.net.SocketPermission', 'AD server:636', 'connect,resolve' );
      exec dbms_java.grant_permission( 'USER', 'SYS:java.util.PropertyPermission', 'javax.net.ssl.keyStore', 'write' );
      exec dbms_java.grant_permission( 'USER', 'SYS:java.util.PropertyPermission', 'javax.net.ssl.trustStorePassword', 'write' );
      
      commit;
      

      【讨论】:

      • 哇,这超出了我在解决方案中所希望的——我将在今天晚些时候试一试。谢谢!
      • 还有一件事,希望您使用 orapki 实用程序正确创建了钱包link to example
      【解决方案3】:

      我终于得到了原始方法。遵循此讨论中的指示(大部分)。是钱包目录的文件夹权限问题,需要为Oracle Server(服务)添加。

      为虚拟帐户“NT SERVICE\MSSQLSERVER”添加文件夹权限
      http://zarez.net/?p=3187

      您的 DBA 需要找出 Oracle 服务器(服务)的帐户。 对于我来说,使用 OracleXE 进行故障排除是:NT SERVICE\OracleServiceXE 尝试设置文件夹权限会产生一些阻力,因为我认为钱包管理器会创建访问权限非常有限的钱包文件,您必须是 Windows 管理员才能清除它们,然后重置它们。

      这些是钱包的 sql 代码设置,我能够在端口 636 上成功查询我们的 LDAP 服务器。

      -- SSL Certificate Wallet Location (file path) and wallet password, as defined by the DBA. 
      ssl_wallet_loc       VARCHAR2(256) := 'file:D:\OracleXE18g\dbhomeXE\owm\wallets\TestXE' ;     -- wallet location
      ssl_wallet_passwd    VARCHAR2(256) := 'WaLLeT123$' ;     -- wallet password
      ssl_wallet_auth      PLS_INTEGER := 2 ;         -- NO_AUTH: 1, ONE_WAY_AUTH: 2, TWO_WAY_AUTH: 3 
      

      【讨论】:

      • 哦,还有,我用firefox导出了我们公司的公共CA,并导入到Oracle Wallet管理器中。
      猜你喜欢
      • 1970-01-01
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-10
      相关资源
      最近更新 更多