Log in or register to post comments

VWS with Obj-C

October 7, 2014 - 8:44pm #1

I've seen the sample code in PHP and Java for the VWS API and I as an iPhone Developer wanted to get something similar for my own work on the client. I'm trying to make a tool that will upload images to the cloud servers written in Objective-C. I started with what I thought would be the simplist and logically the first request for such a tool, GetAllTargets. I used both the PHP and Java sample code to create this code in Obj-C however I keep getting AuthorizationFailure in my response from the API.

A few quick notes, I've changed my AccessKey and SecretKey for security here. I have 3 dependencies linked via CocaoPods, AFNetworking for the newtowrking request, SAMCategories for SHA1 MD5 and Base64 helper functions, & FormatterKit to give me a curl request. (I wonder why the docs don't have curl request?)


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    self.accessKeyTextField.stringValue = @"8a47efefffffffffffffffffffffffffffffffff";
    self.secretKeyTextField.stringValue = @"28d0eacfffffffffffffffffffffffffffffffff";
    
    [self getTargets];
}

- (void)getTargets{
    NSString *accessKey = self.accessKeyTextField.stringValue;
    NSString *secretKey = self.secretKeyTextField.stringValue;
    if(accessKey.length != 40){
        return;
    }
    if(secretKey.length != 40){
        return;
    }
    
    NSURL *URL = [NSURL URLWithString:@"https://vws.vuforia.com/targets"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    [request setHTTPBody:[@"" dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPMethod:@"GET"];
    [self buildRequest:request withAccessKey:accessKey withSecret:secretKey];
    
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                         initWithRequest:request];
    operation.responseSerializer = [AFJSONResponseSerializer serializer];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"SUCCESS: %@", responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSError *jsonError = nil;
        id jsonObject = [NSJSONSerialization JSONObjectWithData:operation.responseData options:NSJSONReadingAllowFragments error:&jsonError];
        NSLog(@"%@", jsonObject);
        //NSLog(@"operation: %@ \n ERROR: %@", operation, error.description);
    }];
    NSLog(@"%@",[TTTURLRequestFormatter cURLCommandFromURLRequest:request]);
    [operation start];
}

- (void)buildRequest:(NSMutableURLRequest *)request
       withAccessKey:(NSString *)accessKey
          withSecret:(NSString *)secret{
    
    NSString *HTTPVerb = [request HTTPMethod];
    NSString *contentMD5 = [[request HTTPBody] sam_MD5Digest];
    NSString *contentType = @"application/json";
    
    [request setValue:contentType forHTTPHeaderField:@"Content-Type"];
    
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
    [dateFormatter setLocale:usLocale];
    dateFormatter.dateFormat = @"EEE, dd MMM yyyy HH:mm:ss z";
    dateFormatter.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    NSDate *date =  [NSDate date];
    NSString *dateString = [dateFormatter stringFromDate:date];
    
    [request setValue:dateString forHTTPHeaderField:@"Date"];
    
    NSString *path = [[request URL] relativePath];
    
    NSString *stringToSign = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%@",
    HTTPVerb,
    contentMD5,
    contentType,
    dateString,
    path];
    
    NSLog(@"stringToSign: %@",stringToSign);
    NSString *sha1 = [stringToSign  sam_HMACDigestWithKey:secret algorithm:kCCHmacAlgSHA1];
    NSLog(@"sha1: %@",sha1);
    NSString *base64EncodedSignedSecret = [sha1 sam_base64EncodedString];
    NSLog(@"signedString: %@", base64EncodedSignedSecret);
    
    NSString *headerFormat = [NSString stringWithFormat:@"VWS %@:%@",accessKey,base64EncodedSignedSecret];

    [request setValue:headerFormat forHTTPHeaderField:@"Authorization"];
}

Heres the Printout:

2014-10-08 11:36:19.621 VuforiaAPIManager[21398:303] stringToSign: GET
d41d8cd98f00b204e9800998ecf8427e
application/json
Wed, 08 Oct 2014 03:36:19 GMT
/targets
2014-10-08 11:36:19.621 VuforiaAPIManager[21398:303] sha1: b5cd7dc3285300eb14cc989648b76f9e7f811307
2014-10-08 11:36:19.621 VuforiaAPIManager[21398:303] signedString: YjVjZDdkYzMyODUzMDBlYjE0Y2M5ODk2NDhiNzZmOWU3ZjgxMTMwNw==
2014-10-08 11:36:19.665 VuforiaAPIManager[21398:303] curl -X GET --compressed -H 'Date: Wed, 08 Oct 2014 03:36:19 GMT' -H 'Content-Type: application/json' -H 'Authorization: VWS 8a47efefffffffffffffffffffffffffffffffff:YjVjZDdkYzMyODUzMDBlYjE0Y2M5ODk2NDhiNzZmOWU3ZjgxMTMwNw==' "https://vws.vuforia.com/targets"
2014-10-08 11:36:24.376 VuforiaAPIManager[21398:303] {
    "result_code" = AuthenticationFailure;
    "transaction_id" = c66c7e5d1412451e9b8db6f146ba6136;
}

Any help on why I'm getting an Authentication Failure, other than the obviously incorrect AccessKey and Secret? My next step should be to look at my dependencies, but I don't want to jump into my dependecies code if the problem in in my own work. A quick check for that would be if someone could run those fake Access Keys and Secrets through their PHP or Java code to see if they get the same SHA1 and base64  strings for the authentication headers the same way.

VWS with Obj-C

October 13, 2014 - 4:40pm #2

Checking the "Common Results Codes" page, the "AuthenticationFailure" error indicates problem with signature authentication. Compare the signature string generated in the Java samples to the one in your Obj-C implementation.

https://developer.vuforia.com/resources/dev-guide/common-result-codes (Common Result Codes)

https://developer.vuforia.com/resources/dev-guide/setting-api (Signature String Format)

Log in or register to post comments