AWS iOS SDK, The service configuration is `nil - ios

I need to create a platform endpoint in AWS for SNS push notifications.
In order to register the device to get the push notifications, I need to send the device ID to SNS, Im not using cognito, I want to upload the token using the AWS SDK from the phone:
AWSSNSCreatePlatformEndpointInput
when I try to register with:
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{
NSLog(#"deviceToken: %#", deviceToken);
/* This is the code to actually register the device with Amazon SNS Mobile Push based on the token received */
NSString * myArn = #"arn:aws:sns:us-east-1:123456789123:app/APNS_SANDBOX/AmazonMobilePushExample";
NSLog( #"Submit the device token [%#] to SNS to receive notifications.", [self deviceTokenAsString:deviceToken] );
AWSSNSCreatePlatformEndpointInput *platformEndpointRequest = [AWSSNSCreatePlatformEndpointInput new];
platformEndpointRequest.customUserData = #"MyUserID;iPhone5";
platformEndpointRequest.token = [self deviceTokenAsString:deviceToken];
platformEndpointRequest.platformApplicationArn = myArn;
//THIS LINE CRASHING
AWSSNS *snsManager = [AWSSNS defaultSNS];
// [snsManager createPlatformEndpoint:platformEndpointRequest];
}
But I get the crash error:
'The service configuration is nil. You need to configure awsconfiguration.json, Info.plist or set defaultServiceConfiguration before using this method.'
So, how to configure either my plist of my method directly with out cognito?
Cheers

What was needed was to set the
AWSServiceManager defaultServiceManager
as Below:
- (void)awsStartWithDeviceToken:(NSData *)deviceToken {
// Set the log level
[AWSLogger defaultLogger].logLevel = AWSLogLevelVerbose;
// Login
AWSStaticCredentialsProvider *credentialsProvider = [[AWSStaticCredentialsProvider alloc]
initWithAccessKey:#"AKIAIxxxYYYA"
secretKey:#"Tx0vhKv1xMaaabbbbccccM5+3R9lEitw2Hzw"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc]
initWithRegion:AWSRegionAPSoutheast2
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
// Create SNS Client
AWSSNS *snsManager = [AWSSNS defaultSNS];
/* This is the code to actually register the device with Amazon SNS Mobile Push based on the token received. */
AWSSNSCreatePlatformEndpointInput* platformEndpointRequest = [AWSSNSCreatePlatformEndpointInput new];
platformEndpointRequest.customUserData = #"kUniqueID"; // It could be anything.
platformEndpointRequest.token = [self deviceTokenAsString:deviceToken]; // Device Token No for APNS
platformEndpointRequest.platformApplicationArn = #"arn:aws:sns:ap-southeast-2:86434343191:app/APNS_SANDBOX/ios_lambada";
[snsManager createPlatformEndpoint:platformEndpointRequest completionHandler:^(AWSSNSCreateEndpointResponse * _Nullable response, NSError * _Nullable error) {
NSLog(#"errore : %#", error);
}];
}

Related

Getting InvalidIdentityPoolConfigurationException when Retriving records from AWS DynamoDB iOS

I have used AWS DynamoDB in my app. i am using AWSDynamoDBObjectMapper for fetching records from database but getting InvalidIdentityPoolConfigurationException every time. i have set poolId and region in info.pilist,
Following is my code,
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1
identityPoolId:IDENTITY_POOL_ID];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast2
credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
AWSDynamoDBObjectMapperConfiguration *objectMapperConfiguration = [[AWSDynamoDBObjectMapperConfiguration alloc] init];
[AWSDynamoDBObjectMapper registerDynamoDBObjectMapperWithConfiguration:configuration objectMapperConfiguration:objectMapperConfiguration forKey:#"USEast1DynamoDBObjectMapper"];
_dynamoDBObjectMapper = [AWSDynamoDBObjectMapper DynamoDBObjectMapperForKey:#"USEast1DynamoDBObjectMapper"];
return YES;
}
DynamoDBManager.m
+(void)loginWithFaceBook:(NSString*)fbId{
AWSDynamoDBScanExpression *scanExpression = [AWSDynamoDBScanExpression new];
scanExpression.filterExpression = #"facebook_id = :val";
scanExpression.expressionAttributeValues = #{#":val":fbId};
[[AppContext.dynamoDBObjectMapper scan:[dynamo_user class]
expression:scanExpression]
continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"The request failed. Error: [%#]", task.error);
} else {
// AWSDynamoDBPaginatedOutput *paginatedOutput = task.result;
NSLog(#"The request sucesss. Result : [%#]", task.result);
}
return nil;
}];
}
MyViewController.m
[DynamoDBManager loginWithFaceBook:[result valueForKey:#"id"]];
Following s my error:
The request failed. Error: [Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=5 "(null)" UserInfo={__type=InvalidIdentityPoolConfigurationException, message=Invalid identity pool configuration. Check assigned IAM roles for this pool.}]
Can anyone having idea about the above error? is any configuration missing in above code?
1. Adding Facebook as an authentication provider in Cognito Console.
I can see that you are using Facebook for authentication. In AWS Cognito Console, when creating the identity pool, you have to add Facebook App ID under "Authentication Providers" -> "Facebook"
2. Adding the sufficient permissions and roles.
Once the pool is created, you have to attach a Role with the Identity pool and the Role should have the sufficient IAM privileges.
For example, if you want to perform a query, the policy document of the role that is attached to the Identity pool should have the following lines:
"Action": [
"dynamodb: Query"
]
You have to add the appropriate actions for the DynamoDB operations you want to perform.

Send push notification from iOS using Amazon SNS

I set it up Amazon SNS and iOS App to send Push Notification via SNS Console and receive in iOS. It works properly.
Now, I'm trying to send push notification from a device to another device, but I'm getting the following error:
-[AWSServiceInfo initWithInfoDictionary:checkRegion:] | Couldn't read credentials provider configurations from Info.plist. Please check
your Info.plist if you are providing the SDK configuration values
through Info.plist.
There's my code to send push notification
AWSSNS *publishCall = [AWSSNS defaultSNS];
AWSSNSPublishInput *message = [AWSSNSPublishInput new];
message.subject = #"My First Message";
//This is the ending point
message.targetArn = #"arn:aws:sns:us-west-2:895047407854:endpoint/APNS_SANDBOX/XXXXX/XXXX-XXXX-XXX-XXXX";
message.subject =#"hello";
message.message =#"teste from device";
// message.messageAttributes = messageDict;
//
// message.messageStructure = jsonString;
[publishCall publish:message completionHandler:^(AWSSNSPublishResponse * _Nullable response, NSError * _Nullable error) {
if(error) NSLog(#"%#", [error userInfo]);
if(response) NSLog(#"%#", [response description]);
}];
I don't know what I'm missing.
As per the debug log of AWSInfo.m here you will get this error when you have not configured your defaultCognitoCredentialsProvider
As they will check
_cognitoCredentialsProvider = [AWSInfo defaultAWSInfo].defaultCognitoCredentialsProvider;
if they find _cognitoCredentialsProvider nil then you will get this error.
So configure defaultCognitoCredentialsProvider properly.

Creating a private Amazon API Gateway

I want to create an api for my app that is only accessible by my app. I have added the AWS Cognito identity to my appDelegate like so:
AWSCognitoCredentialsProvider *credentialsProvider = [[DeveloperAuthenticationProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId:#"poolId"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
__block NSString *cognitoId = nil;
// Retrieve your Amazon Cognito ID
[[credentialsProvider getIdentityId] continueWithBlock:^id(AWSTask *task)
{
if (task.error)
{
NSLog(#"Error: %#", task.error);
}
else
{
// the task result will contain the identity id
cognitoId = task.result;
}
return nil;
}];
How do I use this gonitoId that gets returned to make sure that this is the only app with the id that can access my api? Do I need to save this id and use it when accessing the api?
Thanks.
Securing the API with 'AWS_IAM' authorization will require that requests are signed with credentials in the same AWS account. Past that, if you are in control of the account then you should be able to ensure that only the Cognito roles have access by setting a fine-grained policy with the API Gateway actions and resources.
http://docs.aws.amazon.com/apigateway/latest/developerguide/permissions.html#api-gateway-calling-api-permissions
The app should be receiving Cognito credentials when authenticated so you'll use in the API Gateway SDK. The generated SDKs are available in iOS Android and JavaScript.
http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk.html

AWS CognitoID VS AWS Session Token

I'm a bit confused about the difference between an AWS session token and an AWS CognitoID, are they they same? because through this code
AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc]
initWithRegionType:AWSRegionUSEast1
identityPoolId:#"my-identity-pool"];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSUnknown credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
[[credentialsProvider getIdentityId] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(#"Error: %#", task.error);
}
else {
// the task result will contain the identity id
NSString *cognitoId = task.result;
// -------------------Outputs cognito Id------------------------
NSLog(#"%#,", task.result);
}
return nil;
}];
task.result gives back an AWS CognitoID but what about an AWS Session Token? How can I get it from my ios?
Amazon Cognito IdentityId is not the same as AWS temporary credentials. AWS temporary credentials consist of accessKey, secretKey, and sessionKey. AWSCognitoCredentialsProvider has properties with these names. See the API doc for more details.
In general, if you are using any AWS service clients in the AWS Mobile SDK for iOS, you do not need to retrieve the AWS temporary credentials manually. The SDK automatically retrieves them when it needs them.

How do you include a password for Amazon DynamoDB access in iOS?

A part of my iOS app needs to save users' email addresses in a central database. I've elected to use Amazon DynamoDB. I don't need each app user to have their own credentials, I just would like to have one username/password for the app itself to write back to the database.
Using the Amazon sample code, I put this in the app delegate:
AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider credentialsWithRegionType:CognitoRegionType
identityPoolId:CognitoIdentityPoolId];
AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:DefaultServiceRegionType
credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
Created a full access role in IAM Manager, then use the following code to write to the database:
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
AWSDynamoDBObjectMapper *dynamoDBObjectMapper = [AWSDynamoDBObjectMapper defaultDynamoDBObjectMapper];
NSString *uuid = [[NSUUID UUID] UUIDString];
NSString *emailAddress = ([self.emailAddress.text length]>0)?self.emailAddress.text:#"a#b.com";
EaSLIEmailList *emailListItem = [EaSLIEmailList new];
emailListItem.UUID = uuid;
emailListItem.EmailAddress = emailAddress;
NSMutableArray *tasks = [NSMutableArray array];
[tasks addObject:[dynamoDBObjectMapper save:emailListItem]];
[[BFTask taskForCompletionOfAllTasks:tasks]
continueWithExecutor:[BFExecutor mainThreadExecutor] withBlock:^id(BFTask *task) {
if (task.error) {
NSLog(#"Error: [%#]", task.error);
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
return nil;
}];
This works absolutely fine, but I'm not sure that this is secure. I thought I should create a user and password to embed in the app.
I'd appreciate anyone's guidance on the best and simplest way to do this.
(My concern was that if I don't do this, then someone could access the database without going through the app).
Your backend could call the AWS Security Token Service to generate temporary credentials, which you then pass to the mobile device. These credentials could be assigned permissions to only specific items in DynamoDB (so even if the credentials were compromised, they would not reveal any other data).

Resources