Oracle PL/SQL LDAP - 无法打开钱包

Oracle PL/SQL LDAP - 无法打开钱包

问题描述:

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

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行

我被困在这一点上,我无法找到任何参考线上如何使这项工作。

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

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

1)我认为你说的问题,将与此解决:因为你全自动拿到这些赠款

CREATE DIRECTORY mydir AS 'D:\wallets'; 

授予READ在这种情况下写的是没有必要的。 但是你会在这之后遇到其他问题。这将是

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

2)如果你正在使用11克DB和微软AD服务器的最新版本中,你将无法通过SSL连接来连接到广告,因为Oracle数据库中使用的密码。他们必须匹配DB和AD服务器中的bouth,但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; 
     } 

    } 
}; 

尝试捕捉部分是用于记录由我赶上,并要求匿名块和插入表AD服务器生成的错误消息,我觉得你不需要这个代码,只是为情况。 errorCode字段列出了由AD服务器link to AD error codes生成的一些错误代码。

之后,你需要在数据库创建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补助premissions。

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; 
+0

哇,这比我本来希望得到的解决方案要好得多 - 我今天晚些时候会给出这个答案。谢谢! – kagaku

+0

还有一件事,我希望你使用orapki实用工具正确创建钱包[链接到示例](https://docs.oracle.com/cd/E29542_01/core.1111/e10105/walletmgr.htm#ASADM10183) – n33l1x