aws-amplify / aws-sdk-ios

AWS SDK for iOS. For more information, see our web site:
https://aws-amplify.github.io/docs
Other
1.68k stars 879 forks source link

Issue with Getting AWS Credentials using Cognito Identity in iOS App using OpenID Token #5376

Closed kinglau66 closed 3 months ago

kinglau66 commented 3 months ago

State your question:

I am having trouble with the following code for getting AWS credentials using Cognito Identity. The completion handler is not being called successfully, and I am unsure if the AWS configuration is being set up correctly. The identityId and openToken are obtained from getOpenIdTokenForDeveloperIdentity from the backend, and cognito-identity.amazonaws.com is used as the login provider. Could someone help me identify the issue?

Which AWS Services are you utilizing?

Provide code snippets (if applicable):

let identityId = userManager.sharedUserInstance().getUserInfoFromLocal().identityId
let openToken = userManager.sharedUserInstance().getUserInfoFromLocal().openToken
if(identityId.isEmpty || openToken.isEmpty){
    completion(false, nil)
    return
}

let identityProvider = AWSCognitoIdentity.default()
let request = AWSCognitoIdentityGetCredentialsForIdentityInput()
request?.identityId = identityId
request?.logins = ["cognito-identity.amazonaws.com": openToken]
identityProvider.getCredentialsForIdentity(request!).continueWith { task in
    if let error = task.error {
        print("Error getting credentials: \(error.localizedDescription)")
        completion(false, error)
        return
    }
    guard let result = task.result, let credentials = result.credentials else {
        print("No credentials received")
        completion(false, nil)
        return
    }

    let accessKeyStr = credentials.accessKeyId ?? ""
    let secretKeyStr = credentials.secretKey ?? ""
    let sessionTokenStr = credentials.sessionToken ?? ""

    if accessKeyStr.isEmpty || secretKeyStr.isEmpty || sessionTokenStr.isEmpty {
        print("Credentials are incomplete")
        completion(false, nil)
        return
    }

    self.credentialsExpiryTime = credentials.expiration
    let credentialsProvider = AWSBasicSessionCredentialsProvider(accessKey: accessKeyStr, secretKey: secretKeyStr, sessionToken: sessionTokenStr)
    let configuration = AWSServiceConfiguration(
        region: .APSoutheast1,
        credentialsProvider: credentialsProvider
    )

    AWSSNS.register(with: configuration!, forKey: "AwsNotiLocalKey")
    AWSServiceManager.default().defaultServiceConfiguration = configuration

    print("AWS configuration initialized successfully")
    completion(true, nil)

    return nil
}

Environment (please complete the following information):

Device Information (please complete the following information):

harsh62 commented 3 months ago

@kinglau66 Is it a possibility that you can try using Amplfiy and AWS SDK for Swift using SPM?

kinglau66 commented 3 months ago

This is possible as we are mostly using java-sdk for android related task. If fully using amplify, how to Integrate AWSSNS with OpenIdToken from the backend's GetOpenIdTokenForDeveloperIdentity.. i mean by using aws-amplify/aws-sdk-ios

kinglau66 commented 3 months ago

Updated using a more amplify/aws-sdk-ios approach. Could you advise on the following issue?

