我们正在为Titanium编写一个可以进行SAML身份验证的本机iOS模块。我将SSO url传递给模块,它向url发起HTTP请求,url发送HTTP 302重定向2次并转到IDP,在那里它应该进行身份验证并返回SAML令牌。
这是我从我的Titanium app javascript代码调用的SAML模块中的函数:
var saml = require('com.xxx.SAML');
Ti.API.info("module is => " + saml);
saml.ssoUrl ="https://xxxx";
saml.startSSO();
模块已正确安装并被调用。以下是函数startSSO:
-(id)startSSO:(id)args {
self.samlUtility = [[SAMLUtility alloc] init];
[self.samlUtility setSsoUrl:self.ssoUrl];
[self.samlUtility performSAMLAuth];
NSLog(@"setSsoUrl "); }
SAML Utility类如下:
@implementation SAMLUtility
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler{
NSLog(@"did receive auth challenge");
if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust){
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}else if(challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM || challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNegotiate){
NSURLCredential *credential = [NSURLCredential credentialWithUser:@"xxxx" password:@"xxxx" persistence:NSURLCredentialPersistenceNone];
completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}else {
// Cancel request
NSURLCredential *credential = [[NSURLCredential alloc] init];
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, credential);
}
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest * __nullable))completionHandler{
NSLog(@"in redirection");
NSURLRequest *newRequest = request;
completionHandler(newRequest);
}
-(void)httpRequest:(NSMutableURLRequest*)request callback:(void(^)(NSData *data, NSString *str))callback{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//Manage the time out configuration
configuration.timeoutIntervalForRequest=120;
configuration.timeoutIntervalForResource=120;
//Now initiate the reuqest
self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSData *data = [[NSData alloc] init];
if((request) != nil) {
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if(response){
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
NSLog(@"---- Response Code : %ld",(long)httpResponse.statusCode);
NSLog(@"---- Header fields Code : %@", httpResponse.allHeaderFields);
if(error){
callback(data, error.localizedDescription);
} else {
callback(data, nil);
}
}
else{
NSLog(@"---- Response is not NSHTTPURLResponse it is %@ -data: %@ - error: %@",response, data, error);
}
}];
[task resume];
}
callback(data, nil);
}
-(void)performSAMLAuth{
NSString *escapedspEndPoint = [self.ssoUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"Calling iDP endpoint added encoded %@",escapedspEndPoint);
//call SP login end point
NSURL *urlObject = [NSURL URLWithString:escapedspEndPoint];
NSMutableURLRequest *spLoginReq = [NSMutableURLRequest requestWithURL:urlObject];
//Create a session and connect to the specfied url.
NSLog(@"Going to request now...");
//TODO: This will result in 302 and go to IdP location do authentication with kerberos
//other other options and come back...
[self httpRequest:spLoginReq callback:^(NSData *data, NSString *error){
if(error) {
NSLog(@"Error: %@",error);
NSLog(@"Task execution completed with failure");
} else {
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Success: %@", s);
//Parse the IdP response and send back to
//SP SSO End point
NSMutableURLRequest *spSsoReq = [self buildSsoRequestFrom:data];
[self httpRequest:spSsoReq callback:^(NSData *data, NSString *error){
if(error) {
NSLog(@"Error: %@",error);
NSLog(@"Task execution completed with failure");
} else {
NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Success: %@", s);
NSLog(@"spSsoReq completed");
NSLog(@"------------------------");
}
NSLog(@"Task execution completed");
NSMutableURLRequest *spSsoReq1 = [self buildSsoRequestFrom:data];
if([spSsoReq1.URL.absoluteString isEqualToString:@"https://xxxxx/saml2/sp/acs"]){
[[NSNotificationCenter defaultCenter] postNotificationName:@"SSOCompleted" object: nil];
}
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
if(cookies.count > 0){
for(NSHTTPCookie *cookie in cookies){
NSLog(@"cookie : %@", cookie.name);
}
}
}];
}
}];
}
-(NSMutableURLRequest*)buildSsoRequestFrom:(NSData*)samlHtmlResponse{
TFHpple *doc = [[TFHpple alloc] initWithHTMLData:samlHtmlResponse];
if(doc == nil || (doc.data) == nil) {
NSLog(@"Bad SAML expected response: %@", doc);
return nil;
}
NSArray *elements = [doc searchWithXPathQuery:@"//form"];
if (elements != nil && elements.count > 0) {
for(TFHppleElement *element in elements){
//This is form
TFHppleElement *formElement = (TFHppleElement*)element;
NSString *spSsoUrlString = [formElement objectForKey:@"action"];
NSLog(@"--- Now sending back to SP SSO End point : %@", spSsoUrlString);
//Now iterate through all the child elements of type input
NSURL *spSsoUrl = [NSURL URLWithString:spSsoUrlString];
NSMutableURLRequest *spSsoRequest = [NSMutableURLRequest requestWithURL:spSsoUrl];
//set method to HTTP POST
spSsoRequest.HTTPMethod = @"POST";
//set content type for url encoded
//spSsoRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
//iterate through all the input parameters
//and extract key = name & value = value of the input
NSArray *inputElements = [formElement childrenWithTagName:@"input"];
NSMutableString *postBody = [[NSMutableString alloc] init];
for(TFHppleElement *ie in inputElements) {
TFHppleElement *tfie = (TFHppleElement*)ie;
NSString *key = [tfie objectForKey:@"name"];
NSString *value= [tfie objectForKey:@"value"];
value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@"%2B" options:NSLiteralSearch range:NSMakeRange(0, value.length)];
[postBody stringByAppendingFormat:@"%@=%@",key,value];
}
NSLog(@"3. POST Body : %@", postBody);
NSData *postBodyData = [postBody dataUsingEncoding:NSUTF8StringEncoding];
spSsoRequest.HTTPBody = postBodyData;
return spSsoRequest;
}
}
return nil;
}
当我运行应用程序时,我看到日志停在下面,应用程序崩溃提到分段错误:
[INFO] : [object ComXXXSamlModule] loaded
[INFO] : module is => [object ComXXXSamlModule]
[INFO] : 2016-07-06 18:01:57.837 myxxx[16912:209092] Calling iDP endpoint added encoded https://xxx
[INFO] : 2016-07-06 18:01:57.838 myxxx[16912:209092] Going to request now...
[INFO] : 2016-07-06 18:01:57.840 myxxx[16912:209092] Success:
[INFO] : 2016-07-06 18:01:57.882 myxxx[16912:209092] Document length: 0 (902 in Kerberos-POC)
[INFO] : 2016-07-06 18:01:57.882 myxxx[16912:209092] Unable to parse:
[INFO] : 2016-07-06 18:01:57.882 myxxx[16912:209092] Success:
[INFO] : 2016-07-06 18:01:57.883 myxxx[16912:209092] spSsoReq completed
[INFO] : 2016-07-06 18:01:57.883 myxxx[16912:209092] ------------------------
[INFO] : 2016-07-06 18:01:57.883 myxxx[16912:209092] Task execution completed
[INFO] : 2016-07-06 18:01:57.883 myxxx[16912:209092] Document length: 0 (5728 in Kerberos-POC)
[INFO] : 2016-07-06 18:01:57.883 myxxx[16912:209092] Unable to parse:
但是,如果我将相同的代码放入我的原生iOS应用程序并调用与startSSO相同的代码,则代码将执行超出这些日志(我在日志中看到SAML令牌和更多内容)并完成SAML身份验证。
崩溃日志:
Crashed Thread: 5 KrollContext<kroll$1>
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000018
Exception Note: EXC_CORPSE_NOTIFY
VM Regions Near 0x18:
-->
__TEXT 0000000104e67000-0000000105198000 [ 3268K] r-x/rwx SM=COW /Users/USER/Library/Developer/CoreSimulator/Devices/FBA2AFBE-14CE-4439-B28A-1AC45FE45639/data/Containers/Bundle/Application/74AA8443-77DE-42FF-BA3F-CE6216FB08D5/myxxx.app/myxxx
Application Specific Information:
objc_msgSend() selector name: isKindOfClass:
CoreSimulator 209.19 - Device: iPad Air - Runtime: iOS 9.3 (13E230) - DeviceType: iPad Air
...
Thread 5 Crashed:: KrollContext<kroll$1>
0 libobjc.A.dylib 0x000000010aadb80b objc_msgSend + 11
1 com.xxx.myxxx 0x0000000104e910c7 ConvertIdTiValue + 55 (KrollObject.m:95)
2 com.xxx.myxxx 0x0000000104e92c95 +[KrollObject toValue:value:] + 37 (KrollObject.m:538)
3 com.xxx.myxxx 0x0000000104e8ccfc KrollCallAsFunction + 684 (KrollMethod.m:66)
4 com.apple.JavaScriptCore 0x0000000105a90bba JSC::JSCallbackObject<JSC::JSDestructibleObject>::call(JSC::ExecState*) + 506
5 com.apple.JavaScriptCore 0x0000000105b71340 JSC::LLInt::setUpCall(JSC::ExecState*, JSC::Instruction*, JSC::CodeSpecializationKind, JSC::JSValue, JSC::LLIntCallLinkInfo*) + 528
6 com.apple.JavaScriptCore 0x0000000105b7835d llint_entry + 22900
7 com.apple.JavaScriptCore 0x0000000105b78368 llint_entry + 22911
8 com.apple.JavaScriptCore 0x0000000105b78468 llint_entry + 23167
9 ??? 0x0000061b4034dafa 0 + 6714111089402
10 com.apple.JavaScriptCore 0x0000000105b727d9 vmEntryToJavaScript + 326
11 com.apple.JavaScriptCore 0x0000000105a44959 JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 169
12 com.apple.JavaScriptCore 0x0000000105a2b264 JSC::Interpreter::execute(JSC::ProgramExecutable*, JSC::ExecState*, JSC::JSObject*) + 10404
13 com.apple.JavaScriptCore 0x000000010583b786 JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&) + 470
14 com.apple.JavaScriptCore 0x0000000105a89fb8 JSEvaluateScript + 424
15 com.xxx.myxxx 0x0000000104e819f1 -[KrollBridge evalFileOnThread:context:] + 1281 (KrollBridge.m:460)
16 com.xxx.myxxx 0x0000000104e8625c -[KrollInvocation invoke:] + 124 (KrollContext.m:108)
17 com.xxx.myxxx 0x0000000104e881d2 -[KrollContext invokeOnThread:method:withObject:callback:selector:] + 194 (KrollContext.m:1147)
18 com.xxx.myxxx 0x0000000104e81b63 -[KrollBridge evalFile:callback:selector:] + 115 (KrollBridge.m:480)
19 com.xxx.myxxx 0x0000000104e82952 -[KrollBridge didStartNewContext:] + 2498 (KrollBridge.m:614)
20 com.xxx.myxxx 0x0000000104e88de8 -[KrollContext main] + 2392 (KrollContext.m:1349)
21 com.apple.Foundation 0x0000000106f1e12b __NSThread__start__ + 1198
22 libsystem_pthread.dylib 0x000000010b9fe99d _pthread_body + 131
23 libsystem_pthread.dylib 0x000000010b9fe91a _pthread_start + 168
24 libsystem_pthread.dylib 0x000000010b9fc351 thread_start + 13
任何帮助都会受到赞赏,因为基于此我无法理解崩溃的原因。