AWS iOT login issue using IAM user credentials iOS - ios

I am trying to login into the AWS iOT using the IAM user credentials.
But I am getting the error continuously "connection error", in the console it is showing as "CP Conn 0x2819e8a80 SSLHandshake failed (-9807)". I checked with different wifi connections but still, I am getting the same errors.
Here I am sharing my code to get the more clarity,
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: myAccessKey, secretKey: mySecretKey)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSIoTDataManager.register(with: configuration!, forKey: "iOTManager")
iotDataManager = AWSIoTDataManager(forKey: "iOTManager")
#if DEMONSTRATE_LAST_WILL_AND_TESTAMENT
let lwtTopic: NSString = Constants.lwtTopic
let lwtMessage: NSString = Constants.lwtMessage
self.iotDataManager.mqttConfiguration.lastWillAndTestament.topic = lwtTopic as String
self.iotDataManager.mqttConfiguration.lastWillAndTestament.message = lwtMessage as String
self.iotDataManager.mqttConfiguration.lastWillAndTestament.qos = .AtMostOnce
#endif
self.iotDataManager.connectUsingWebSocket( withClientId: UUID().uuidString, cleanSession:true, statusCallback: mqttEventCallback)
}
func mqttEventCallback( _ status: AWSIoTMQTTStatus ) {
DispatchQueue.main.async {
print(status.rawValue)
switch(status)
{
case .connecting:
print("Connecting..!")
case .connected:
print("Connected..!")
case .disconnected:
print("Disconnected..!")
case .connectionRefused:
print("connectionRefused..!")
case .connectionError:
print("connectionError..!")
case .protocolError:
print("protocolError..!")
default:
print("unknowState" + String(status.rawValue))
}
}
When I am running the same code in iPad mini, I am able to login into AWS iOT successfully but it is not in iPhone(7, 7Plus, 8Plus). I was wondering, why it is happening. I am not getting what wrong in the code. Please help me to fix this issue.

After some research I found this 2 things
1) SSL handshake fail when using new endpoint with '-ats' or '.ats' here
2) Its gives issue in higher version (IOS 12.1.1) so check your device version.
Please refer this Doc also

Related

iOS - TunnelKit OpenVPNTunnelProvider ProviderConfigurationError

I am trying to create an ios vpn client using Tunnelkit. I am following this tutorial.
https://github.com/passepartoutvpn/tunnelkit
am able to compile and run the application, but when I try to connect, the app crashes and throwing.
Thread 1: Fatal error: 'try!' expression unexpectedly raised an error:
TunnelKit.OpenVPNTunnelProvider.ProviderConfigurationError.credentials(details:
"keychain.set()")
Anyone who had already set up tunnel kit OpenVPN, please help to resolve this issue.
func connect() {
let server = textServer.text!
let domain = textDomain.text!
let hostname = ((domain == "") ? server : [server, domain].joined(separator: "."))
let port = UInt16(textPort.text!)!
let socketType: SocketType = switchTCP.isOn ? .tcp : .udp
let credentials = OpenVPN.Credentials(textUsername.text!, textPassword.text!)
let cfg = Configuration.make(hostname: hostname, port: port, socketType: socketType)
let proto = try! cfg.generatedTunnelProtocol(
withBundleIdentifier: tunnelIdentifier,
appGroup: appGroup,
credentials: credentials
)
let neCfg = NetworkExtensionVPNConfiguration(title: "new title", protocolConfiguration: proto, onDemandRules: [])
vpn.reconnect(configuration: neCfg) { (error) in
if let error = error {
print("configure error: \(error)")
return
}
}
}
You need to follow the integration steps.
https://github.com/passepartoutvpn/tunnelkit#demo
Enable App Groups and Keychain Sharing capabilities
make sure the appGroup value is the same which you set in your target/Signings & Capabilities/App Groups

Process for uploading image to s3 with AWS Appsync || iOS image uploading with Appsync

