User Preferences augmenting IOS ADAL sample project


to the microsoft sample IOS project for ADAL, we added some user preferences handling so the “stay signed in” feature of the Microsoft Online web page makes sense (by NOT appearing!):


//
//  samplesWebAPIConnector.h
//  Microsoft Tasks
//
//  Created by Brandon Werner on 3/11/14.
//  Copyright (c) 2014 Microsoft. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "samplesTaskItem.h"

@interface samplesWebAPIConnector : NSObject<NSURLConnectionDataDelegate>

+(void) getTaskList:(void (^) (NSArray*, NSError* error))completionBlock;
+(void) addTask:(samplesTaskItem*)task completionBlock:(void (^) (bool, NSError* error)) completionBlock;
+(void) signOut;
+(void) readApplicationSettings;

@end




//
//  samplesWebAPIConnector.m
//  Microsoft Tasks
//
//  Created by Brandon Werner on 3/11/14.
//  Copyright (c) 2014 Microsoft. All rights reserved.
//

#import "samplesWebAPIConnector.h"
#import "ADALiOS/ADAuthenticationContext.h"
#import "samplesTaskItem.h"
#import "ADALiOS/ADAuthenticationSettings.h"

@implementation samplesWebAPIConnector

ADAuthenticationContext* authContext;

NSString* taskWebApiUrlString;
NSString* authority;
NSString* clientId;
NSString* resourceId;
NSString* redirectUriString;
NSString* userId;

bool loadedApplicationSettings;

+ (void) readApplicationSettings {
    NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"settings" ofType:@"plist"]];
    
    clientId = [dictionary objectForKey:@"clientId"];
    authority = [dictionary objectForKey:@"authority"];
    resourceId = [dictionary objectForKey:@"resourceString"];
    redirectUriString = [dictionary objectForKey:@"redirectUri"];
    userId = [dictionary objectForKey:@"userId"];
    taskWebApiUrlString = [dictionary objectForKey:@"taskWebAPI"];
    
    loadedApplicationSettings = YES;
    
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    if ([userDefaults boolForKey:@"enabled_preference"])
    {
        NSString *s = [userDefaults stringForKey:@"name_preference"];
        userId = s;
    }
}

+(NSString*) trimString: (NSString*) toTrim
{
    //The white characters set is cached by the system:
    NSCharacterSet* set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    return [toTrim stringByTrimmingCharactersInSet:set];
}

+(void) getToken : (BOOL) clearCache completionHandler:(void (^) (NSString*, NSError*))completionBlock;
{
    ADAuthenticationError *error;
    authContext = [ADAuthenticationContext authenticationContextWithAuthority:authority error:&error];
    
    NSURL *redirectUri = [[NSURL alloc]initWithString:redirectUriString];
    
    [authContext acquireTokenWithResource:resourceId clientId:clientId redirectUri:redirectUri userId:userId completionBlock:^(ADAuthenticationResult *result) {
        
        if (result.tokenCacheStoreItem == nil)
        {
            completionBlock(nil, result.error);
        }
        else
        {
            completionBlock(result.tokenCacheStoreItem.accessToken, nil);
        }
    }];
}

+(void) getTaskList:(void (^) (NSArray*, NSError*))completionBlock;
{
    if (!loadedApplicationSettings)
    {
        [self readApplicationSettings];
    }
    
    [self craftRequest:[self.class trimString:taskWebApiUrlString] completionHandler:^(NSMutableURLRequest *request, NSError *error) {
        
        if (error != nil)
        {
            completionBlock(nil, error);
        }
        else
        {
            
            NSOperationQueue *queue = [[NSOperationQueue alloc]init];
            
            [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                
                if (error == nil && data != nil){
                    
                    NSArray *tasks = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                    
                    //each object is a key value pair
                    NSDictionary *keyValuePairs;
                    NSMutableArray* sampleTaskItems = [[NSMutableArray alloc]init];
                    
                    for(int i =0; i < tasks.count; i++)
                    {
                        keyValuePairs = [tasks objectAtIndex:i];
                        
                        samplesTaskItem *s = [[samplesTaskItem alloc]init];
                        s.itemName = [keyValuePairs valueForKey:@"Title"];
                        
                        [sampleTaskItems addObject:s];
                    }
                    
                    completionBlock(sampleTaskItems, nil);
                }
                else
                {
                    completionBlock(nil, error);
                }
                
            }];
        }
    }];
    
}

+(void) addTask:(samplesTaskItem*)task completionBlock:(void (^) (bool, NSError* error)) completionBlock
{
    if (!loadedApplicationSettings)
    {
        [self readApplicationSettings];
    }
    
    [self craftRequest:taskWebApiUrlString completionHandler:^(NSMutableURLRequest* request, NSError* error){
        
        if (error != nil)
        {
            completionBlock(NO, error);
        }
        else
        {
            NSDictionary* taskInDictionaryFormat = [self convertTaskToDictionary:task];
            
            NSData* requestBody = [NSJSONSerialization dataWithJSONObject:taskInDictionaryFormat options:0 error:nil];
            
            [request setHTTPMethod:@"POST"];
            [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
            [request setHTTPBody:requestBody];
            
            NSOperationQueue *queue = [[NSOperationQueue alloc]init];
            
            [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                
                NSString* content = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"%@", content);
                
                if (error == nil){
                    
                    completionBlock(true, nil);
                }
                else
                {
                    completionBlock(false, error);
                }
            }];
        }
    }];
}

