2012-08-23 37 views
13

Tôi cần tạo giao dịch Xác thực SAML 2.0 do SP bắt đầu bằng phương thức Ràng buộc Chuyển hướng HTTP. Hóa ra điều này khá dễ dàng. Chỉ nhận được URI IdP và nối một tham số chuỗi truy vấn đơn SAMLRequest. Tham số là khối mã hóa xml mô tả yêu cầu SAML. Càng xa càng tốt.Làm cách nào để chuẩn bị chính xác yêu cầu SAML 'Chuyển hướng HTTP' bằng cách sử dụng C#

Sự cố xảy ra khi chuyển đổi SAML thành tham số chuỗi truy vấn. Tôi tin rằng quá trình này chuẩn bị nên là:

  1. Xây dựng một chuỗi SAML
  2. Compress chuỗi này
  3. Base64 mã hóa chuỗi
  4. URLEncode chuỗi.

Các SAML Yêu cầu

<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> 

Bộ luật

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); 
    } 
} 

tôi nghi ngờ nén là bằng cách nào đó để đổ lỗi. Tôi đang sử dụng các lớp học DeflaterOutputStream từ SharpZipLib đó là nghĩa vụ phải thực hiện một tiêu chuẩn công nghiệp deflate-thuật toán vì vậy có lẽ có một số cài đặt ở đây tôi đã sai?

Đầu ra được mã hóa có thể được kiểm tra bằng cách sử dụng SAML2.0 Debugger (một công cụ chuyển đổi trực tuyến hữu ích của nó). Khi tôi giải mã đầu ra của tôi bằng cách sử dụng công cụ này nó đi ra như vô nghĩa.

Do đó, câu hỏi là: Bạn có biết cách chuyển đổi chuỗi SAML thành tham số truy vấn SAMLRequest được mã hóa và được mã hóa chính xác không?

Cảm ơn bạn

EDIT 1

Câu trả lời được chấp nhận dưới đây đưa ra câu trả lời cho vấn đề này. Đây là mã cuối cùng được sửa chữa bởi tất cả các ý kiến ​​và câu trả lời tiếp theo.

Encode SAMLRequest - Mã Working

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); 
    } 
} 

Biến SAMLRequest chứa SAML hiển thị ở phía trên cùng của câu hỏi này.

Giải mã SAMLResponse - Mã Working

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)); 
    } 
} 
+0

Tôi không thể sử dụng "Mã SAMLResponse giải mã - Mã làm việc" theo cách viết. Tôi đã phải tách đầu vào từ đầu ra MemoryStream. Tôi cũng đã phải UrlDecode và Convert.FromBase64String (...) trước khi thực hiện DeflateStream. Chỉ nghĩ rằng tôi sẽ ghi chú trong trường hợp nó giúp người tiếp theo. –

+0

Bạn có thể đăng mã làm việc của bạn được không. – biofractal

+0

Hey Randall, bạn có thể cung cấp mã cho những thay đổi bạn đã thực hiện cho "Giải mã SAMLResponse - Mã làm việc" không? Điều đó sẽ được nhiều đánh giá cao! Cảm ơn – Naner

Trả lời

11

Tôi đã chỉ cần chạy đoạn mã sau với ví dụ SAML của bạn:

 var saml = string.Format(sample, Guid.NewGuid()); 
     var bytes = Encoding.UTF8.GetBytes(saml); 

     string middle; 
     using (var output = new MemoryStream()) 
     { 
      using (var zip = new DeflaterOutputStream(output)) 
       zip.Write(bytes, 0, bytes.Length); 

      middle = Convert.ToBase64String(output.ToArray()); 
     } 

     string decoded; 
     using (var input = new MemoryStream(Convert.FromBase64String(middle))) 
     using (var unzip = new InflaterInputStream(input)) 
     using (var reader = new StreamReader(unzip, Encoding.UTF8)) 
      decoded = reader.ReadToEnd(); 

     bool test = decoded == saml; 

