2016-11-19 93 views
0

我嘗試使用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行

我被困在這一點上,我無法找到任何參考線上如何使這項工作。

回答

1

您可以嘗試在l_wallet_ssl的聲明中使用pls_integer而不是number。另外,考慮從open_ssl函數調用中刪除when others exception以查看是否可以獲得更有用的錯誤(請參閱表4-86,瞭解來自this link的錯誤範圍)。

1

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