+(void) craftRequest : (NSString*)webApiUrlString completionHandler:(void (^)(NSMutableURLRequest*, NSError* error))completionBlock
{
    [self getToken:NO completionHandler:^(NSString* accessToken, NSError* error){
        
        if (accessToken == nil)
        {
            completionBlock(nil,error);
        }
        else
        {
            NSURL *webApiURL = [[NSURL alloc]initWithString:webApiUrlString];
            
            NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:webApiURL];
            
            NSString *authHeader = [NSString stringWithFormat:@"Bearer %@", accessToken];
            
            [request addValue:authHeader forHTTPHeaderField:@"Authorization"];
            
            completionBlock(request, nil);
        }
    }];
}

+(NSDictionary*) convertTaskToDictionary:(samplesTaskItem*)task
{
    NSMutableDictionary* dictionary = [[NSMutableDictionary alloc]init];
    
    if (task.itemName){
        [dictionary setValue:task.itemName forKey:@"Title"];
    }
    
    return dictionary;
}

+(void) signOut
{
    [authContext.tokenCacheStore removeAll];
    
    NSHTTPCookie *cookie;
    
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    for (cookie in [storage cookies])
    {
        [storage deleteCookie:cookie];
    }
}

@end

The main controller

//
//  samplesTaskListTableViewController.m
//  Microsoft Tasks
//
//  Created by Brandon Werner on 3/4/14.
//  Copyright (c) 2014 Microsoft. All rights reserved.
//

#import "samplesTaskListTableViewController.h"
#import "samplesTaskItem.h"
#import "sampleAddTaskItemViewController.h"
#import "samplesWebAPIConnector.h"
#import "ADALiOS/ADAuthenticationContext.h"

@interface samplesTaskListTableViewController ()

@property NSMutableArray *taskItems;
@property ADAuthenticationContext *authContext;

@end

@implementation samplesTaskListTableViewController


-(void)loadData {
    
    // Load data from the webservice
    [samplesWebAPIConnector getTaskList:^(NSArray *tasks, NSError* error) {
       
        self.webView.delegate = self;
        if (error != nil)
        {
            dispatch_async(dispatch_get_main_queue(),^ {
                
                [samplesWebAPIConnector signOut];
                [self loadData];

            });
        }
        else
        {
            self.taskItems = (NSMutableArray*)tasks;
            
            // Refresh main thread since we are async
            dispatch_async(dispatch_get_main_queue(), ^{
                NSString *fullURL = @"https://ssoportal.rapmlsqa.com/SPInitiatedSSOHandler.aspx/BARS/6?wa=wsignin1.0&wtrealm=http://tablet.com/&wreply=http%3A%2F%2Fm.rapmlsqa.com%2FSPHandler.aspx%3FMls%3DBARS";
                NSURL *url = [NSURL URLWithString:fullURL];
                NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:url];
                
                NSArray *cookiesForDomain = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:@"https://ssoportal.rapmlsqa.com/"]];
                
                NSMutableString *cookieStringToSet      = [[NSMutableString alloc] init];
                for (NSHTTPCookie *cookie in cookiesForDomain) {
                    [cookieStringToSet appendFormat:@"%@=%@;", cookie.name, cookie.value];
                }
                
                if (cookieStringToSet.length) {
                    [requestObj setValue:cookieStringToSet forHTTPHeaderField:@"Cookie"];
                }
                [_webView loadRequest:requestObj];

            });
        }
    }];
}

- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {

        NSString *requestURL = [[request.URL absoluteString] lowercaseString];
    
        // Stop at the end URL.
        if ( [requestURL hasPrefix:@"https://ssoportal.rapmlsqa.com/ssologon"] )
        {
            [samplesWebAPIConnector signOut];
            [self loadData];
            return NO;
        }
        return YES;
}

- (IBAction)pressedLogout:(id)sender {
    
    [samplesWebAPIConnector signOut];
    [self.taskItems removeAllObjects];
    
    // Refresh main thread since we are async
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tableView reloadData];
    });
    
    [self loadData];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
 //   [samplesWebAPIConnector signOut];
    self.refreshControl = [[UIRefreshControl alloc] init];
    
    [self.refreshControl addTarget:self action:@selector(refreshInvoked:forState:) forControlEvents:UIControlEventValueChanged];
    
    [self setRefreshControl:self.refreshControl];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(defaultsChanged:) name:NSUserDefaultsDidChangeNotification
                                               object:nil];

    
    self.taskItems = [[NSMutableArray alloc] init];
    [self loadData];
    
}

- (void)defaultsChanged:(NSNotification *)notification {
    [samplesWebAPIConnector signOut];
    [samplesWebAPIConnector readApplicationSettings];
}

-(void) refreshInvoked:(id)sender forState:(UIControlState)state {
    // Refresh table here...
    [self.taskItems removeAllObjects];
    [self.tableView reloadData];
    [self loadData];
    [self.refreshControl endRefreshing];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Return the number of rows in the section.
    return [self.taskItems count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TaskPrototypeCell" forIndexPath:indexPath];
    
    samplesTaskItem *taskItem = [self.taskItems objectAtIndex:indexPath.row];
    cell.textLabel.text = taskItem.itemName;
    
    if (taskItem.completed) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    
    return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    samplesTaskItem *tappedItem = [self.taskItems objectAtIndex:indexPath.row];
    tappedItem.completed = !tappedItem.completed;
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if (buttonIndex == 0)
    {
        [alertView dismissWithClickedButtonIndex:0 animated:NO];
        [samplesWebAPIConnector signOut];
        [self loadData];
    }
}

@end

Advertisements

About home_pw@msn.com

Computer Programmer who often does network administration with focus on security servers. Very strong in Microsoft Azure cloud!
This entry was posted in AAD. Bookmark the permalink.