示例#1
0
def undo_account_changes(AccountId, account_was_created, existingAccount, accountUpdates):
    if account_was_created:
        response = account_utils.get_account_table().delete_item(Key={'AccountId': AccountId}, ReturnValues='ALL_OLD')
        print 'Rolled back account creation for {}'.format(response.get('Attributes'))
    else:
        delete_keys = set()
        account_rollback = {}

        for k,v in accountUpdates.iteritems():
            if k in existingAccount:
                account_rollback[k] = existingAccount[k]
            else:
                delete_keys.add(k)

        account_rollback['AccountId'] = AccountId
        account_utils.update_account(account_rollback, delete_keys)
        print 'Rolled back account changes.'
示例#2
0
def put(request, UpdateAccountRequest):
    if not request.event["cognitoIdentityId"]:
        raise errors.ForbiddenRequestError(
            'The credentials used did not contain Cognito identity information'
        )

    account_utils.validate_account_update_request(UpdateAccountRequest)

    account = account_utils.get_account_for_identity(
        request.event["cognitoIdentityId"])

    if not account:
        account = {
            'AccountId': str(uuid.uuid4()),
            'CognitoIdentityId': request.event["cognitoIdentityId"]
        }

        if 'PlayerName' in UpdateAccountRequest:
            # IndexedPlayerName and PlayerNameSortKey are used to search accounts by name, case insensitive.  See accountsearch.py
            account['PlayerName'] = UpdateAccountRequest['PlayerName']
            account['IndexedPlayerName'] = UpdateAccountRequest[
                'PlayerName'].lower()
            account['PlayerNameSortKey'] = randint(
                1, account_utils.get_name_sort_key_count())

        account_utils.create_account(account)
        return account_utils.convert_account_from_dynamo_to_player_model(
            account)
    else:
        if account.get('AccountBlacklisted'):
            raise errors.ForbiddenRequestError('The account is blacklisted')

        updateRequest = {'AccountId': account['AccountId']}

        if 'PlayerName' in UpdateAccountRequest:
            # IndexedPlayerName and PlayerNameSortKey are used to search accounts by name, case insensitive.  See accountsearch.py
            updateRequest['PlayerName'] = UpdateAccountRequest['PlayerName']
            updateRequest['IndexedPlayerName'] = UpdateAccountRequest[
                'PlayerName'].lower()
            updateRequest['PlayerNameSortKey'] = randint(
                1, account_utils.get_name_sort_key_count())

        result = account_utils.update_account(updateRequest)
        return account_utils.convert_account_from_dynamo_to_player_model(
            result)
示例#3
0
def verify_auth_challenge_response(event):
    if 'privateChallengeParameters' not in event['request'] or 'type' not in event['request']['privateChallengeParameters']:
        print 'The request is missing privateChallengeParameters.type'
        event['response']['answerCorrect'] = False
        return

    challenge_type = event['request']['privateChallengeParameters']['type']
    password = None
    new_password = None
    if challenge_type == 'BasicAuth':
        password = event['request']['challengeAnswer']
    elif challenge_type == 'ForceChangePassword':
        try:
            answer = json.loads(event['request']['challengeAnswer'])
        except ValueError as e:
            print 'Unable to parse the answer for ForceChangePassword as json'
            event['response']['answerCorrect'] = False
            return

        password = answer.get('password')
        new_password = answer.get('newPassword')
        if password == None or new_password == None:
            print 'The answer for the ForceChangePassword challenge is missing the password or newPassword.'
            event['response']['answerCorrect'] = False
            return
    else:
        print 'Unsupported challenge type: {}'.format(challenge_type)
        event['response']['answerCorrect'] = False
        return

    # Use the provided username and password to attempt authentication using the admin API.
    try:
        idpResponse = account_utils.get_user_pool_client().admin_initiate_auth(
            UserPoolId = event['userPoolId'],
            ClientId = event['callerContext']['clientId'],
            AuthFlow = 'ADMIN_NO_SRP_AUTH',
            AuthParameters = {
                'USERNAME': event['userName'],
                'PASSWORD': password
            }
        )
    except:
        traceback.print_exc()
        raise errors.ClientError("Authentication failed")

    if 'AuthenticationResult' not in idpResponse:
        if 'ChallengeName' in idpResponse:
            print 'The response from AdminInitiateAuth contained a {} challenge.'.format(idpResponse.get('ChallengeName'))

        if idpResponse.get('ChallengeName') == 'NEW_PASSWORD_REQUIRED':
            idpResponse = account_utils.get_user_pool_client().admin_respond_to_auth_challenge(
                UserPoolId=event['userPoolId'],
                ClientId=event['callerContext']['clientId'],
                ChallengeName='NEW_PASSWORD_REQUIRED',
                ChallengeResponses={
                    'NEW_PASSWORD': new_password,
                    'USERNAME': event['userName']
                },
                Session=idpResponse['Session']
            )

            if 'AuthenticationResult' not in idpResponse:
                if 'ChallengeName' in idpResponse:
                    print 'The response from AdminInitiateAuth contained a {} challenge.'.format(idpResponse.get('ChallengeName'))
                print 'Authentication failed: the response from AdminInitiateAuth did not contain AuthenticationResult'
                event['response']['answerCorrect'] = False
                return
        else:
            print 'Authentication failed: the response from AdminInitiateAuth did not contain AuthenticationResult'
            event['response']['answerCorrect'] = False
            return

    if 'IdToken' not in idpResponse['AuthenticationResult']:
        print 'The response from AdminInitiateAuth did not contain an IdToken'
        event['response']['answerCorrect'] = False
        return

    # Use the token to get the identity for the user.
    provider_id = 'cognito-idp.' + event['region'] + '.amazonaws.com/' + event['userPoolId']
    idResponse = account_utils.get_identity_pool_client().get_id(
        IdentityPoolId = account_utils.get_identity_pool_id(),
        Logins = {
            provider_id: idpResponse['AuthenticationResult']['IdToken']
        }
    )

    if 'IdentityId' not in idResponse:
        print 'The response from GetId did not contain an IdentityId'
        event['response']['answerCorrect'] = False
        return

    # Update the identity to username mapping.
    account = account_utils.get_account_for_identity(idResponse['IdentityId'])
    if account:
        if account.get('AccountBlacklisted'):
            raise errors.ClientError("Authentication failed: the account is blacklisted")

        account_utils.update_account({
             'AccountId': account['AccountId'],
             'CognitoIdentityId': idResponse['IdentityId'],
             'CognitoUsername': event['userName']
        })
    else:
        account_utils.create_account({
             'AccountId': str(uuid.uuid4()),
             'CognitoIdentityId': idResponse['IdentityId'],
             'CognitoUsername': event['userName']
        })

    event['response']['answerCorrect'] = True
