Git Product home page Git Product logo

signin-awsmhh's Introduction

SignIn-awsmhh

Overview

The SignIn app is an example of an AWS User Pools authentication for IOS written in Swift.

  • "Cognito Your User Pools" login is implemented
  • Facebook and Google+ login is implemented
  • Signup, Forgot Password and Update Attributes are implemented
  • While some functions require entry of a verification code and that is implemented, if you terminate the app there needs to be a way to enter that code, and that is NOT implemented.
  • MFA (multi-factor authentication) is not implemented.
  • Supports identity linking

MySampleApp

  • This is the source downloaded from MobileHub with most of the capabilities turned on.
  • It uses the same MobileHubHelper as SignIn does. The nice thing is that this means it has access to all of the capabilities of the modified MobileHubHelper, including identity linking and user pools.
  • Small changes were required to make the code work in this project.
  • Removed some imports from the source, because I am using a bridging-header.
  • Changed the MainViewController to make it allow "linking" (which is really just signing in a second time with a different provider)
  • MySampleApp does not implement the SignUp Forgot Password etc in the sample app, but that would be pretty easy (I did that in the SignIn app)
  • Changed the SignInViewController to actually log in with User Pools when you type a username and password and click signin.
Background

This app was built to use the far superior mobile-hub-helper framework to replace earlier efforts with the ios-sdk samples.

What the App does

The app is written in Swift using AWS Mobile Hub Helper and AWS Mobile Client (from the AWS Mobile Hub). The app has a logged in and a not logged in state. Both should be allowed (in your cognito console federated identity choose -allow unauthenticated identities). The app will allow login using Facebook, Google and a custom User Pool that you create in Cognito User Pools. You can switch between identities or link identities. The app allows you to Sign Out (which simply signs you out of one SignInProvider account, possibly leaving you logged in as the same identity on another linked account). The app also allows you to Sign Out of ALL accounts . The app supports the latest AWS IOS SDK and currently is written in Swift 2. #Building

Building SignIn
  • Clone the repository using the --recursive flag, that way you will get the aws-mobilehub-helper-ios installed for you.
  • Install cocoapods
  • Use AWS account and create a User Pool in the Cognito console.
    • Make sure you make a User Pool not a Federated Identities Pool
    • Configure your User Pool with email as a required field (aka Attribute) and no other required fields. If you want phone number to be required, or want more fields then you would need to change the SignupViewController.swift to require the required ones, and allow input of all attributes. As delivered Signin requires only Username, Password (which are required by default) and Email Address (A real email is needed to get the Confirmation Number).
    • On the Pool Details page take note of your Pool Name and your Pool ID
    • On the same page add an app to your User Pool. Specify the same name you intend to use for your app name. I used "signin". Click on Show Details and take note of the App Client Id, and the App Client Secret. Click Save Changes.
    • Take a look at the Policies section of the Pool Details page to see what password requirements you want to implement. I unchecked "Require special characters" and required a minimum length of only 6. If you use something other than that edit the storyboard text for the signup view controller to say that they are required.
  • Use AWS account and create a Federated identity pool in the Cognito console.
  • To build the app you need an enhanced version of the mobile-hub-helper (changes are described at the bottom of the README.md). Clone the mobile-hub-helper fork at https://github.com/BruceBuckland/aws-mobilehub-helper-ios which has a few small fixes in it to make it handle User Pools and/or developer identities.
  • pod install
  • The easiest way to do this next step may be to use AWS Mobile Hub to create configure and download an app using your google and facebook keys, and then copy the data you need from the Info.plist in that downloaded app. But if you understand the console or aws cli, and are comfortable with Cognito and IAM, you can build the required config there and grab the id's needed for AWSKeys.config. Create a new file in Xcode File > New > File... > IOS > Other > Configuration Settings File. Name the file AWSKeys.xcconfig (because that is the filename ignored in the .gitignore, and that might help you avoid uploading your keys to github!). In that file put the following:
    //
    //  AWSKeys.xcconfig
    //
    // This file should be in .gitignore so keys don't end up on github
    // keys entered here are referenced in Info.plist

    COGNITO_USER_POOL_APP = signin
    COGNITO_USER_POOL_NAME = Your Pool Name
    COGNITO_USER_POOL_ID = Your Pool ID
    COGNITO_USER_POOL_APP_CLIENT_ID = Your App Client ID
    COGNITO_USER_POOL_APP_CLIENT_SECRET = Your App Client Secret
    COGNITO_REGIONTYPE = Your region name for instance USEast1

    // Note:  this is the federated Identity Pool ID (And not the one for the user pool)
    COGNITO_IDENTITY_POOL_ID = Your federated identities pool id
