2012-03-29 13 views
5

Sto creando un'app per iPhone che consente agli utenti di interagire con un server protetto. Tuttavia, per autenticare l'utente, l'app deve passare attraverso SAML dal server in cui l'utente accede al server su cui si trovano i dati (fornendo SSO). Quindi l'app sta simulando l'invio di richieste HTTP SAML (dove normalmente il browser si prenderà cura di).Come inviare un messaggio di risposta SAML utilizzando NSURLConnection?

Il processo sta funzionando con Ruby utilizzando la gemma Mechanize, ma ora non riesco a farlo funzionare su iPhone con NSURLConnection.

Il problema che si verifica è: sembra che la risposta SAML codificata in base 64 non venga inviata correttamente da NSURLConnection al server. I segni + sono sostituiti da spazi, causando il fallimento della decodifica della risposta SAML sul lato server. L'utilizzo della codifica dell'URL con stringByAddingPercentEscapesUsingEncoding genera lo stesso errore di decodifica.

Questo è il codice estrazione e l'invio della risposta 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]; 

La forma SAML che il server invia e dove la risposta SAML è preso da, assomiglia a questo:

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

E l'errore che il server produce dopo aver ricevuto la richiesta POST:

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

Avviso come t lui + segni nella risposta grezza sono cambiati in spazi.

Sembra normale che il server decodifichi la risposta ricevuta e quindi sostituisca + segni con spazi, tuttavia: perché funziona quando il modulo SAML viene pubblicato dal browser, ma non da NSURLConnection?

Per risolvere ho provato:

  • utilizzando diverse codifiche di decodificare e codificare risposta SAML. Ora utilizzando NSUTF8StringEncoding, provato anche: NSASCIIStringEncoding, NSNEXTSTEPStringEncoding, NSNonLossyASCIIStringEncoding, NSUnicodeStringEncoding

  • utilizzando stringByAddingPercentEscapesUsingEncoding, quindi questa riga di codice:

    NSString * samlResponseString = [corpo substringWithRange: intervallo];

diventa:

NSString* samlResponseString = [[body substringWithRange:range] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
  • utilizzando altri enctypes per la forma, ma il server non sarà nemmeno accettare tali richieste: multipart/form-data text/plain

Apprezzo molto il tuo aiuto. Grazie in anticipo!

risposta

0

Ho avuto un problema nell'invio di base64 tramite post e risolto tramite la codifica dell'URL. Prova questo:

NSString *post = [@"RelayState=https://example.com&SAMLResponse=" stringByAppendingString: 
     (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, 
     (__bridge CFStringRef)samlResponseString, NULL, (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ", 
     CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))]; 
Problemi correlati