I'm working on a new project that requires uploading attachments in the form of images. I'm using DynamoDB and AppSync API's to insert and retrieve data from database. As we are new to the AppSync and all the amazon services and database we are using for the app i'm little bit confused about the authentication process. Right now we are using API key for authentication and I have tried these steps to upload image to s3.
1 Configue the AWSServiceManager with static configuration like :-
let staticCredit = AWSStaticCredentialsProvider(accessKey: kAppSyncAccessKey, secretKey: kAppSyncSecretKey)
let AppSyncRegion: AWSRegionType = .USEast2
let config = AWSServiceConfiguration(region: AppSyncRegion, credentialsProvider: staticCredit)
AWSServiceManager.default().defaultServiceConfiguration = config
2 Uploading picture with this method : -
func updatePictureToServer(url:URL, completion:#escaping (Bool)->Void){
let transferManager = AWSS3TransferManager.default()
let uploadingFileURL = url
let uploadRequest = AWSS3TransferManagerUploadRequest()
let userBucket = String(format: "BUCKET")
uploadRequest?.bucket = userBucket
let fileName = String(format: "%#%#", AppSettings.getUserId(),".jpg")
uploadRequest?.key = fileName
uploadRequest?.body = uploadingFileURL
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error as NSError? {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
print("Error uploading: \(String(describing: uploadRequest!.key)) Error: \(error)")
}
} else {
print("Error uploading: \(String(describing: uploadRequest!.key)) Error: \(error)")
}
completion(false)
return nil
}
_ = task.result
completion(true)
print("Upload complete for: \(String(describing: uploadRequest!.key))")
return nil
})
}
3 And finally i'm able to see the uploaded image on the S3 bucket
But i'm concerned about how to save the url of the image and how to retrieve the image because when i have to make the buket PUBLIC to retrieve the image and i don't think that's a good approach, plus is it necessary to have a Cognito user pool because we aren't using Cognito user pool yet in our app and not have much knowledge about that too and documents are not helping in practical situations because we are implementing ti for the first time so we need some little help.
So two question : -
Proper procedure to use for uploading and retrieving images for S3 and AppSync.
Is it necessary to use Cognito user pool for image uploading and retrieving.
Thanks
Note: Any suggestion or improvement or anything related to the AppSync, S3 or DynamoDB will be truly appreciated and language is not a barrier just looking for directions so swift or objective-c no problem.
You need per-identity security on the bucket using Cognito Federated Identities which gives each user their own secure bucket. You can leverage the AWS Amplify to set this up for your project with $amplify add auth and selecting the default config, then $amplify add storage which configures that bucket and pool with appropriate permissions to use private uploads.
For more info checkout the repo: https://github.com/aws-amplify/amplify-cli

AWS Cognito iOS. Unauthenticated error after logout