示例#4
0
def put_account(AccountId, AccountRequest, create_account):
    account_utils.validate_account_update_request(AccountRequest)

    # Collect the attribute changes for the Cognito user.
    cognito_request = AccountRequest.get('IdentityProviders', {}).get(account_utils.IDP_COGNITO, {})
    cognito_updates = get_cognito_updates(cognito_request)

    # Get the existing account if needed and determine the Cognito username.
    create_user = False
    existing_account = {}
    username = None
    if create_account:
        username = AccountRequest.get('CognitoUsername')
        create_user = '******' in AccountRequest
    else:
        existing_account = account_utils.get_account_table().get_item(Key = { 'AccountId': AccountId }, ConsistentRead = False).get('Item', {})
        username = existing_account.get('CognitoUsername')
        if 'CognitoUsername' in AccountRequest and 'CognitoUsername' in existing_account and username != AccountRequest.get('CognitoUsername'):
            raise errors.ClientError('Changing the account username is not supported.')
        create_user = '******' in AccountRequest and 'CognitoUsername' not in existing_account

    if cognito_updates and not username:
        raise errors.ClientError('Unable to update Cognito: There is no Cognito user associated with this account.')

    # Collect the attribute changes for the account row.
    account_updates, delete_keys, added_to_blacklist = get_account_updates(AccountRequest, existing_account)

    # Create or update the account.
    updated_account = None
    account = account_updates.copy()
    account['AccountId'] = AccountId
    if create_account:
        account_utils.create_account(account)
        updated_account = account
        print 'Created account: ', account
    elif account_updates or delete_keys:
        updated_account = account_utils.update_account(account, delete_keys, existing_account)
        print 'Updated account: ', account

    # Create or update the Cognito user, and roll back the account changes if that fails.
    try:
        if create_user:
            account_utils.get_user_pool_client().admin_create_user(
                UserPoolId=account_utils.get_user_pool_id(),
                Username=username,
                UserAttributes=cognito_updates,
                DesiredDeliveryMediums=['EMAIL']
            )
            print 'Created: ', account_utils.logging_filter(cognito_updates)
        elif cognito_updates:
            account_utils.get_user_pool_client().admin_update_user_attributes(
                UserPoolId=account_utils.get_user_pool_id(),
                Username=username,
                UserAttributes=cognito_updates
            )
            print 'Updated: ', account_utils.logging_filter(cognito_updates)
    except botocore.exceptions.ClientError as e:
        if updated_account:
            undo_account_changes(AccountId, create_account, existing_account, account_updates)

        code = e.response.get('Error', {}).get('Code', None)
        if code == 'UserNotFoundException':
            raise errors.ClientError('User does not exist in Cognito.')
        if code == 'UsernameExistsException':
            raise errors.ClientError('The username already exists in Cognito.')
        raise
    except:
        if updated_account:
            undo_account_changes(AccountId, create_account, existing_account, account_updates)

        raise

    if added_to_blacklist and username:
        # Invalidate existing tokens for the user after adding to the blacklist.
        account_utils.get_user_pool_client().admin_user_global_sign_out(UserPoolId=account_utils.get_user_pool_id(), Username=username)

    account = account_utils.convert_account_from_dynamo_to_admin_model(updated_account or existing_account)
    load_user(account)

    return account