Biến thử nghiệm là true. Điều này có nghĩa là vòng lặp zip/base64/unbase64/unzip thực hiện chính xác. Lỗi phải xảy ra sau. Có lẽ URLEncoder phá hủy chúng? Bạn có thể thử thử nghiệm urlencode/decode tương tự không? Ngoài ra, kiểm tra kết quả là bao lâu. Có thể là URL kết quả bị cắt ngắn do độ dài của nó.

(chỉnh sửa: Tôi đã thêm StreamReader thay vì đọc vào mảng. Trước đó mẫu của tôi đã sử dụng byte.Length để chuẩn bị bộ đệm và điều đó có thể làm hỏng kiểm tra. Bây giờ chỉ đọc thông tin từ luồng nén)

chỉnh sửa:

 var saml = string.Format(sample, Guid.NewGuid()); 
     var bytes = Encoding.UTF8.GetBytes(saml); 

     string middle; 
     using (var output = new MemoryStream()) 
     { 
      using (var zip = new DeflateStream(output, CompressionMode.Compress)) 
       zip.Write(bytes, 0, bytes.Length); 

      middle = Convert.ToBase64String(output.ToArray()); 
     } 

     // MIDDLE is the thing that should be now UrlEncode'd 

     string decoded; 
     using (var input = new MemoryStream(Convert.FromBase64String(middle))) 
     using (var unzip = new DeflateStream(input, CompressionMode.Decompress)) 
     using (var reader = new StreamReader(unzip, Encoding.UTF8)) 
      decoded = reader.ReadToEnd(); 

     bool test = decoded == saml; 

mã này tạo ra một biến middle, đã từng là urlencoded, đi qua debugger đúng cách. DeflateStream xuất phát từ tiêu chuẩn .Net của System.IO.Compression không gian tên. Tôi không có ý tưởng nhỏ nhất tại sao Deflate của SharpZip không được trang web 'trình gỡ lỗi' chấp nhận. Nó là không thể phủ nhận rằng nén hoạt động, vì nó quản lý để giải nén dữ liệu đúng .. nó chỉ có được một số sự khác biệt trong các thuật toán, nhưng tôi không thể nói sự khác biệt giữa deflate này là gì và deflate, d'oh.

+0

trang web trình gỡ lỗi bạn đã cung cấp hiển thị ví dụ về thư được mã hóa. Tôi đã cố gắng giải nén nó với Deflate và GZip - và điều đó là không thể .. Ngay cả GZipStream của Net cũng không thể giải mã được .. Thuật toán nén nào sử dụng nó? – quetzalcoatl

+0

Tôi đã tìm thấy một máy nén hoạt động với trang web mẫu và tôi đã cập nhật lại câu trả lời. Vui lòng đọc lại phần cuối cùng :) – quetzalcoatl

+0

Công việc tuyệt vời. Mã của bạn làm việc rất đẹp. Cảm ơn bạn :-) – biofractal

6

Câu hỏi ở trên cùng chứa phần "Mã SAMLResponse giải mã - Mã làm việc", nhưng mã đó dường như bị hỏng. Sau khi thử một vài thứ, tôi phát hiện ra rằng nó đang cố gắng đọc và viết vào cùng một luồng cùng một lúc. Tôi làm lại nó bằng cách tách đọc và ghi các luồng và đây là giải pháp của tôi (tôi đang cung cấp các phần yêu cầu cho thuận tiện và rõ ràng):

Encode SAML Xác thực Yêu cầu:

public static string EncodeSamlAuthnRequest(this string authnRequest) { 
    var bytes = Encoding.UTF8.GetBytes(authnRequest); 
    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); 
    } 
    } 

Giải mã SAML Xác thực Trả lời:

public static string DecodeSamlAuthnRequest(this string encodedAuthnRequest) { 
    var utf8 = Encoding.UTF8; 
    var bytes = Convert.FromBase64String(HttpUtility.UrlDecode(encodedAuthnRequest)); 
    using (var output = new MemoryStream()) { 
    using (var input = new MemoryStream(bytes)) { 
     using (var unzip = new DeflateStream(input, CompressionMode.Decompress)) { 
     unzip.CopyTo(output, bytes.Length); 
     unzip.Close(); 
     } 
     return utf8.GetString(output.ToArray()); 
    } 
    } 
} 
Các vấn đề liên quan