I'm using AWS Cognito, integrated with iOS app through MobileHub to login via Facebook.
Everything works fine until I logout of existing identity and try to login with another FB account (or even with the same).
In this case I get this error, every time I call any AWS Lambda:
AWSiOSSDK v2.4.9 [Error] AWSCredentialsProvider.m line:577.
[AWSCognitoCredentialsProvider credentials].
Unable to refresh. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)" UserInfo={__type=NotAuthorizedException, message=Unauthenticated access is not supported for this identity pool.}]
But if I terminate and restart the app, everything works correct again.
This error originates here:
From reading AWS SDK code I see, that it happens because cognito identity doesn't get logins from credential provider here:
I guess this is expected, since I've logged out. But the problem is that even after logging in to FB AWS still considers me Unauthorized. From similar questions on StackOverflow I see, that in past people set logins dictionary on AWSCognitoCredentialsProvider manually. But now this property is deprecated and other similar properties are readonly.
Here is my AWS setup in AppDelegate didFinishLaunchingWithOptions method:
let cred = AWSCognitoCredentialsProvider(regionType: .euWest1, identityPoolId: "POOLID")
let config = AWSServiceConfiguration(region: .euWest1, credentialsProvider: cred)
AWSServiceManager.default().defaultServiceConfiguration = config
if let config = config {
config.timeoutIntervalForRequest = 30
config.timeoutIntervalForResource = 30
config.maxRetryCount = 3
AWSLambdaInvoker.register(with: config, forKey: "key")
}
let mapperConfiguration = AWSDynamoDBObjectMapperConfiguration()
mapperConfiguration.saveBehavior = .updateSkipNullAttributes
AWSDynamoDBObjectMapper.register(with: config!, objectMapperConfiguration: mapperConfiguration, forKey: "updateObjectMapper")
And here is logout code:
AWSIdentityManager.defaultIdentityManager().logout { (result, error) in
if let cp = AWSServiceManager.default().defaultServiceConfiguration.credentialsProvider as? AWSCognitoCredentialsProvider {
cp.clearKeychain()
}
// Open login screen
}
Please note, that I tried both clearing keychain and not doing it. The result is the same.
I'd really appreciate any help!
Best regards,
Alex
Are you doing this in the implementation of the logins method?
- (AWSTask<NSDictionary<NSString *, NSString *> *> *)logins {
FBSDKAccessToken* fbToken = [FBSDKAccessToken currentAccessToken];
if(fbToken){
NSString *token = fbToken.tokenString;
return [AWSTask taskWithResult: #{ AWSIdentityProviderFacebook : token }];
}else{
return [AWSTask taskWithError:[NSError errorWithDomain:#"Facebook Login"
code:-1
userInfo:#{#"error":#"No current Facebook access token"}]];
}
}
More details.

Using DynamoDB With Cognito: Token is not from a supported provider of this identity pool

I am in the process of implementing registration and login for my iOS app, using this project as an example:
https://github.com/awslabs/aws-sdk-ios-samples/tree/75ada5b6283b7c04c1214b2e1e0a6394377e3f2b/CognitoYourUserPools-Sample/Objective-C/CognitoYourUserPoolsSample
Previously, my app was able to access DynamoDB resources by using a credentials provider set up in my AppDelegate's didFinishLaunchingWithOptions method. However, after changing my project to include logging in and function like the example, I see the error:
"__type":"NotAuthorizedException","message":"Token is not from a supported provider of this identity pool."
The code setting the credentialsProviderin AppDelegate currently looks like this:
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId:APP_CLIENT_ID, clientSecret: APP_CLIENT_SECRET, poolId: USER_POOL_ID)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: USER_POOL_NAME)
let pool = AWSCognitoIdentityUserPool(forKey:USER_POOL_NAME)
pool.delegate = self
self.storyboard = UIStoryboard(name: "Main", bundle: nil)
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager:pool)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
I also cannot access any DynamoDB data through my app.
Based on the console output, the registration process seems to work correctly, although I'm unsure about the sign-in process. It occurred to me that I had changed the region from EU-West-1, where the DynamoDB resources were stored, to US-East-1. In order to account for this change, I repeated the same steps I had intially taken to allow my app to access DynamoDB:
I created Auth and Unauth roles, both with access to the same actions as the role which had previously worked, but for the EU-West-1 resources instead.
I set these roles to the user pool I created when setting up registration under "unauthenticated role" and "authenticated role".
In case it makes a difference, I should note that I did not use the exact same sign-in process outlined in the example project I linked. Instead, I used the explicit sign in process, like so:
let name = usernameField.text!
let user = pool!.getUser(name)
lock()
user.getSession(name, password: passwordField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
(task:AWSTask!) -> AnyObject! in
if task.error != nil {
self.sendErrorPopup("ERROR: Unable to sign in. Error description: " + task.error!.description)
} else {
print("Successful Login")
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("mainViewControllerSegue", sender: self)
}
}
self.unlock()
return nil
})
The methods lock(), unlock(), and sendErrorPopup() are strictly UI-related methods that I made so that the beginning and end of the sign-in process would be more visually clear. The console output always reads "successful login", but I am wondering if this code actually signs the user in correctly, since the error message makes it sound like the user might not be properly authorized.
It occurred to me that the US-West tables might not have been set up correctly, but I experience the same problem even when trying to create new tables, so I don't think that's the issue. Are there steps I might have missed as far as giving the user access to DynamoDB? Has the process changed with AWS Cognito's new beta user pool system?
EDIT 2:
I fixed the previous issue, and for a while, my app was working fine. However, it has suddenly stopped loading DynamoDB data when I sign in, and shows the error message: invalid login token. Can't pass in a Cognito token. Currently, my AppData code looks like this:
let serviceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: nil)
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId:APP_CLIENT_ID, clientSecret: APP_CLIENT_SECRET, poolId: USER_POOL_ID)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPoolWithConfiguration(serviceConfiguration, userPoolConfiguration: userPoolConfiguration, forKey: USER_POOL_NAME)
let pool = AWSCognitoIdentityUserPool(forKey:USER_POOL_NAME)
pool.delegate = self
self.storyboard = UIStoryboard(name: "Main", bundle: nil)
self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager:pool)
let manager = IdentityProviderManager(tokens: [NSString:NSString]())
self.credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: IDENTITY_POOL_ID, identityProviderManager: manager)
let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider!)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
...and my sign-in code looks like this:
if locked { return }
trimRegistrationValues()
let name = usernameField.text!
let user = pool!.getUser(name)
lock()
user.getSession(name, password: passwordField.text!, validationData: nil, scopes: nil).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: {
(task:AWSTask!) -> AnyObject! in
if task.error != nil {
self.sendErrorPopup("ERROR: Unable to sign in. Error description: " + task.error!.description)
} else {
print("Successful Login")
let loginKey = "cognito-idp.us-east-1.amazonaws.com/" + USER_POOL_ID
var logins = [NSString : NSString]()
self.credentialsProvider!.identityProvider.logins().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("ERROR: Unable to get logins. Description: " + task.error!.description)
} else {
if task.result != nil{
let prevLogins = task.result as! [NSString:NSString]
print("Previous logins: " + String(prevLogins))
logins = prevLogins
}
logins[loginKey] = name
let manager = IdentityProviderManager(tokens: logins)
self.credentialsProvider!.setIdentityProviderManagerOnce(manager)
self.credentialsProvider!.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("ERROR: Unable to get ID. Error description: " + task.error!.description)
} else {
print("Signed in user with the following ID:")
print(task.result)
dispatch_async(dispatch_get_main_queue()){
self.performSegueWithIdentifier("mainViewControllerSegue", sender: self)
}
}
return nil
}
}
return nil
}
}
self.unlock()
return nil
})
I haven't changed anything between my app working and not working. I did cause a "too many password resets" error while testing the password reset functionality, but the issue persisted even when I created a new user account on my app, so I don't think that's the cause. Am I handling login correctly? If so, where should I look for other possible causes to this issue?
That exception is usually thrown if you've given Cognito a login but have not enabled your identity pool to consume that login provider. If you haven't, go to the Cognito Federated Identities console and turn on whichever provider you are trying to use (looks like User Pools), and this error should go away.
If you're certain you have set that up, can you give a code snippet of how you're setting the logins?
The key that you set the ID token against in logins should be of the format cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID> not your USER_POOL_NAME. This blog along with the link in your post for our dev guide should explain the steps and code you need.
As for the solution to deprecated logins dictionary, you need to use this constructor to create the credentials provider. The identityProviderManager here should be an implementation of AWSIdentityProviderManager Protocol and the logins method should return the dictionary mapping for your provider name to the token. The credentials provider will call this method every time it needs the identity provider token. Check this answer for more details.

