2017-05-02 11 views
2

次のコードは、OAuth2トークンを要求しています。これはIndy 10.0.52で動作しますが、Indy 10 SVN 5412では無効な要求資格情報が原因で400 Bad Requestエラーが生成されます。Indyアップグレード後のエンコードの問題

WXYZUserID :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZUserID, '')); 
WXYZPassword :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZPassword, '')) 
WXYZSecret :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZSecret, '')); 
OAuthURL  :=  Trim(GetSettingsValue(mySQLQuery, wcsOAuthURL, '')); 
WxyzHttp := TIdHttp.Create(nil); 
Serial := TStringList.Create; 
if (WXYZUserID <> '') and (WXYZPassword <> '') and (WXYZSecret <> '') then 
    Serial.Add('grant_type=password&username=' + WXYZUserID + '&password=' + WXYZPassword) 
Else 
    Serial.Add('grant_type=password&username=****-*****&password=***************'); 

Output := TMemoryStream.Create; 
Serial.SaveToStream(Output); 

WxyzHttp.ConnectTimeout := 60000; 

IdLogFile := TIdLogFile.Create; 
IdLogFile.Filename := 'Logs/WxyzHTTP' + FOrmatDateTime('yyyymmdd_hhnnsszzz',now) + '.log'; 
IdLogFile.Active := True; 

IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil); 
IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method := sslvSSLv23; 
IdSSLIOHandlerSocketOpenSSL1.Intercept := IdLogFile; 
WxyzHttp.IOHandler := IdSSLIOHandlerSocketOpenSSL1; 

if (WXYZUserID <> '') and (WXYZPassword <> '') and (WXYZSecret <> '') then 
    WxyzHttp.Request.CustomHeaders.Values['Authorization'] := 'Basic ' + WXYZSecret 
Else 
    WxyzHttp.Request.CustomHeaders.Values['Authorization'] := 'Basic ****************************************************************'; 

WxyzHttp.Request.ContentType := 'application/x-www-form-urlencoded; charset="utf-8"'; 

Try 
Token := WxyzHttp.Post(OAuthURL, Output); 
Except 
On E: Exception do 
Begin 
    DbgWebCatLog(wcmtDbg, 'GetSerialToken', E.ClassName + ' error raised, with message: ' + E.Message, ''); 
    Token := ''; 
    end; 
end; 

IdLogFileの日付を取得するコードを追加しました。 Indy 10.0.52バージョンのログには、資格情報を含む次の行が含まれています。