// After the user is authenticated, I have to add that user's identity
// token to the logins map in the credentials provider
// (Cognito? not user pools.  I think this is how Cognito finds out about
// User Pools (and developer authenticated IdP's)).
// So my Amazon User Pool Provider name is:


COGNITO_USER_POOL_IDP_NAME = cognito-idp.us-east-1.amazonaws.com/< your pool id like us-east-1_sfoOIFIdif>

// this ID goes in a login entry dictionary in the cognito
// credentials provider that includes
// COGNITO_USER_POOL_IDP_NAME:"ID Token from IDP (in this case User Pools)"
//

GOOGLE_CLIENT_ID = from your mobile hub downloaded info.plist
GOOGLE_URL_SCHEME = from your mobile hub downloaded info.plist
FACEBOOK_APP_ID =  from your mobile hub downloaded info.plist
PROJECT_CLIENT_ID = < from the Info.plist downloaded when you made a mobile hub like MobileHub 3252345-3245-325-345-3425-2345 aws-my-sample-app-ios-swift-v0.4>

  • You will need to specify your AWSKeys.xcconfig as a Configuration for (Debug and Release) in your project settings -> Select Project -> Select Info -> Select Configurations -> Select the AWSKeys file in both Debug and Release.
  • If you change the configuration of these settings you must do a Product -> Clean (which gets rid of the preconfigured info.plist I think, so the settings can find thier way to K. struct in ConstantsK.swift
  • This app uses an AWSSignInProvider class called AWSCUPIdPSignInProvider that allows authentication using Cognito Your User Pools.
  • Build and Run (Tested on a iPhone6 format machine)
Optional, if you want to use the framework, you have to build it.
  • cd top level directory aws-mobile-hub-helper
  • Scripts/GenerateHelperFramework.sh (This puts a builtFramework directory at top level)
  • In xcode open SignIn-awsmhh remove the AWSMobileHubHelper.framework from that app and add the file aws-mobilehub-helper-ios/builtFramework/framework/AWSMobileHubHelper.framework to your app.
Changes to aws/mobile-hub-helper
  • The following changes were required and have been made. If you want to use user pools or developer identities and/or link identities, these are needed fixes.
    • Expose the required method completeLogin and allow AWSSignInProvider's to resume sessions when the app restarts (in addition to the hard-coded Google and Facebook). Required to allow a swift AWSSignInManager (without using bridging headers).
    • Enhancement to provide currentSignInProvider externally to AWSIdentityManager (via the currentSignInProvider and providerKey methods) so that Cognito User Pools providers (and developer providers) can manage signup, signin, update attributes, forgot password etc. To do those you need to be get at your user pool from within the app (unless you want to do the web redirection approach used by google and facebook (which is unnecessarily complex for developer providers).
    • The mobile-hub-helper has a hard-coded affinity for Google+ and Facebook. Only those two providers may resume sessions using AWSIdentityManager. While it is possible to try to go around AWSIdentityManager and AWSMobileClient using appDelegate code, a better solution is to make AWSIdentityManager resume any type of session that any AWSSignInProvider produces. Added a SignInProviderKeyDictionary entry to Info.plist. This dictionary relates AWSSignInProvider class names to keys stored in NSUserDefaults, instead of just hard coding "Google" and "Facebook".
    • Created AWSCUPIdPSignInProvider.swift. This class, included in this repository, is an AWSSignInProvider for Cognito User Pools. It makes sense to include it in aws-mobile-hub-helper, but I did not because that repo is distributed as a static library and swift cannot make those.
    • Added the ability to find out the name of the key in NSUserDefaults (Google, Facebook, and whatever friendly key name you use for User Pools) which is useful for the App being able to tell what Authentication Provider is giving the error (ex: "Login with Google failed Because" rather than "Login failed because")
    • Added the ability to merge identities. If you set the boolean Info.plist key “Allow Merged Identities” to YES, AWSIdentityManager will maintain an NSDictionary called cachedLogins, which is added to when a new login call is made and which is shortened when a logout call is made. Then when it returns logins it always returns the loginCache. (This code now works even if identities cannot be merged. In that case the merge request should be canceled so: the provider is logged out (this removes that new identity that was unmergable from the running app, wipes the keychain, cleans up loginCache and removes the NSUserDefaults session key) and the application goes through a resume process where it starts any remaining sessions (there will always be at least one).
    • Modified to reload all the signInProviders that left NSUserDefaults keys, not just one of them as before). Now maintains a cache of the providers (in addition to a cache of logins). Supports providerKey(signInProvider) method to get current provider key name (a friendly name) for ANY provider (not just the currently active provider). Use of all of this is demonstrated in the SignIn app. What this will let us do is improve the above behavior when a login error occurs because identities cannot be be merged, and leave the user authenticated with the prior signInProvider after that rejection (code to do that is in test).
    • Modified the providerKey method to be a class function and also to create that function by using an Extension to AWSIdentityManager (to reduce the amount of custom code needed)
    • Extended AWSIdentityManager with two methods. getIdentityForIdentityId (To return a list of usernames that have been associated with this identityId) and recordIdentityForIdentityId (To update that list upon an Observed Sign In). Sync's are minimized (only hitting the server when there is a new username to record, or when the identityId is first loaded. For applications where identity is signed in once and used, should be minimal.
Bugs and To Do
  • Both Apps

    • If you try to link an identityId to another that has the same IdP, you get cannot merge identities. This is correct. However if you try to link an identity with a new username from the same Cognito Pool, you drive Cognito crazy and it keeps trying to get credentials using the new token for the old identityId, then gives up with a cryptic error (GetCredentialsForIdentity keeps failing. Clearing identityId did not help. Please check your Amazon Cognito Identity configuration.). This is not a user friendly message. If I try it again it works (having cleared the identityId, like it promised to do previously but clearly didn't). The next login works in any case. This could be a credentials provider bug, or it could just be something we need to detect upon login. Further investigation needed.

    • If try to Sign up a user with a duplicate email address, it creates the user and when the user confirms, Cognito says "duplicate" and puts the user in an unusable state. At this point there is no way to "fix that user other than administratively. So this will result in practice with users that mess up with email addresses in a position where they need to pick a new username. This seems very unfriendly. The solution (obviously) is to notify the user that the email address is duplicate upon signup. So.... We need to fetch the user that the user tries to sign up with BEFORE letting him fall into the mantrap that AWS have laid, and hopefully someday AWS will hide all this in the sdk.

      • AWS has clarified that there is a way to handle this.– confirmSignUp:forceAliasCreation:
    • Instead I had another fix. A first version of a fix for this has now been applied to SignIn and MySampleApp. The change applies to SignUpViewController. What it does is attempt to login with the alias (email) but uses a very unlikely password. We expect it to fail in one of two ways. If it is not authorized, then the email exists as an alias to another user, if it is not found, then the email is not an alias to another user and can be used. Based upon that response we either return an error or perform the user.SignUp. This seems to work well and is a good workaround till they fix the SDK

    • AWSGoogleSignInProvider crashes on startup sometime, I think it is related to trying to start up when it's token is expired or something, because the crash is only occassional, but when it does crash.. it keeps crashing. Investigate.

      • As a fix to AWSGoogleSignInProvider crashes, and really ANY AWSSignInProvider crash, what I did is to set a NSUserDefaults flag (ProvidersOk) that get set to no when starting and gets set to YES when the AWSSignInProviders all complete initialization. If upon starting up the ProviderOk flag is NO, then it drops all the provider keys and clears the keychain. That way it at least the providers get a clean slate (though you do have to log in again).
    • Need to make Username get carried around the various Signin Screens but it carries usernames from one IdP to the next, so it needs improvement to only carry cognito (your) user pools names around.

    • Need to make delegate based authentication work. I think this may present problems in the context of mobilehubhelper, but maybe not.

    • Cognito user pools are now included in mobile-hub, so this is on hold till the update the aws-mobilehub-helper-ios repository. It does delegate based processes.

    • Facebook FBSDKApplicationDelegate bug. ApplicationDidFinishLaunching with options ALWAYS returns NO, it needs to return Yes, or the sessions get torn down.

      • I have a fix in test, just ignoring the return value and returning YES
    • Using AWSIdentityManagerDidSignInNotification as an indication of a successful login does not work because errors that occur in login still set this notification so move the notification send to be when completion is successful.

  • SignIn

    • Unless we have the delegate based authentication, the login screen requires the user to click "Sign-In". But if it is a new user, the user needs to "Sign-Up". So there is a UX problem (because the user might not click "Sign-In".
  • MySampleApp

    • Make SignUp Forgot etc buttons pick up color from cognito sync.
      • Cognito user pools are now included in mobile-hub, so this is on hold till the update the aws-mobilehub-helper-ios repository.

signin-awsmhh's People

Contributors

brucebuckland avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

signin-awsmhh's Issues

Add example on invoking lambda functions

I've used SignIn-awsmhh for my project to work using Cognito Federated Identities with Cognito User Pools, starting from a new project.

Now user is logged-in and I want to invoke lambda function and this lead to a crash:
terminating with uncaught exception of type NSException

Logs displayed the following useful informations before crash occurs:

AWSiOSSDK v2.4.11 [Debug] AWSInfo.m line:122 | -[AWSServiceInfo initWithInfoDictionary:checkRegion:] | Couldn't read the region configuration from Info.plist for the client. Please check your `Info.plist` if you are providing the SDK configuration values through `Info.plist`.
 *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'The service configuration is `nil`. You need to configure `Info.plist` or set `defaultServiceConfiguration` before using this method.'

And here is the code:

        let lambda = AWSLambda.defaultLambda()
        
        lambda.invoke(request, completionHandler: {
            (response: AWSLambdaInvocationResponse?, error: NSError?) in
            
            print("ERROR HERE: \(error)")
            let payload = response?.payload
            print("PAYLOAD HERE: \(payload)")
            
            })

AWS Mobile Hub console does not offer any settings or help to directly manage lambda. Nor informations on how to configure Info.plist as stated by logs.

So could you please add an example of lambda invocation using AWS Mobile Hub Helper?

Implement startNewPasswordRequired()

Implement method startNewPasswordRequired() to allow user to set a new password.

If my understanding of Cognito is correct, new user created by Cognito console cannot be used because of FORCE_CHANGE_PASSWORD status: he/she cannot even authentify.

Cannot succeed to query DynamoDB as in you sample

I took your NoSQL code as sample for my own code. But I cannot succeed to load any data!

    func getItemWithCompletionHandler(completionHandler: (response: AWSDynamoDBObjectModel?, error: NSError?) -> Void) {
        let objectMapper = AWSDynamoDBObjectMapper.defaultDynamoDBObjectMapper()
        objectMapper.load(Graffiti.self, hashKey: AWSIdentityManager.defaultIdentityManager().identityId!, rangeKey: 1111500000, completionHandler: {(response: AWSDynamoDBObjectModel?, error: NSError?) -> Void in
            dispatch_async(dispatch_get_main_queue(), {
                completionHandler(response: response, error: error)
            })
        })
    }

response parameter appears to be nil but log displayed a response with valid. It seems mapping to table model object does not work.

I even try another request to query a list of data. In this situation too log indicate data has been successfully retrieved but code crash at object mapping.

Have you ever encountered such cases?

Can't integrate this work to own project

After spending some time studying this project, I want to integrate it in my own project. Hélas, without success.

What I have done

Replaced AWSMobileHubHelper.framework and ViewController.swift obtained at AWS Mobile console by SignIn-awsmhh's.

Problem

App crashed after few seconds with following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSDictionaryM removeObjectForKey:]: key cannot be nil'

This seems to be related to Identity Pool Configuration as stated by the log:

AWSiOSSDK v2.4.11 [Debug] AWSURLSessionManager.m line:553 | -[AWSURLSessionManager printHTTPHeadersForResponse:] | Response headers:
{
    Connection = "keep-alive";
    "Content-Length" = 143;
    "Content-Type" = "application/x-amz-json-1.1";
    Date = "Mon, 31 Oct 2016 17:28:24 GMT";
    "x-amzn-ErrorMessage" = "Invalid identity pool configuration. Check assigned IAM roles for this pool.";
    "x-amzn-ErrorType" = "InvalidIdentityPoolConfigurationException:";
    "x-amzn-RequestId" = "6d551129-9f8f-11e6-93ad-1f2317c04f0e";
}

AWSKeys.xcconfig is the same as in the SignIn-awsmhh project.

AWS - Unauthenticated access is not supported for this identity pool in swift.

I have custom UI for Signup and Singing so not using AWSAuthUI

I was able to successfully setup Signup by following the documentation and am able to see confirm users in the user pool.

I am facing issue in DynamoDB Access (Authentication issue)

Bellow is the code is am using for Login

@IBAction func btn_login(_ sender: UIButton) {
    ActivityIndicator.start()
    if(txt_soul_id.text != "" && txt_pwd.text != ""){
        
        let emailTextField = txt_soul_id.text!
        let passwordTextField = txt_pwd.text!
        
        let len = passwordTextField.count
        if(len > 7){
            if(Validations.isValidPassword(password: passwordTextField)){
                let mypool = configuration.pool?.getUser(emailTextField)
                
                mypool?.getSession(emailTextField, password: passwordTextField, validationData: nil).continueWith(block: { (task) in
                    if(task.error != nil){
                        ActivityIndicator.stop()
                        Alerts.normal_display(msg_title: "", msg_desc: (task.error?._userInfo!["message"])!, action_title: "OK", myVC: self)
                    }else{
                        ActivityIndicator.stop()
                        DispatchQueue.main.async {
                            let vc = self.storyboard?.instantiateViewController(withIdentifier: "EditProfileVC_sid") as! EditProfileVC
                            self.navigationController?.pushViewController(vc, animated: true)
                        }
                    }
                    return nil
                })
            }else{
                ActivityIndicator.stop()
                Alerts.normal_display(msg_title: "", msg_desc: "Password must require number, special character, uppercase and lowercase letter.", action_title: "Ok", myVC: self)
            }
        }else{
            ActivityIndicator.stop()
            Alerts.normal_display(msg_title: "Minimum 8 Character", msg_desc: "Your password must be at least 8 characters", action_title: "Ok", myVC: self)
        }
    }else{
        ActivityIndicator.stop()
        Alerts.normal_display(msg_title: "Required", msg_desc: "Username and password required", action_title: "OK", myVC: self)
    }
}

Upon successful login I am trying to save into the dynamodb model I have created

@IBAction func save_profile(_ sender: UIButton) {
    let dynamoDbObjectMapper = AWSDynamoDBObjectMapper.default()
    // Create data object using data models you downloaded from Mobile Hub
    let userItem: User = User()
    var stype : [String]? = nil
    stype?.append("soltype1")
     userItem._userId = AWSIdentityManager.default().identityId
    //userItem._soultypes = stype
    userItem._about = "About Me"
    userItem._bday = "19-19-1991"
    userItem._culture = "Jain"
    userItem._email = "[email protected]"
    userItem._mobile = 1234567890
    userItem._mobilePrefix = "+32"
    userItem._soulid = "mysid"
    
   
    //Save a new item
    dynamoDbObjectMapper.save(userItem, completionHandler: {
        (error: Error?) -> Void in
        if let error = error {
            print("Amazon DynamoDB Save Error: \(error)")
            return
        }
        print("An item was saved.")
    })
}

userItem._userId is nil

Gives error nil for identityId along with
Amazon DynamoDB Save Error: Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)" UserInfo={__type=NotAuthorizedException, message=Unauthenticated access is not supported for this identity pool.}

Error during pod update

Trying to update pod then getting the following error:

[!] /usr/bin/curl -f -L -o /var/folders/d3/zy9yl0lj4xz4dvt1sc24l9xr0000gs/T/d20161027-94327-9ibmzq/file.tgz https://dl.google.com/dl/cpdc/09f214fda7470397/GoogleAppUtilities-1.1.2.tar.gz --create-dirs --netrc-optional

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (7) Couldn't connect to server

I am not a Cocoapods user so I don't know what to do now.

Fatal error on SignUp

Fatal error raised on SignUp right after validation using SignUp button:
fatal error: unexpectedly found nil while unwrapping an Optional value

Crashed occured on SignupViewController:signupPressed on signUp call:

self.pool!.signUp(usernameField.text!, password: passwordField.text!, userAttributes: attributes, validationData: nil).continueWithBlock{ (task) in

All parameters are populated:

  • usernameField
  • passwordField
  • userAttributes, with email only

I hard-coded these values to bypass eventual problems with form fields.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.