2012-03-29 13 views
5

Estoy creando una aplicación para iPhone que permite a los usuarios interactuar con un servidor seguro. Sin embargo, para autenticar al usuario, la aplicación debe pasar por SAML desde el servidor en el que el usuario inicia sesión en el servidor donde están los datos (proporcionando SSO). Por lo tanto, la aplicación imita el envío de solicitudes HTTP de SAML (donde normalmente se ocuparía el navegador).Cómo publicar mensaje de respuesta SAML usando NSURLConnection?

El proceso está trabajando con Ruby usando la gema Mechanize, pero ahora no puedo hacer que funcione en el iPhone con NSURLConnection.

El problema que encuentro es: parece que la respuesta SAML codificada en base64 no se envía correctamente por NSURLConnection al servidor. Los signos + se reemplazan por espacios, lo que hace que la decodificación de SAML Response en el servidor falle. El uso de codificación URL con stringByAddingPercentEscapesUsingEncoding da como resultado el mismo error de decodificación.

Este es el código de la extracción y el envío de la respuesta 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 de SAML que el servidor envía y donde la respuesta SAML se toma de, tiene el siguiente aspecto:

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

Y el error que produce el servidor después de recibir la solicitud POST:

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

Observe cómo t he + signos en la respuesta cruda se cambian en espacios.

Parece que el servidor decodifica la respuesta recibida y, por lo tanto, reemplaza + signos con espacios: ¿por qué funciona cuando el formulario SAML se publica desde el navegador, pero no desde NSURLConnection?

Para resolver Traté:

  • utilizando diferentes codificaciones para decodificar y codificar la respuesta SAML. Ahora, utilizando NSUTF8StringEncoding, también intentado: NSASCIIStringEncoding, NSNEXTSTEPStringEncoding, NSNonLossyASCIIStringEncoding, NSUnicodeStringEncoding

  • usando stringByAddingPercentEscapesUsingEncoding, por lo que esta línea de código:

    NSString * samlResponseString = [cuerpo substringWithRange: rango];

se convierte en:

NSString* samlResponseString = [[body substringWithRange:range] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 
  • utilizando otros enctypes para el formulario, pero el servidor no aceptará incluso aquellas solicitudes: multipart/form-data text/plain

Agradezco mucho su ayuda. ¡Gracias de antemano!

Respuesta

0

Tuve un problema al enviar base64 por correo postal y lo resolví por codificación de URL. Pruebe esto:

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