Esempio n. 1
0
def default_search():
    listUsersResponse = account_utils.get_user_pool_client().list_users(
        UserPoolId=account_utils.get_user_pool_id(), Limit=50)
    usersByName = {
        user.get('Username', ''): user
        for user in listUsersResponse.get('Users', [])
    }

    accounts = []
    scanResponse = account_utils.get_account_table().scan(Limit=50)
    for accountItem in scanResponse.get('Items', []):
        account = account_utils.convert_account_from_dynamo_to_admin_model(
            accountItem)
        username = account.get('CognitoUsername')
        if username:
            user = usersByName.get(username)
            if user:
                account['IdentityProviders'] = {
                    account_utils.IDP_COGNITO:
                    account_utils.convert_user_from_cognito_to_model(user)
                }
                del usersByName[username]
            else:
                populate_identity_provider(account)
        accounts.append(account)

    for username, user in usersByName.iteritems():
        account = populate_account_for_user(user)
        accounts.append(account)

    accounts.sort(cmp=account_utils.compare_accounts)

    return {'Accounts': accounts}
Esempio n. 2
0
def get(request, AccountId):
    response = account_utils.get_account_table().get_item(Key = { 'AccountId': AccountId }, ConsistentRead = False)

    if not 'Item' in response:
        raise errors.ClientError("No account found for '{}'".format(AccountId))

    account = account_utils.convert_account_from_dynamo_to_admin_model(response['Item'])
    load_user(account)

    return account
def search_by_start_name(StartPlayerName):
    sortKeyCount = account_utils.get_name_sort_key_count()
    limit = 20

    accounts = []

    # Accounts are randomly split across multiple partition keys in accounts.py to distribute load on the index.
    # This will collect results from all of the keys and combine them.
    for partition in range(1, sortKeyCount + 1):
        # The query limit is set to the same limit as the number of returned accounts in case the results all come from
        # the same partition key.  An eventually consistent query consumes half a unit per 4KB regardless of how
        # many items contributed to the 4KB, so it's not too inefficient to read a lot of small items and throw most of them away.
        # This implementation expects searches to be relatively infrequent.
        queryArgs = {
            'ConsistentRead': False,
            'IndexName': 'PlayerNameIndex',
            'KeyConditionExpression': Key('PlayerNameSortKey').eq(partition),
            'Limit': limit,
            'ScanIndexForward': True
        }

        if StartPlayerName:
            # Convert the inclusive start key from the request into an exclusive start key since Dynamo only supports exclusive.
            # Dynamo sorts keys by utf-8 bytes.  This attempts to decrement the last byte so that it's one before
            # the start name.  Not guaranteed to work in all cases.
            exclusiveStartKeyBytes = bytearray(StartPlayerName.lower(),
                                               'utf-8')
            if exclusiveStartKeyBytes[-1] > 0:
                exclusiveStartKeyBytes[-1] = exclusiveStartKeyBytes[-1] - 1
            exclusiveStartKey = exclusiveStartKeyBytes.decode(
                'utf-8', 'ignore')

            queryArgs['ExclusiveStartKey'] = {
                'PlayerNameSortKey': partition,
                'IndexedPlayerName': exclusiveStartKey,
                'AccountId': ' '
            }
        response = account_utils.get_account_table().query(**queryArgs)

        for item in response.get('Items', []):
            accounts.append(
                account_utils.convert_account_from_dynamo_to_admin_model(item))

    accounts.sort(cmp=account_utils.compare_accounts)
    if len(accounts) > limit:
        del accounts[limit:]

    populate_identity_providers(accounts)

    return {'Accounts': accounts}
Esempio n. 4
0
def search_by_cognito_identity_id(CognitoIdentityId):
    response = account_utils.get_account_table().query(
        ConsistentRead=False,
        IndexName='CognitoIdentityIdIndex',
        KeyConditionExpression=Key('CognitoIdentityId').eq(CognitoIdentityId))

    accounts = []

    for item in response.get('Items', []):
        accounts.append(
            account_utils.convert_account_from_dynamo_to_admin_model(item))

    populate_identity_providers(accounts)

    return {'Accounts': accounts}
Esempio n. 5
0
def get_accounts_by_username(Username):
    response = account_utils.get_account_table().query(
        ConsistentRead=False,
        IndexName='CognitoUsernameIndex',
        KeyConditionExpression=Key('CognitoUsername').eq(Username))

    accounts = []

    for item in response.get('Items', []):
        accounts.append(
            account_utils.convert_account_from_dynamo_to_admin_model(item))

    populate_identity_providers(accounts)

    return accounts
Esempio n. 6
0
def get(request):
    if not request.event["cognitoIdentityId"]:
        raise errors.ForbiddenRequestError('The credentials used did not contain Cognito identity information')

    account = account_utils.get_account_for_identity(request.event["cognitoIdentityId"])
    if not account:
        raise errors.ClientError("No account found for '{}'".format(request.event["cognitoIdentityId"]))

    if account.get('AccountBlacklisted'):
        raise errors.ForbiddenRequestError('The account is blacklisted')

    response = account_utils.get_account_table().get_item(Key = { 'AccountId': account['AccountId'] }, ConsistentRead = False)

    if not 'Item' in response:
        raise errors.ClientError("No account found for '{}'".format(account['AccountId']))

    return account_utils.convert_account_from_dynamo_to_player_model(response['Item'])
Esempio n. 7
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.'
def search_by_start_name(start_player_name=None, serialized_page_token=None):
    page_size = 20

    config = dynamodb_pagination.PartitionedIndexConfig(
        table=account_utils.get_account_table(),
        index_name='PlayerNameIndex',
        partition_key_name='PlayerNameSortKey',
        sort_key_name='IndexedPlayerName',
        partition_count=account_utils.get_name_sort_key_count(),
        required_fields={'AccountId': ' '})

    if serialized_page_token:
        page_token = dynamodb_pagination.PageToken(config,
                                                   serialized_page_token)
    else:
        page_token = dynamodb_pagination.get_page_token_for_inclusive_start(
            config, start_player_name, forward=True)

    search = dynamodb_pagination.PaginatedSearch(config, page_token,
                                                 start_player_name)

    raw_account_items = search.get_next_page(page_size)

    accounts = [
        account_utils.convert_account_from_dynamo_to_admin_model(item)
        for item in raw_account_items
    ]
    populate_identity_providers(accounts)

    result = {'Accounts': accounts}

    forward_token = search.get_page_token(forward=True)
    if forward_token:
        result['next'] = forward_token

    backward_token = search.get_page_token(forward=False)
    if backward_token:
        result['previous'] = backward_token

    return result
Esempio n. 9
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