2014-11-18 43 views
0

저는 Delphi XE 6 및 TIdHttp 구성 요소 (Indy 10.6.0.5122)를 사용 중이며 http 프록시 (CCProxy - http://www.youngzsoft.net/ccproxy/)를 통해 SOAP 서비스 - http://www.webservicex.net/globalweather.asmx을 사용하려고합니다.Delphi - Authorization TIdHttp가 HTTP 프록시를 통해 실패했습니다.

<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><h1>Unauthorized ...</h1> 
<h2>IP Address: xxx.xxx.xxx.:61295<br> 
MAC Address: <br> 
Server Time: 2014-11-18 14:19:00<br> 
Auth Result: </h2></body></html> 

내가 문제를 디버깅하기 위해 IdHttp에 IdSSLIOHandlerSocketOpenSSL 및 IdLogDebug1 구성 요소를 연결 한 : 문제는 웹 서비스에 연결하는 첫 번째 시도에서 내가 "무단"respone를받을 수 있습니다. 작업의

로그 지금

***********************IdSSLIOHandlerSocketOpenSSL1Status 
Connecting to xxx.xxx.xxx.xxx. 

***********************IdLogDebug1Send 
POST http://www.webservicex.net/globalweather.asmx HTTP/1.1 
Content-Type: text/xml; charset=utf-8 
Content-Length: 388 
SOAPAction: http://www.webserviceX.NET/GetCitiesByCountry 
Host: www.webservicex.net 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Encoding: identity 
User-Agent: Mozilla/3.0 (compatible; Indy Library) 



***********************IdLogDebug1Send 
<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Body> 
    <GetCitiesByCountry xmlns="http://www.webserviceX.NET"> 
     <CountryName>Romania</CountryName> 
    </GetCitiesByCountry> 
    </soap:Body> 
</soap:Envelope> 

***********************IdLogDebug1Receive 
HTTP/1.0 407 Unauthorized 
Server: Proxy 
Proxy-Authenticate: Basic realm="CCProxy Authorization" 
Cache-control: no-cache 

<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><h1>Unauthorized ...</h1> 
<h2>IP Address: xxx.xxx.xxx.xxx:61295<br> 
MAC Address: <br> 
Server Time: 2014-11-18 14:19:00<br> 
Auth Result: </h2></body></html> 

***********************IdSSLIOHandlerSocketOpenSSL1Status 
Disconnected. 

을 수행, 흥미로운 것은 내가 웹 서비스의 모든 전화를 다시 시도하고 경우에하는 것이 제대로 작동한다는 것입니다. 작업 로그 :

***********************IdSSLIOHandlerSocketOpenSSL1Status 
Connecting to xxx.xxx.xxx.xxx. 

***********************IdLogDebug1Send 
POST http://www.webservicex.net/globalweather.asmx HTTP/1.1 
Content-Type: text/xml; charset=utf-8 
Content-Length: 388 
SOAPAction: http://www.webserviceX.NET/GetCitiesByCountry 
Host: www.webservicex.net 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Encoding: identity 
User-Agent: Mozilla/3.0 (compatible; Indy Library) 
Proxy-Authorization: Basic YW1ibzphbWJvIQ== 



***********************IdLogDebug1Send 
<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Body> 
    <GetCitiesByCountry xmlns="http://www.webserviceX.NET"> 
     <CountryName>Romania</CountryName> 
    </GetCitiesByCountry> 
    </soap:Body> 
</soap:Envelope> 

***********************IdLogDebug1Receive 
HTTP/1.1 200 OK 
Cache-Control: private, max-age=0 
Content-Length: 2456 


***********************IdLogDebug1Receive 
Content-Type: text/xml; charset=utf-8 
Server: Microsoft-IIS/7.0 
X-AspNet-Version: 4.0.30319 
X-Powered-By: ASP.NET 
Date: Tue, 18 Nov 2014 12:26:21 GMT 

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetCitiesByCountryResponse xmlns="http://www.webserviceX.NET"><GetCitiesByCountryResult>&lt;NewDataSet&gt; 
    &lt;Table&gt; 
    &lt;Country&gt;Romania&lt;/Country&gt; 
    &lt;City&gt;Arad&lt;/City&gt; 
    &lt;/Table&gt; 
    &lt;Table&gt; 
    &lt;Country&gt;Romania&lt;/Country&gt; 
    &lt;City&gt;Bacau&lt;/City&gt; 
    &lt;/Table&gt; 
    ...... 

응답이 맞습니다. 첫 번째 시도에서 작업하기 위해 응용 프로그램

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, 
    IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, Soap.SOAPHTTPTrans, 
    IdAuthentication, IdHeaderList, IdIntercept, IdLogBase, IdLogDebug, 
    IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL 
    ,IdGlobal; 

type 
    TForm1 = class(TForm) 
    IdHTTP1: TIdHTTP; 
    Button1: TButton; 
    HTTPReqResp1: THTTPReqResp; 
    Memo1: TMemo; 
    Button2: TButton; 
    Button3: TButton; 
    Button4: TButton; 
    IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL; 
    IdLogDebug1: TIdLogDebug; 
    Memo2: TMemo; 
    procedure Button1Click(Sender: TObject); 
    procedure Button2Click(Sender: TObject); 
    procedure Button3Click(Sender: TObject); 
    procedure Button4Click(Sender: TObject); 
    procedure FormCreate(Sender: TObject); 
    procedure IdHTTP1ProxyAuthorization(Sender: TObject; 
     Authentication: TIdAuthentication; var Handled: Boolean); 
    procedure IdSSLIOHandlerSocketOpenSSL1StatusInfo(const AMsg: string); 
    procedure IdSSLIOHandlerSocketOpenSSL1Status(ASender: TObject; 
     const AStatus: TIdStatus; const AStatusText: string); 
    procedure IdLogDebug1Receive(ASender: TIdConnectionIntercept; 
     var ABuffer: TIdBytes); 
    procedure IdLogDebug1Send(ASender: TIdConnectionIntercept; 
     var ABuffer: TIdBytes); 
    procedure IdHTTP1Authorization(Sender: TObject; 
     Authentication: TIdAuthentication; var Handled: Boolean); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    postData: TMemoryStream; 
begin 
    postData := TMemoryStream.Create; 
    try 
    Memo1.Lines.Clear; 
    postData.LoadFromFile('..\..\soap1.1.txt'); 
    IdHTTP1.Request.ContentType := 'text/xml'; 
    IdHTTP1.Request.Charset := 'utf-8'; 
    IdHTTP1.Request.CustomHeaders.Values['SOAPAction'] := 'http://www.webserviceX.NET/GetCitiesByCountry'; 
    IdHTTP1.ProtocolVersion := pv1_1; 
    IdHTTP1.HTTPOptions := IdHTTP1.HTTPOptions + [hoKeepOrigProtocol]; 
    Memo1.Lines.Text := IdHTTP1.Post('http://www.webservicex.net/globalweather.asmx', postData); 
    finally 
    postData.Free; 
    end; 
end; 


procedure TForm1.FormCreate(Sender: TObject); 
begin 
with IdHTTP1.ProxyParams do 
    begin 
    ProxyServer := 'xxx.xxx.xxx.xxx'; 
    ProxyPort := 808; 
    ProxyUsername := 'User-001'; 
    ProxyPassword := 'User-001!'; 
    end; 

end; 

procedure TForm1.IdHTTP1Authorization(Sender: TObject; 
    Authentication: TIdAuthentication; var Handled: Boolean); 
begin 
// 
    Authentication.Username := 'User-001'; 
    Authentication.Password := 'User-001!'; 
end; 

procedure TForm1.IdHTTP1ProxyAuthorization(Sender: TObject; 
    Authentication: TIdAuthentication; var Handled: Boolean); 
begin 
// 
// Authentication.Username := 'User-001'; 
// Authentication.Password := 'User-001!'; 
// Handled := true; 
end; 

procedure TForm1.IdLogDebug1Receive(ASender: TIdConnectionIntercept; 
    var ABuffer: TIdBytes); 
begin 
Memo2.Lines.Add(#13#10+'***********************IdLogDebug1Receive '+#13#10+BytesToString(ABuffer)) 
end; 

procedure TForm1.IdLogDebug1Send(ASender: TIdConnectionIntercept; 
    var ABuffer: TIdBytes); 
begin 
Memo2.Lines.Add(#13#10+'***********************IdLogDebug1Send '+#13#10+BytesToString(ABuffer)) 
end; 

procedure TForm1.IdSSLIOHandlerSocketOpenSSL1Status(ASender: TObject; 
    const AStatus: TIdStatus; const AStatusText: string); 
begin 
Memo2.Lines.Add(#13#10+'***********************IdSSLIOHandlerSocketOpenSSL1Status '+#13#10+AStatusText) 
end; 

procedure TForm1.IdSSLIOHandlerSocketOpenSSL1StatusInfo(const AMsg: string); 
begin 
Memo2.Lines.Add(#13#10+'***********************IdSSLIOHandlerSocketOpenSSL1StatusInfo '+#13#10+AMsg) 
end; 

end. 

코드는 어떻게 인증을해야합니까?

추신 : 나는 이미이 질문 - Authorization failure TIdHTTP over HTTPS을 읽었습니다.

답변 : 레미 Lebeau 문제의 지시에 따라이

OnProxySelectAuthorization

의 이벤트

을 설정하여 해결하고

IdHTTP1에 hoInProcessAuth를 추가했다. HTTPOptions

+1

, 왜 THTTPRIO와 웹 서비스를 소비하지? – whosrdaddy

+0

나는 THttpRio로 webservice를 소비하려고 시도했지만, 클라이언트와 webservice 사이에 http 프록시가 존재할 때 델파이 SOAP 구현이 버그가 있으며 둘 다 인증을 요구할 때 ... – RBA

+0

감사합니다. downvoter. -1에 대한 이유를 제공해야합니다. – RBA

답변

2

당신이 그렇게 TIdHTTP 당신이 (그냥 Handled:=True을 반환하는 경우에도) 할당 TIdHTTP.OnProxyAuthorization 이벤트 핸들러가 있는지 확인도 407 회신 Proxy-Authorization 헤더를 처리하고 할 수 uses 절에 IdAuthentication 장치를 추가했는지 확인하십시오, 그렇지 않으면 TIdHTTP이 시도하지 않습니다 TIdHTTP.ProxyParams 등록 정보에 사용자 이름/암호를 제공 했더라도 407 응답을 처리하는 동안 프록시 인증이 필요합니다.

은 무엇 가능성이 일어나고있는 것은 TIdHTTP.ProxyParams.Authentication 속성이 초기에 첫 번째 요청시 nil을하고 407 응답을 처리하는 동안 TIdBasicAuthentication 대상으로 채워집니다하지만 누락 된 OnProxyAuthorization 이벤트 핸들러가 다음 승인을 건너 TIdHTTP을 초래하고 있다는 것입니다 두 번째 요청이 이루어지면 TIdHTTP.ProxyParams.Authentication 속성이 더 이상 0이 아니므로 해당 시간에 권한 부여를 시도합니다.

TIdHTTP.OnProxyAuthorization 이벤트가 할당되지 않은 경우 프록시 인증을 건너 뛸 때 버그가있는 것으로 보입니다 (IMHO). 이에 비해 속성에 비어 있지 않은 값이 할당되어있는 한 TIdHTTP.OnAuthorization 이벤트는 할당 해제 될 수 있습니다. TIdHTTP.ProxyParams.Password 속성에 관한 OnProxyAuthorization 이벤트에 대해 비슷한 로직을 가진 TIdHTTP을 업데이트했습니다.

그래서, 최신 SVN의 스냅 샷 업데이트 또는 단지 TIdHTTP.OnProxyAuthorization 이벤트 핸들러를 할당 중 하나는, 당신은 확인을해야한다 : 나는 요청할 수 있습니다 경우

procedure TForm1.IdHTTP1ProxyAuthorization(Sender: TObject; Authentication: TIdAuthentication; var Handled: Boolean); 
begin 
    // prompt the user for username/password (optional) and store them 
    // in the Authentication.Username and Authentication.Password 
    // properties, respectively. By default, they are initialized with 
    // the current values of the ProxyParams.UserName and 
    // ProxyParams.Password properties... 
    Handled := True; 
end; 
+0

당신이 말한대로 이벤트를 추가했지만, AuthenticationClass가 nil이 아니더라도 결과는 동일합니다. IdHTTP1SelectProxyAuthorization (발신자 : TObject; var AuthenticationClass : TIdAuthenticationClass; ...); AuthenticationClass = nil 인 경우 showmessage ('nil'); 끝; – RBA

+0

'OnProxySelectAuthorization' 이벤트 핸들러에 추가하면 해결할 것이라고 제안하지 않았습니다. 나는'IdAuthentication' 유닛을'uses' 절에 추가하는 것이 그것을 고쳐야한다고 제안했습니다. 하지만 OnProxyAuthorization 버그가있는 것 같습니다. 내 대답을 세부 사항으로 업데이트했습니다. –

+0

이미 uses 절에 추가되었습니다. 나는 당신의 업데이트를 시도 할 것이고 그것이 맞으면 대답을 받아 들일 것이다. – RBA