Question:
I am having a hard time figuring out how to return developer credentials provided by my server (via AWS) to my Example identity provider.
It seems I need to do this synchronously within the refresh
method on the ExampleIdentityProvider class. I’m using AFNetworking to make the request, but it is an async GET
request. How can I do this synchronously for the refresh method on my IdentityProvider?
The following is in Swift:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
class ExampleIdentityProvider: AWSAbstractIdentityProvider { var newToken: String! override var token: String { get { return newToken } set { newToken = newValue } } override func getIdentityId() -> BFTask! { if self.identityId != nil { return BFTask(result: self.identityId) }else{ return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in if self.identityId == nil { return self.refresh() } return BFTask(result: self.identityId) }) } } override func refresh() -> BFTask! { return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in let result = AFNETWORKING REQUEST FOR CREDENTIALS TO MY SERVER self.identityId = result.identityId self.token = result.token return BFTask(result: self.identityId) }) } } |
Answer:
I believe I have figured it out. I needed to utilize BFTask which is built for handling background tasks with completion.
For people struggling with a Swift implementation of developer authentication with Cognito who might have a similar setup to me, this is how I accomplished it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
class ExampleAppIdentityProvider: 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/" override var token: String { get { return _token } } override var logins: [ NSObject : AnyObject ]! { get { return _logins } set { _logins = newValue } } override func getIdentityId() -> BFTask! { if self.identityId != nil { return BFTask(result: self.identityId) }else{ return BFTask(result: nil).continueWithBlock({ (task) -> AnyObject! in if self.identityId == nil { return self.refresh() } return BFTask(result: self.identityId) }) } } override func refresh() -> BFTask! { let task = BFTaskCompletionSource() 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 initialized the ExampleAppIdentityProvider
by doing:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
let identityProvider = ExampleAppIdentityProvider() let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: GlobalVariables.cognitoUnauthRoleArn, authRoleArn: GlobalVariables.cognitoAuthRoleArn) let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider) AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration let transferManager = AWSS3TransferManager.defaultS3TransferManager() let uploadRequest = AWSS3TransferManagerUploadRequest() uploadRequest.bucket = GlobalVariables.awsBucket uploadRequest.key = "\(GlobalVariables.environment)/uploads/users/\(userId)/\(type)/\(timestamp)/original.jpg" uploadRequest.ACL = .AuthenticatedRead uploadRequest.body = tmpFileUrl // Upload file let task = transferManager.upload(uploadRequest) |
I created a struct
named GlobalVariables
with global environment variables that hold values for bucket
, unAuthRoleArn
, authRoleArn
, etc. Of course you don’t have to do that, but I’m mentioning it in case someone is confused.