2012-03-29 20 views
5

Tôi đang tạo một ứng dụng iPhone cho phép người dùng tương tác với một máy chủ được bảo mật. Tuy nhiên, để xác thực người dùng, ứng dụng cần phải trải qua SAML từ máy chủ mà người dùng đăng nhập vào máy chủ dữ liệu được bật (cung cấp SSO). Vì vậy, ứng dụng bắt chước gửi yêu cầu HTTP SAML (thông thường trình duyệt sẽ xử lý).Làm cách nào để đăng thông báo phản hồi SAML bằng NSURLConnection?

Quá trình này hoạt động với Ruby bằng đá quý Mechanize, nhưng bây giờ tôi không thể làm cho nó hoạt động trên iPhone với NSURLConnection.

Sự cố tôi gặp phải là: có vẻ như phản hồi SAML được mã hóa base64 không được NSURLConnection gửi đến máy chủ đúng cách. Các dấu + được thay thế bằng dấu cách, khiến việc giải mã phản hồi SAML ở phía máy chủ bị lỗi. Sử dụng mã hóa URL với stringByAddingPercentEscapesSử dụngKết quả mã hóa trong cùng một lỗi giải mã.

Đây là mã giải nén và gửi đáp ứng SAML:

// Extract the SAML Response from the form that is sent by the server 
body = [[NSString alloc] initWithData:[self receivedData]  encoding:NSUTF8StringEncoding]; 
NSString *searchSAMLResponseStart = @"name=\"SAMLResponse\" value=\""; 
NSString *searchSAMLResponseEnd = @">\n<NOSCRIPT><INPUT TYPE=\"SUBMIT\""; 
NSRange samlResponseStartRange = [body rangeOfString:searchSAMLResponseStart options:0]; 
NSRange samlResponseEndRange = [body rangeOfString:searchSAMLResponseEnd options:0]; 
NSRange range = NSMakeRange (NSMaxRange(samlResponseStartRange), samlResponseEndRange.location - NSMaxRange(samlResponseStartRange) -1); 
NSString* samlResponseString = [body substringWithRange:range]; 

// Construct the SAML POST request 
NSURL    *url; 
NSMutableURLRequest *request; 
url = [NSURL URLWithString:kSamlPostUrl]; 
request = [NSMutableURLRequest requestWithURL:url]; 
NSString *userAgent = kUserAgent; 
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; 
[request setHTTPMethod:@"POST"]; 
NSString *post = [@"RelayState=https://example.com&SAMLResponse=" stringByAppendingString:samlResponseString]; 
NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO]; 
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; 
[request setValue:postLength forHTTPHeaderField:@"Content-Length"]; 
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 
[request setHTTPBody:postData]; 

// Send the request   
self.connectionPostSaml = [NSURLConnection connectionWithRequest:request delegate:self]; 

Dạng SAML mà máy chủ gửi và nơi Hồi đáp SAML được lấy từ, trông như thế này:

<html> 
<HEAD><META HTTP-EQUIV='PRAGMA' CONTENT='NO-CACHE'><META HTTP-EQUIV='CACHE-CONTROL'  CONTENT='NO-CACHE'><TITLE>SAML 2.0 Auto-POST form</TITLE></HEAD> 
    <body onLoad="document.forms[0].submit()"> 
<NOSCRIPT>Your browser does not support JavaScript. Please click the 'Continue' button  below to proceed. <br><br></NOSCRIPT> 
     <form action="https://sso.example.com/saml2" method="POST"> 
     <input type="hidden" name="RelayState" value="https://example.com"> 
     <input type="hidden" name="SAMLResponse"  value="PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERl 
c3RpbmF0aW9uPSJodHRwczovL3Nzby5vcG93ZXIuY29tL3NwL0FDUy5zYW1sMiIgSUQ9Il85ZWY0 
M2MzMGRkZmQ0YzY1ODNiMjgxZjAwNDU5ZWQyMjZmMjQiIElzc3VlSW5zdGFudD0iMjAxMi0wMy0y 
OFQyMTo0MDowNloiIFZlcnNpb249IjIuMCI+CiAgICA8bnMxOklzc3VlciB4bWxuczpuczE9InVy 
bjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIEZvcm1hdD0idXJuOm9hc2lzOm5h 
bWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5wZ2UuY29tPC9uczE6SXNzdWVy 
(…) 
cnRpb24+CjwvUmVzcG9uc2U+"> 
<NOSCRIPT><INPUT TYPE="SUBMIT" VALUE="Continue"></NOSCRIPT> 
     </form> 
    </body> 
</html> 

Và lỗi mà máy chủ tạo ra sau khi nhận được yêu cầu POST:

Unable to parse incoming SAML2 message, raw:  PFJlc3BvbnNlIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIERl 
c3RpbmF0aW9uPSJodHRwczovL3Nzby5vcG93ZXIuY29tL3NwL0FDUy5zYW1sMiIgSUQ9Il9iN2Q5 
OTZhMmI1MjhiNWRkNjY0YWM4YjUwZmVjM2M2OTMzMWEiIElzc3VlSW5zdGFudD0iMjAxMi0wMy0y 
OVQyMjowMzoxNVoiIFZlcnNpb249IjIuMCI CiAgICA8bnMxOklzc3VlciB4bWxuczpuczE9InVy 
bjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iIEZvcm1hdD0idXJuOm9hc2lzOm5h 
bWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5wZ2UuY29tPC9uczE6SXNzdWVy 
PgogICAgPFN0YXR1cz4KICAgICAgICA8U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVz 
OnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIi8 CiAgICA8L1N0YXR1cz4KICAgIDxuczI6QXNz 
(…) 

Lưu ý cách t ông + dấu hiệu trong phản ứng thô được thay đổi thành không gian. Có vẻ như hành vi bình thường đối với máy chủ để giải mã phản hồi nhận được và do đó thay thế + dấu cách bằng dấu cách, tuy nhiên: tại sao nó hoạt động khi biểu mẫu SAML được đăng từ trình duyệt, chứ không phải từ NSURLConnection?

Để giải quyết tôi đã cố gắng:

  • sử dụng mã hóa khác nhau để giải mã và mã hóa Hồi đáp SAML. Bây giờ sử dụng NSUTF8StringEncoding, cũng đã cố gắng: NSASCIIStringEncoding, NSNEXTSTEPStringEncoding, NSNonLossyASCIIStringEncoding, NSUnicodeStringEncoding

  • sử dụng stringByAddingPercentEscapesUsingEncoding, vì vậy dòng mã này:

    NSString * samlResponseString = [cơ thể substringWithRange: phạm vi];

trở thành:

NSString* samlResponseString = [[body substringWithRange:range] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
  • sử dụng enctypes khác đối với hình thức, nhưng máy chủ thậm chí sẽ không chấp nhận những yêu cầu: multipart/form-data text/plain

Tôi đánh giá rất cao sự giúp đỡ của bạn. Cảm ơn bạn trước!

Trả lời

0

Tôi gặp sự cố khi gửi base64 qua bài đăng và giải quyết nó bằng mã hóa url. Hãy thử điều này:

NSString *post = [@"RelayState=https://example.com&SAMLResponse=" stringByAppendingString: 
     (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, 
     (__bridge CFStringRef)samlResponseString, NULL, (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", 
     CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))]; 
Các vấn đề liên quan