Sent 05/01/2017 18:34:35: grant_type=password&username=*************_*****-*****&password=***}%25**(**(*** 

セキュリティ上の理由から、すべての英数字を「*」に置き換えました。 "%25"文字はもともとは実際のパスワードの "%"でした。何かが元の "%"を "%25"に翻訳しましたが、他の特殊文字は変更しませんでした。

Indy 10 SVN 5412からのログの初期検査では、サーバーから無効な要求資格情報があることを示すメッセージが検出されました。さらに、上記の行に対応するすべての特殊文字は、すべての特殊文字がエンコードされていることを示しています。 grant_type、ユーザー名とパスワードは、私が見つけたtStringListを使ってurlencodingされています。ストリームを使用して同じデータをレンダリングするようにコードを変更しましたが、現在は何もエンコードされていません。 "%"は "%25"に翻訳されていません。無効な要求資格情報メッセージが引き続き取得されます。

私の質問は、なぜIndy 10.5.52で "%"文字のみを "%25"に変換するのでしょうか?

以下は、動作するIndy 10.0.52バージョンの完全なログです。

Stat Connected. 
Sent 05/01/2017 18:34:35: POST /auth/realms/hvac/tokens/grants/access HTTP/1.0<EOL>Content-Type: application/x-www-form-urlencoded; charset="utf-8"<EOL>Content-Length: 82<EOL>Authorization: Basic<EOL> **********<EOL>Host: services.ccs.utc.com:443<EOL>Accept: text/html, */*<EOL>Accept-Encoding: identity<EOL>User-Agent: Mozilla/4.0 (compatible; MSIE 8.0)<EOL><EOL> 
Sent 05/01/2017 18:34:35: grant_type=password&username=*************_*****-*****&password=***}**%25**(**(*** 
Recv 05/01/2017 18:34:35: HTTP/1.1 200 OK<EOL>Server: Apache-Coyote/1.1<EOL>Pragma: no-cache<EOL>Cache-Control: no-store<EOL>Content-Type: application/json;charset=UTF-8<EOL>Content-Length: 569<EOL>Date: Mon, 01 May 2017 22:34:35 GMT<EOL>Connection: close<EOL><EOL>{<EOL> "access_token":"**********",<EOL> "token_type":"Bearer",<EOL> "expires_in":1800,<EOL> "refresh_token":"**********",<EOL> "id_token":"**********"<EOL>} 
Stat Disconnected. 
Stat Disconnected 

以下は、無効な要求資格情報で失敗したIndy 10 SVN 5412バージョンのフルログです。

Stat Connected. 
Sent 05/02/2017 15:11:08: POST /auth/realms/hvac/tokens/grants/access HTTP/1.0<EOL>Connection: keep-alive<EOL>Content-Type: application/x-www-form-urlencoded; charset=utf-8<EOL>Content-Length: 82<EOL>Authorization: Basic **********<EOL>Host: services.ccs.utc.com<EOL>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<EOL>User-Agent: Mozilla/3.0 (compatible; Indy Library)<EOL><EOL> 
Sent 05/02/2017 15:11:08: grant_type=password&username=*************_*****-*****&password=***}**%**(**(***<EOL> 
Recv 05/02/2017 15:11:08: HTTP/1.1 400 Bad Request<EOL>Server: Apache-Coyote/1.1<EOL>Content-Type: application/json;charset=UTF-8<EOL>Content-Length: 84<EOL>Date: Tue, 02 May 2017 19:11:08 GMT<EOL>Connection: close<EOL><EOL>{<LF> "error": "invalid_grant",<LF> "error_description": "Invalid request credentials"<LF>} 
Stat Disconnected. 
Stat Disconnected. 

答えて

4

あなたはインディのすべてのバージョンでは、どのような方法でそれをコードしないよう-ある、TIdHTTPを掲示ますTMemoryStreamを、掲示されています。 TMemoryStreamの内容が正しくフォーマットされていることを確認する責任はお客様にあります。それはインディーではなく、あなたの上にあります。

TIdHTTP.Post()はあなたのためにapplication/x-www-webform-urlencoded形式の文字列をフォーマットすることポストTStrings代わりのTStream、過負荷を持っています。 TMemoryStreamはまったく使用する必要はありません。インディ10.0.52、TIdHTTP.Post(TStrings)

のみvaluename=valueの対をコードし、それはTIdURI.ParamsEncode()を使用してエンコードし、セット'*#%<> []'であるか包括#33..#128との間のASCII文字でない任意の文字%は、コードします。 10.0.52はUnicode対応ではないため、文字列をUTF-8にエンコードすることはなく、Delphi 2009 +のUnicodeStringタイプ(またはさらにWideString)をサポートしていません。したがって、TStringsに格納されている文字列は、UTF-8形式でなければなりません(Delphi 2009以降の場合は、UTF-8でなければならず、各コードユニットに16ビット文字を使用する必要があります)。 8ビット文字)。

最新のIndyバージョン(この執筆時点では10.6.2.5418)では、TIdHTTP.Post(TStrings)は完全にUnicode対応であり、UnicodeStringをサポートしています。namevalueの両方がname=valueのペアでエンコードされ、'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz*-._' にないUnicode文字をUTF-8にエンコードすることで、HTML5標準に準拠して手動でエンコードします(TIdURIは使用しません)(デフォルトでは、 AByteEncodingパラメータ:Post())を使用して、結果のバイトオクテットをパーセントエンコードします。言ったことで

、より多くのこのような何かを試してみてください。

try 
    WXYZUserID :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZUserID, '')); 
    WXYZPassword :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZPassword, '')) 
    WXYZSecret :=  Trim(GetSettingsValue(mySQLQuery, wcsWXYZSecret, '')); 
    OAuthURL  :=  Trim(GetSettingsValue(mySQLQuery, wcsOAuthURL, '')); 

    WxyzHttp := TIdHttp.Create(nil); 
    try 
    WxyzHttp.ConnectTimeout := 60000; 

    IdLogFile := TIdLogFile.Create(WxyzHttp); 
    IdLogFile.Filename := 'Logs/WxyzHTTP' + FormatDateTime('yyyymmdd_hhnnsszzz',now) + '.log'; 
    IdLogFile.Active := True; 

    IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(WxyzHttp); 
    IdSSLIOHandlerSocketOpenSSL1.SSLOptions.Method := sslvSSLv23; 
    IdSSLIOHandlerSocketOpenSSL1.Intercept := IdLogFile; 
    WxyzHttp.IOHandler := IdSSLIOHandlerSocketOpenSSL1; 

    if (WXYZSecret <> '') then 
     WxyzHttp.Request.CustomHeaders.Values['Authorization'] := 'Basic ' + WXYZSecret 
    else 
     WxyzHttp.Request.CustomHeaders.Values['Authorization'] := 'Basic ****************************************************************'; 

    WxyzHttp.Request.ContentType := 'application/x-www-form-urlencoded'; 
    WxyzHttp.Request.CharSet := 'utf-8'; 

    Serial := TStringList.Create; 
    try 
     Serial.Add('grant_type=password'); 

     if (WXYZUserID <> '') and (WXYZPassword <> '') then 
     begin 
     Serial.Add('username=' + WXYZUserID); 
     Serial.Add('password=' + WXYZPassword); 
     end else 
     begin 
     Serial.Add('username=****-*****'); 
     Serial.Add('password=***************'); 
     end; 

     Token := WxyzHttp.Post(OAuthURL, Serial); 
    finally 
     Serial.Free; 
    end; 
    finally 
    WxyzHttp.Free; 
    end; 
except 
    on E: Exception do 
    begin 
    DbgWebCatLog(wcmtDbg, 'GetSerialToken', E.ClassName + ' error raised, with message: ' + E.Message, ''); 
    Token := ''; 
    end; 
end; 
+0

あなたのレミーをありがとうございます。 tStringListを構築するコードを再構築することはやりました。 –

関連する問題