0

I have initialized the credentials provider per this AWS Developer Guide. I'm not sure if it worked, and how to check. I can't seem to find any documentation on how to use Cognito with Swift. I'm running it as a unit test, and the test passes and the line print("identityId", identityId) outputs:

identityId <AWSTask: 0x17d5fde0; completed = NO; cancelled = NO; faulted = NO;>

However, during debug the property identityProvider.identityId is nil.

Here are my files:

// MyAuth.swift

import Foundation
import AWSCognito

class MyAuth {

    func getUnauthCognitoId()->Bool {
        let identityProvider = MyIdentityProvider()
        let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: Constants.ARNUnauth.value, authRoleArn: Constants.ARNAuth.value)
        let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
        AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration

        if let identityId = identityProvider.getIdentityId() {
            print("identityId", identityId)
            return true
        } else {
            return false
        }

    }

}

And

//  MyIdentityProvider.swift

import Foundation
import AWSCognito

class MyIdentityProvider: AWSAbstractCognitoIdentityProvider {
    var _token: String!
    var _logins: [ NSObject : AnyObject ]!

    // Header stuff you may not need but I use for auth with my server
    /*let acceptHeader = "application/vnd.exampleapp-api+json;version=1;"
    let authHeader = "Token token="
    let userDefaults = NSUserDefaults.standardUserDefaults()
    let authToken = self.userDefaults.valueForKey("authentication_token") as String*/

    // End point that my server gives amazon identityId and tokens to authorized users
    let url = "https://api.myapp.com/api/amazon_id/"

    func authenticatedWithProvider()->Bool {
        if let logins = _logins {
            return logins["ProviderName"] == nil
        }
        else {
            return false
        }
    }

    override var token: String {
        get {
            return _token
        }
    }

    override var logins: [ NSObject : AnyObject ]! {
        get {
            return _logins
        }
        set {
            _logins = newValue
        }
    }

    override func getIdentityId() -> AWSTask! {
        if self.identityId != nil {
            return AWSTask(result: self.identityId)
        }
        else if(!self.authenticatedWithProvider()) {
            return super.getIdentityId()
        }
        else{
            return AWSTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
                if self.identityId == nil {
                    return self.refresh()
                }
                return AWSTask(result: self.identityId)
            })
        }
    }

    override func refresh() -> AWSTask! {
        let task = AWSTaskCompletionSource()
        if(!self.authenticatedWithProvider()) {
            return super.getIdentityId()
        }
        else {
            // TODO: Authenticate with developer
            return task.task
        }
        /*let request = AFHTTPRequestOperationManager()
        request.requestSerializer.setValue(self.acceptHeader, forHTTPHeaderField: "ACCEPT")
        request.requestSerializer.setValue(self.authHeader+authToken, forHTTPHeaderField: "AUTHORIZATION")
        request.GET(self.url, parameters: nil, success: { (request: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
            // The following 3 lines are required as referenced here: http://stackoverflow.com/a/26741208/535363
            var tmp = NSMutableDictionary()
            tmp.setObject("temp", forKey: "ExampleApp")
            self.logins = tmp

            // Get the properties from my server response
            let properties: NSDictionary = response.objectForKey("properties") as NSDictionary
            let amazonId = properties.objectForKey("amazon_identity") as String
            let amazonToken = properties.objectForKey("token") as String

            // Set the identityId and token for the ExampleAppIdentityProvider
            self.identityId = amazonId
            self._token = amazonToken

            task.setResult(response)
            }, failure: { (request: AFHTTPRequestOperation!, error: NSError!) -> Void in
                task.setError(error)
        })*/
        return task.task
    }
}

And

import XCTest
@testable import My

class MyTests: XCTestCase {

    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }

    func testExample() {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measureBlock {
            // Put the code you want to measure the time of here.
        }
    }

    func testGetUnauthCognitoId() {
        let myAuth = MyAuth()
        XCTAssertTrue(myAuth.getUnauthCognitoId())
    }

}
JBaczuk
  • 13,886
  • 10
  • 58
  • 86
  • Looks like the identityid is nil to me. There are some interesting sample for getting the credential provider working in iOS over at this [page](https://github.com/aws/aws-sdk-ios/blob/master/AWSCoreTests/AWSCognitoIdentityServiceTests.m). They also have some interesting prebuilt test cases. I took a brief look and the page provided seemed relevant to your issue. BTW - If you only want to download a single folder from the repo check out this SO [Q&A](http://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repo/32545187#32545187) – Tommie C. Nov 05 '15 at 15:36
  • Edit: I've edited the code that I've changed, specifically I implemented an AWSAbstractCognitoIdentityProvider and am not sure if its retrieving an identity successfully or not. – JBaczuk Nov 06 '15 at 04:33
  • BTW - Are you running this on the device? – Tommie C. Nov 06 '15 at 05:06
  • @Tommie C. Yes, as a unit test – JBaczuk Nov 06 '15 at 13:19

2 Answers2

1

It turns out that if you create a default service configuration within the application:didFinishLaunchingWithOptions: application delegate method in your app delegate file as described here:

let credentialsProvider = AWSCognitoCredentialsProvider(
        regionType: AWSRegionType.USEast1, identityPoolId: cognitoIdentityPoolId)

let defaultServiceConfiguration = AWSServiceConfiguration(
        region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)

AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration

The SDK will use an unauthenticated identity whenever you try to use any of the AWS services, and you don't necessarily need to create a cognitoIdentity object.

JBaczuk
  • 13,886
  • 10
  • 58
  • 86
0

getIdentityId returns an AWSTask. Since AWSTask is essentially BFTask with a different name, you can get the identityId using the continueWithBlock syntax shown on the BFTask page. Something like:

credentialProvider.getIdentityId().continueWithBlock {
    (task: AWSTask!) -> AWSTask in
    if task.error() {
        // failed to retrieve identityId.
    } else {
        print("identityId", task.result())
    }
Scott Willeke
  • 8,884
  • 1
  • 40
  • 52
  • This makes sense, but can it be unit tested (since it's asynchronous code), and if so, how? – JBaczuk Nov 06 '15 at 14:56
  • I think I figured out how using this article: http://blog.dadabeatnik.com/2014/07/13/asynchronous-unit-testing-in-xcode-6/ – JBaczuk Nov 06 '15 at 15:12
  • Yes usually the unit testing framework will have a way to handle asynchronous code. This is particularly true in iOS since all network calls are supposed to be fine asynchronously. I've used kiwi and they have some docs on this at https://github.com/kiwi-bdd/Kiwi/wiki/Asynchronous-Testing – Scott Willeke Nov 07 '15 at 04:16
  • I didn't see an error in the original question. The output you saw in the debugger was the reference to an AWSTask instance. So if you have updated the code as described above you most certainly won't see that. Can you please provide the updated code that you are using and give the verbatim error message that you see. – Scott Willeke Nov 10 '15 at 18:20
  • I will post an update, my code has been all over the place recently, but I was finding that the identity was nil – JBaczuk Nov 10 '15 at 18:24