从plsql调用webservice时的2路ssl身份验证

时间:2013-12-27 06:59:00

标签: web-services plsql ssl-certificate

我正在尝试从PL / SQL块调用第三方Web服务。

对于使用SSL,我从网站下载了证书并安装在Oracle钱包中。

现在客户端需要双向SSL身份验证。怎么做到这一点?我是否需要在HTTP调用中添加其他内容?

以下是我正在使用的代码。

create or replace function GetDeptInfo( arg0 number ) return XmlType is
    --// URL to call
    SOAP_URL constant varchar2(1000) := 'https://google.com:7002/WebService-Annotation-context-root/MyCompanyPort';

    SOAP_ENVELOPE constant varchar2(32767) :=
        '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://annotation/">
             <env:Header/>
             <env:Body>
                 <ns1:getDeptInfo>
                          <arg0>$arg0</arg0>
                 </ns1:getDeptInfo>
             </env:Body>
         </env:Envelope>';

    --// we'll identify ourselves using an IE9/Windows7 generic browser signature
    C_USER_AGENT    constant varchar2(4000) := 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)';

    --// these variables need to be set if web access
    --// is via a proxy server
    proxyServer varchar2(20) default null;
    proxyUser   varchar2(20) default null;
    proxyPass   varchar2(20) default null;

    --// our local variables
    soapEnvelope    varchar2(32767);
    proxyURL        varchar2(4000);
    request         utl_http.req;
    response        utl_http.resp;
    buffer          varchar2(32767);
    soapResponse    clob;
    xmlResponse     XmlType;
    eof             boolean;
begin
    --// create the SOAP envelope
    soapEnvelope := replace( SOAP_ENVELOPE, '$arg0', arg0 );

    --// our "browser" settings
    utl_http.set_response_error_check( true );
    utl_http.set_detailed_excp_support( true );
    utl_http.set_cookie_support( true );
    utl_http.set_transfer_timeout( 10 );
    utl_http.set_follow_redirect( 3 );
    utl_http.set_persistent_conn_support( true );

    --// configure for web proxy access if applicable
    if proxyServer is not null then
        proxyURL := 'http://'||proxyServer;
        if (proxyUser is not null) and (proxyPass is not null) then
            proxyURL := Replace( proxyURL, 'http://',  'http://'||proxyUser||':'||proxyPass||'@' );
        end if;
        utl_http.set_proxy( proxyURL, null );
    end if;

    --// make the POST call to the web service
    UTL_HTTP.set_wallet('file:/tmp/DEVF1MB/wallet', 'WalletPasswd123');
    request := utl_http.begin_request( SOAP_URL, 'POST', utl_http.HTTP_VERSION_1_1 );
    utl_http.set_header( request, 'User-Agent', C_USER_AGENT );
    utl_http.set_header( request, 'Content-Type', 'text/xml; charset=utf-8' );
    utl_http.set_header( request, 'Content-Length', length(soapEnvelope) );

    utl_http.set_header( request, 'SoapAction', 'http://www.webserviceX.NET/GetWeather' );
    utl_http.write_text( request, soapEnvelope );

    --// read the web service HTTP response
    response := utl_http.get_response( request );
    dbms_lob.CreateTemporary( soapResponse, true );
    eof := false;
    loop
        exit when eof;
        begin
            utl_http.read_line( response, buffer, true );
            if length(buffer) > 0 then
                dbms_lob.WriteAppend(
                    soapResponse,
                    length(buffer),
                    buffer
                );
            end if;

        exception when utl_http.END_OF_BODY then
            eof := true;
        end;

    end loop;
    utl_http.end_response( response );

    --// as the SOAP responds with XML, we convert
    --// the response to XML
    xmlResponse := XmlType( soapResponse );
    dbms_lob.FreeTemporary( soapResponse );

    return( xmlResponse );

exception when OTHERS then
    if soapResponse is not null then
        dbms_lob.FreeTemporary( soapResponse );
    end if;
    raise;
end;

2 个答案:

答案 0 :(得分:1)

这是我的2美分:(并且有效;-))

首先,我成功地使用utl_http调用一个Web服务到一个关闭的wsdl,它是一个http URL。

接下来,当网络服务主机将网址更改为https时,我将其证书导入我的电子钱包后仍然取得了成功。在做begin_request之前有这个陈述:

UTL_HTTP.SET_WALLET ('file:/tmp/wallet/dp_wallet','pass1234');

(我在tmp文件夹中测试它,我有权测试)。它也有效,直到他们强制执行双向身份验证。   我一直在寻找一种方法,在拨打电话时发送(提供)我的证书。我没有成功:致命的SSL错误。

对你有用的几个技巧:

  1. 请勿将钱包密码用作&#34;密码&#34;。或者任何简单。请使用数字。如果有的话,错误消息并不明显。我使用smart1234并且它有效。

  2. 您必须已添加解析,将当前用户连接到网络acl。请添加以下内容以及钱包(这有所不同):

    BEGIN
        DBMS_NETWORK_ACL_ADMIN.ASSIGN_WALLET_ACL('www.xml','file:/tmp/wallet/dp_wallet');
    END;
    /
    COMMIT;
    
  3. 提供对世界的读取权限(以防万一)。错误很容易识别。它将是:&#34;无法打开文件&#34;

  4. 使用测试sql是一个好主意,但并不意味着你在实际的begin_request中取得了成功:

    SELECT utl_http.request('https://dpserver:4401/tuxops/LookUp',
                            '',
                            'file:/tmp/wallet/dp_wallet',
                            'smart1234')
    FROM dual;
    
  5. 退出并从此用户重新登录!

  6. 有时需要几分钟才能生效!我很难测试,因为我忽略了这两个。

  7. 如果您提供了3次或更多次错误密码或其他故障,则可能会有延迟成功。 简单的选择是注销并重新登录。这会重置会话错误。

  8. 希望我的发现对你有用:)

答案 1 :(得分:0)

从概念上讲,您需要与第三方交换SSL证书,在您的客户端为2路SSL生成。 它完全取决于Web服务(wsdl)提供程序的配置。 通常,https模式下有两种类型的web服务配置。

  1. 没有客户端身份验证的https
  2. https with client authentication
  3. 如果提供商已将其Web服务配置为“使用客户端身份验证进行https”,那么您必须与他交换SSL证书(双向SSL)。在这种情况下,您还需要提供从客户端生成的SSL证书,以便在第三方服务器上安装,反之亦然。但只有在提供程序已配置为以此方式与您进行该Web服务通信时,它才有效。

    在第二个选项中,通常信任您(客户)端的第三方Web服务端点URL工作,无需交换证书。