AWS

AWS Cognito User Pools with mobile sdk for iOS using custom challenge

I was integrating AWS Cognito user pool to an iOS application. The sign in feature is using custom challenge for authentication, but there is a lack of documentation about how to use the iOS sdk. After many trial and errors, I have finally able to sign in success, so I’m going to document the steps as shown below:

Step 1: Create a CognitoUserPool

In AppDelegate, after didFinishLaunchingWithOptions, the user pool is initialised.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  // setup service configuration
  let serviceConfiguration = AWSServiceConfiguration(region: CognitoIdentityUserPoolRegion, credentialsProvider: nil
  // create pool configuration
  let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoIdentityUserPoolAppClientId, clientSecret: nil, poolId: CognitoIdentityUserPoolId)
// initialize user pool client
  AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)
  // fetch the user pool client we initialized in above step 
  let pool = AWSCognitoIdentityUserPool(forKey: AWSCognitoUserPoolsSignInProviderKey)
  self.storyboard = UIStoryboard(name: “Main”, bundle: nil)
  pool.delegate = self
  return true 
}

Step 2: Implement the protocol delegate

extension AppDelegate: AWSCognitoIdentityCustomAuthentication{
  func didCompleteStepWithError(_ error: Error?) {
  }
  func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {
  }
  func startCustomAuthentication() -> AWSCognitoIdentityCustomAuthentication {
  if (self.navigationController == nil) {
  self.navigationController = self.storyboard?.instantiateViewController(withIdentifier: “signinController”) as? UINavigationController
  }
  if (self.signInViewController == nil) {
  self.signInViewController =   self.navigationController?.viewControllers[0] as? SignInViewController
  }
  DispatchQueue.main.async {
    self.navigationController!.popToRootViewController(animated: true)
    if (!self.navigationController!.isViewLoaded
    || self.navigationController!.view.window == nil) {
self.window?.rootViewController?.present(self.navigationController!,
animated: true,
completion: nil)
     }
    }
  return self.signInViewController! 
  }
}

Step 3: Handle the custom challenge inside the sign in view controller

extension SignInViewController: AWSCognitoIdentityCustomAuthentication {
func getCustomChallengeDetails(_ authenticationInput: AWSCognitoIdentityCustomAuthenticationInput, customAuthCompletionSource: AWSTaskCompletionSource<AWSCognitoIdentityCustomChallengeDetails>) {
let authDetails = AWSCognitoIdentityCustomChallengeDetails(challengeResponses: [“USERNAME”:”YourUserName”, “ANSWER”: “123456”])
customAuthCompletionSource.set(result: authDetails)
}
public func didCompleteStepWithError(_ error: Error?) {
DispatchQueue.main.async {
if let error = error as? NSError {
print(“error”)
} else {
print(“success”)
self.dismiss(animated: true, completion: nil)
}
}
}
}

Step 4: After sign in success, you can get the username and user attribute:

self.user?.getDetails().continueOnSuccessWith { (task) -> AnyObject? in
DispatchQueue.main.async(execute: {
self.response = task.result
// With user details
print(response)
})
return nil
}

Please let me know if you have any questions. I hope AWS could update the documentations and provide sample example code to save us time to understand the sdk through trial and error.

Deploy Koa.js Application to AWS EC2 ubuntu instance

I am developing a Koa application, which is a new web framework designed by the team behind Express. Here is a step-by-step tutorial on how to deploy the koa.js application on your Amazon Web Service (AWS) ubuntu server.

Firstly, launch the ubuntu instance on AWS. Then you need to change the security group.


Otherwise if you hit the public domain in browser, it would stuck at “Connecting” state until timeout. And the site can’t be reached as shown as the screenshot below:


By default, the launch wizard group only has type ssh.


Click “Edit” button add HTTP port 80 and HTTPS port 443 inbound rule:


Secondly, ssh into your instance, install nodejs according to the official documentations:

$ curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
$ sudo apt-get install -y nodejs

Thirdly, we use Nginx as reverse proxy server:

$ sudo apt-get update
$ sudo apt-get install nginx

Open the configuration file and edit as below. Be careful not to miss the semicolon:

server { 
    listen 80 default_server;
listen [::]:80 default_server;
    root /var/www/yourApp;
    location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

Save the file and restart nginx service:

$ sudo systemctl restart nginx

Finally, clone your git repository to the path /var/www/yourApp, you will get a permission denied, so change ownership of the folder. You may replace the ubuntu part to ‘whoami’:

$ sudo chown -R ubuntu /var/www

Run your server, for example a simple app.js:

var koa = require('koa');
var app = koa();

// logger

app.use(function *(next){
var start = new Date;
yield next;
var ms = new Date - start;
console.log('%s %s - %s', this.method, this.url, ms);
});

// response

app.use(function *(){
this.body = 'Hello World';
});

app.listen(3000);

Start the server:

$ node app.js

Open your browser and hit your public domain:


Done. Leave a comment below if you have any questions 🙂

Launching RancherOS on AWS EC2

RancherOS is a linux distro for running Docker container. There is an AMI (Amazon Machine Images) in the marketplace, but it took me a while to figure out how to setup the security group etc. Here is the missing manual:

  1. Assume you already have a .pem key, then launch instance and select the Rancher AMI


2. Open terminal and connect to your instance. Note that instead of ssh as root, use rancher as the user:

$ ssh -i “XXX.pem” rancher@ec2–XX–XXX–XX–XX.ap-southeast-1.compute.amazonaws.com

3. The rancher/server should be running already, check by:

$ docker ps

If not, download and run the server using docker:

docker run -d -p 8080:8080 rancher/server

4. Go to the Security Group tab and create a new one with inbound rules:


where

  • Ports 22, 2376 and 8080/tcp are for Docker machine to provision hosts
  • Ports 500 and 4500/udp for Rancher network
  • Ports 9345 and 9346/tcp for UI
  • Port 80/tcp is for the site we deploy

5. Select the instance, then Actions > Networking > Change Security Group for the image > checked the new Security Group ID > Assign Security Group using the one we just created.

6. Open a browser and go to the Public DNS with port 8080, such as http://ec2-XX-XXX-XX-13.ap-southeast-1.compute.amazonaws.com:8080

And you should be able to see the Rancher UI:


7. Add host with Amazon EC2 using the Access Key and Secret Key. If you don’t have it yet, go the AWS console > IAM (Identity and Access Management) > Create New Users > download the credentials.csv

Then go to the Groups tab > Group Actions > Add Users to Group to add this user in. Also Attached Policy > Search for AmazonEC2FullAccess to check the box and apply.

8. Back to Rancher UI to add the newly generated Access Key and Secret Key from the credentials.csv


Finally fill out the informations according to what you need, and see your host up and running from now on.

P.S. To handle the docker’s secret API keys, certificate files and production config, you could try the beta vault integration depending on how you integrate.