HTTP リダイレクト バインディング メソッドを使用して、SP が開始した SAML 2.0 認証トランザクションを作成する必要があります。これは非常に簡単です。IdP URI を取得し、単一のクエリ文字列 param を連結するだけ SAMLRequest
です。param は、SAML リクエストを記述する xml のエンコードされたブロックです。ここまでは順調ですね。
問題は、SAML をクエリ文字列パラメーターに変換するときに発生します。この準備プロセスは次のようにする必要があると思います。
- SAML 文字列を作成する
- この文字列を圧縮します
- Base64 で文字列をエンコードします
- 文字列を UrlEncode します。
SAML リクエスト
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="{0}"
Version="2.0"
AssertionConsumerServiceIndex="0"
AttributeConsumingServiceIndex="0">
<saml:Issuer>URN:xx-xx-xx</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
コード
private string GetSAMLHttpRedirectUri(string idpUri)
{
var saml = string.Format(SAMLRequest, Guid.NewGuid());
var bytes = Encoding.UTF8.GetBytes(saml);
using (var output = new MemoryStream())
{
using (var zip = new DeflaterOutputStream(output))
{
zip.Write(bytes, 0, bytes.Length);
}
var base64 = Convert.ToBase64String(output.ToArray());
var urlEncode = HttpUtility.UrlEncode(base64);
return string.Concat(idpUri, "?SAMLRequest=", urlEncode);
}
}
なんらかの理由で圧縮が原因だと思います。業界標準の deflate-algorithm を実装することになっているSharpZipLibDeflaterOutputStream
のクラスを使用しているので、ここにいくつかの設定が間違っている可能性がありますか?
エンコードされた出力は、このSAML2.0 Debugger (便利なオンライン変換ツール) を使用してテストできます。このツールを使用して出力をデコードすると、意味がありません。
したがって、問題は次のとおりです。SAML 文字列を正しくデフレートおよびエンコードされた SAMLRequest クエリ パラメータに変換する方法を知っていますか?
ありがとうございました
編集1
以下の受け入れられた回答は、問題に対する回答を提供します。これは、後続のすべてのコメントと回答によって修正された最終的なコードです。
SAMLRequest のエンコード - 作業コード
private string GenerateSAMLRequestParam()
{
var saml = string.Format(SAMLRequest, Guid.NewGuid());
var bytes = Encoding.UTF8.GetBytes(saml);
using (var output = new MemoryStream())
{
using (var zip = new DeflateStream(output, CompressionMode.Compress))
{
zip.Write(bytes, 0, bytes.Length);
}
var base64 = Convert.ToBase64String(output.ToArray());
return HttpUtility.UrlEncode(base64);
}
}
このSAMLRequest
変数には、この質問の上部に示されている SAML が含まれています。
SAMLResponse のデコード - 作業コード
private string DecodeSAMLResponse(string response)
{
var utf8 = Encoding.UTF8;
var bytes = utf8.GetBytes(response);
using (var output = new MemoryStream())
{
using (new DeflateStream(output, CompressionMode.Decompress))
{
output.Write(bytes, 0, bytes.Length);
}
var base64 = utf8.GetString(output.ToArray());
return utf8.GetString(Convert.FromBase64String(base64));
}
}