I am encountering the error: Error: Error Domain=com.amazonaws.service.cognitoidentity.AWSCognitoCredentialsProviderHelper Code=0 "identityId shouldn't be nil" UserInfo={NSLocalizedDescription=identityId shouldn't be nil}

  import AWSCognitoAuth
  import AWSCognitoIdentityProvider
  import AWSCore
  import AWSSNS
  import SwiftUI

  var cachedLogin: NSDictionary?
  class DeveloperAuthenticatedIdentityProvider: AWSCognitoCredentialsProviderHelper {

    // Handles getting the login
    override func logins() -> AWSTask<NSDictionary> {
      guard let cachedLoginObj = cachedLogin else {
        return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSDictionary> in
          guard let credential = credentialTask.result else {
            return AWSTask(result: nil)
          }

          self.setCognitoTokenKey(credential: credential)

          return AWSTask(result: cachedLogin)
        }) as! AWSTask<NSDictionary>
      }
      return AWSTask(result: cachedLoginObj)
    }

    // Handles getting a token from the server
    override func token() -> AWSTask<NSString> {
      return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSString> in
        guard let credential = credentialTask.result else {
          return AWSTask(result: nil)
        }

        self.setCognitoTokenKey(credential: credential)
        self.identityId = credential.identityId
        return AWSTask(result: credential.token as NSString)
      }) as! AWSTask<NSString>
    }

    // Handles getting the identity id
    override func getIdentityId() -> AWSTask<NSString> {

      return getCredentials().continueWith(block: { (credentialTask) -> AWSTask<NSString> in
        guard let credential = credentialTask.result else {
          return AWSTask(result: nil)
        }

        self.setCognitoTokenKey(credential: credential)

        return AWSTask(result: credential.identityId as NSString)
      }) as! AWSTask<NSString>
    }

    //This method is used to AWS Token set
    func setCognitoTokenKey(credential: AmazonCognitoCredential) {
      let login: NSDictionary = ["cognito-identity.amazonaws.com": credential.token]
      cachedLogin = login
      self.identityId = credential.identityId
    }

    // Gets credentials from server
    func getCredentials() -> AWSTask<AmazonCognitoCredential> {
      // Creating a credential object with hardcoded values
      let hardcodedCredential = AmazonCognitoCredential(
        token: "token_from_backend_getOpenIdTokenForDeveloperIdentity",
        identityId: "id_from_backend_getOpenIdTokenForDeveloperIdentity ")
      let tokenRequest = AWSTaskCompletionSource<AmazonCognitoCredential>()
      tokenRequest.set(result: hardcodedCredential)
      return tokenRequest.task
    }
    typealias CompletionBlock = (
      _ success: Bool, _ errorMassage: Error?, _ responce: AmazonCognitoCredential?
    ) -> Void
    func getAwsToken(complitionBlock: @escaping CompletionBlock) {
      //Your server token code
    }
    /// AmazonCognito credential custom class

    final class AmazonCognitoCredential {
      let token: String
      let identityId: String

      init(token: String, identityId: String) {
        self.token = token
        self.identityId = identityId
      }
    }
  }

  struct ContentView: View {
    init() {
      print("test")
      let region = AWSRegionType.APSoutheast1
      let identityPoolId = "identityPoolId"
      let devAuth = DeveloperAuthenticatedIdentityProvider(
        regionType: region, identityPoolId: identityPoolId, useEnhancedFlow: true,
        identityProviderManager: nil)
      let credentialsProvider = AWSCognitoCredentialsProvider(
        regionType: region, identityProvider: devAuth)
      let configuration = AWSServiceConfiguration(
        region: region, credentialsProvider: credentialsProvider)
      AWSServiceManager.default()?.defaultServiceConfiguration = configuration

      print("test2")
      let sns = AWSSNS.default()
      let arn = AWSSNSListEndpointsByPlatformApplicationInput()
      arn?.platformApplicationArn = "arn"
      sns.listEndpoints(byPlatformApplication: arn!) { (response, error) in
        if let error = error {
          print("Error: \(error)")
          return
        }

        guard let endpoints = response?.endpoints else {
          print("No endpoints found")
          return
        }

        for endpoint in endpoints {
          print("Endpoint ARN: \(endpoint.endpointArn ?? "nil")")
          // Additional processing if needed
        }
      }

    }
    var body: some View {
      VStack {
        Image(systemName: "globe")
          .imageScale(.large)
          .foregroundColor(.accentColor)
        Text("Hello, wor1ld!")
      }
    }
  }
thisisabhash commented 3 months ago

Can you try enabling verbose logs like this and share them in the issue after removing sensitive information?

AWSDDLog.sharedInstance.logLevel = .verbose
AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
kinglau66 commented 3 months ago

My bad, this works after updating the token. Apparently, the token had expired because I tested it quite some time after getting it. Thanks!