Latest from Pandera Systems

Leaders in Enterprise Decision Automation®.

Categories

Customizing Mobile Authentication with the MicroStrategy iOS SDK

As companies increasingly use MicroStrategy Mobile, they may need the ability to customize authentication on the app. The MicroStrategy Mobile SDK has several methods open for this, but very few samples to explain how to use them. We will show how you can intercept the user’s credentials and change them on the client side before passing them to the mobile server. Specifically, we will be passing the user-entered credentials to a third-party to retrieve a SAML token, which we then pass to a custom MicroStrategy task to validate. Once validated, this task returns the MicroStrategy credentials back to the application, which will take over with out-of-the-box functionality.

Once a custom MicroStrategy Mobile project has been set up in XCode, you will need to make a custom Application Delegate as described in the MicroStrategy Developer Zone. The below shows what the header and implementation files will look like for this.


//
//  SampleAppDelegate.h
//  MicroStrategyMobile
//
//  Created by Pandera Systems on 2/3/17.
//  Copyright © 2017 MicroStrategy Inc. All rights reserved.
//
#import 
#import 
@interface SampleAppDelegate : MSIAppDelegateImpl
@end

//
//  SampleAppDelegate.m
//  MicroStrategyMobile
//
//  Created by Pandera Systems on 2/3/17.
//  Copyright © 2017 MicroStrategy Inc. All rights reserved.
//
#import "SampleAppDelegate.h"
#import "SampleLoginPromptViewController.h"
#import 
#import 
#import 
@implementation DomtarAppDelegate
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
    MSICustomizableAuthenticationPromptView *loginView = [[MSICustomizableAuthenticationPromptView alloc] init];
    SampleLoginPromptViewController *loginViewController = [[SampleLoginPromptViewController alloc] init];
    MSIAuthenticationModule *loginModule = [[MSIAuthenticationModule alloc] init];
    [[MSIMobileLoginManager sharedMobileLoginManager] setView:loginView controller:loginViewController module:loginModule forPromptType:AuthenticationPromptType];   
    BOOL res = [super application:application didFinishLaunchingWithOptions:launchOptions];   
    return res;
}
@end

 

Next, we will create the SampleLoginPromptViewController. This view takes over after the user hits a button on the login screen of the application. Here, we take the parameters the user entered, and send them to a third-party service. A SAML token is sent as a response, which is sent to a custom task that was created on the mobile server. This task validates the SAML token and searches for the corresponding user, grabbing their credentials. It then sends the credentials back to the application. The application replaces the original parameters with the new credentials it received from the task, and allows the mobile application to continue using out-of-the-box functionality.


//
//  SampleLoginPromptViewController.h
//  MicroStrategyMobile
//
//  Created by Pandera Systems on 2/3/17.
//  Copyright © 2017 MicroStrategy Inc. All rights reserved.
//
#import 
#import 
@interface SampleLoginPromptViewController : MSIAuthenticationPromptViewController
{
    NSMutableData *_responseData;
}
@end


//
//  SampleLoginPromptViewController.m
//  MicroStrategyMobile
//
//  Created by Pandera Systems on 2/3/17.
//  Copyright © 2017 MicroStrategy Inc. All rights reserved.
//
#import "SampleLoginPromptViewController.h"
#import 
#import 
#import 
#import "MicroStrategyMobileSDK/MSIProjectInfo.h"
@interface SampleLoginPromptViewController()
@end

@implementation SampleLoginPromptViewController

// Hook to add custom logic when the view notifies the view controller that the user provided the credentials
-(void) loginPromptView:(MSIMobileLoginPromptView *)promptView didInputAuthenticationParameters:(NSDictionary *)parameters{
    
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"samplePList" ofType:@"plist"];
    NSDictionary *plistData = [NSDictionary dictionaryWithContentsOfFile:filePath];
    
    NSString *username = parameters[@"username"];
    NSString *password = parameters[@"password"];
    
    NSString *post = [NSString stringWithFormat: @"username=%@&password=%@", username, password];
    
    NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
    NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];
    
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:[plistData objectForKey:@"sampleIdp"]]];
    [request setHTTPMethod:@"POST"];
    [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
    [request setValue: @"application/x-www-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postData];
    
    //create URL connection and make request
    NSURLResponse *response = nil;
    NSError *error = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
    //the request is complete and the data has been received
    //can parse the responseData variable now
    NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
    
    NSArray* value = [string componentsSeparatedByString: @"value=\""];
    NSString* SAMLResponse = [[[value objectAtIndex:1] componentsSeparatedByString: @"\""] objectAtIndex: 0];
    
    NSString *encoded = [SAMLResponse stringByReplacingOccurrencesOfString:@"+" withString:(NSString *)@"%2B"];
    encoded = [encoded stringByReplacingOccurrencesOfString:@"=" withString: @"%3D"];
    
    //Send SAML Response to MSTR to validate and get username/password
    NSString *post2Mstr = [NSString stringWithFormat: @"userid=%@&password=%@&SAMLResponse=%@", username, password, encoded];
    NSData *postData2Mstr = [post2Mstr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
    NSString *postLength2Mstr = [NSString stringWithFormat:@"%lu", (unsigned long)[postData2Mstr length]];
    
    NSMutableURLRequest *request2Mstr = [[NSMutableURLRequest alloc] init];
    [request2Mstr setURL:[NSURL URLWithString:[plistData objectForKey:@"samlValidationTask"]]];
    [request2Mstr setHTTPMethod:@"POST"];
    [request2Mstr setValue:postLength2Mstr forHTTPHeaderField:@"Content-Length"];
    [request2Mstr setValue: @"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    [request setValue:username forHTTPHeaderField:@"userid"];
    [request setValue:password forHTTPHeaderField:@"password"];
    [request setValue:encoded forHTTPHeaderField:@"SAMLResponse"];
    [request2Mstr setHTTPBody:postData2Mstr];
    
    //create URL connection and make request
    NSURLResponse *response2Mstr = nil;
    NSError *error2Mstr = nil;
    NSData *data2Mstr = [NSURLConnection sendSynchronousRequest:request2Mstr returningResponse:&response2Mstr error:&error2Mstr];
    
    //the request is complete and the data has been received
    //can parse the responseData variable now
    NSString *mstrResponse = [[NSString alloc] initWithData:data2Mstr encoding:NSASCIIStringEncoding];
    
    NSArray* mstrUser = [mstrResponse componentsSeparatedByString: @"\"username\":\""];
    username = [[[mstrUser objectAtIndex:1] componentsSeparatedByString: @"\""] objectAtIndex: 0];
    NSArray* mstrPass = [mstrResponse componentsSeparatedByString: @"\"password\":\""];
    password = [[[mstrPass objectAtIndex:1] componentsSeparatedByString: @"\""] objectAtIndex: 0];
        
    [parameters setValue:username forKey:@"username"];
    [parameters setValue:password forKey:@"password"];
    
    [super loginPromptView:promptView didInputAuthenticationParameters:parameters];
}
@end

 

After exiting the above view, the application will go on to authenticate using the new parameters that were given.

  

The following two tabs change content below.
Rebecca has worked with and specialized in the MicroStrategy SDK for over 5 years.

Comments