Amazon Cognito with iOS: Access to Identity Forbidden

Thanks for the help in advance!
I am having some trouble getting Amazon Cognito to store/synchronize data properly.
On the dataset.synchronize() line (which does not store the data in Cognito), I get a large output error (with ID starred out) such as:
AWSCredentialsProvider.m line:429 | __73-[AWSCognitoCredentialsProvider
getCredentialsWithCognito:authenticated:]_block_invoke | GetCredentialsForIdentity
failed. Error is [Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain
Code=10 "(null)" UserInfo={__type=NotAuthorizedException, message=Access to
Identity '*****' is forbidden.}]
The cognitoID is not nil, and returns properly (and matches the values I can read online)
For instance, after authenticating with Facebook, I perform the following:
if (FBSDKAccessToken.currentAccessToken() != nil)
{
let fbCognitoToken = FBSDKAccessToken.currentAccessToken().tokenString
credentialsProvider.logins = [AWSCognitoLoginProviderKey.Facebook.rawValue: fbCognitoToken]
// Retrieve your Amazon Cognito ID
credentialsProvider.getIdentityId().continueWithBlock { (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("Error: " + task.error!.localizedDescription)
}
else {
// the task result will contain the identity id
let cognitoId = task.result
//checking if cognito was successful, if true, sets success condition to true to prepare for segue into app
if cognitoId != nil{
print (cognitoId)
cognitoSuccess = true
let syncClient = AWSCognito.defaultCognito()
let dataset = syncClient.openOrCreateDataset("User_Data")
dataset.setString("test#test.com", forKey:"Email")
// credentialsProvider.refresh()
dataset.synchronize()
} }return nil}}
I can read data from Facebook correctly, and all authentication occurred correctly from what I can tell. I suspect there is something simple that is at the root here, but after spending several days, I cannot figure it out! Using the IAM checker in the AWS portal returns all "green checks" for Cognito functions, so I am sure this not a permissions issue on the server-side, either.
Thanks again for any insight you might have!
Edit:
Before the chunk of code above, I call:
let credentialsProvider = self.initializeCognito()
which runs (identity pool ID starred out):
func initializeCognito () -> AWSCognitoCredentialsProvider
{
let credentialsProvider = AWSCognitoCredentialsProvider(
regionType: AWSRegionType.USEast1, identityPoolId: "******")
let defaultServiceConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
return credentialsProvider
}
That exception can be thrown when you're trying to get credentials for an authenticated id without giving any provider token linked to it. Cognito requires at least one to be given.
Can you check that you're including the facebook token during the GetCredentialsForIdentity call that's failing? If not, I'd guess that's your issue.
Edit:
Since you are using AWSCognito.defaultCognito(), it might help to follow the example on this docs page to make sure the sync client uses the right credentials provider:
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
Ended up figuring out the answer-- when I first set up AWS and was following some of Amazon's guides, I had placed code to create a new credentialsProvider in the application's App Delegate. I forgot about it, and then was trying later on to initialize another credentialsProvider. This confusion created the issues, and removing the initialization in App Delegate fixed the authentication problems.

Resources