Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated API docs #171

Merged
merged 3 commits into from May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
117 changes: 111 additions & 6 deletions firebase_admin/_user_import.py
Expand Up @@ -27,7 +27,7 @@ def b64_encode(bytes_value):
class UserProvider(object):
"""Represents a user identity provider that can be associated with a Firebase user.

One or more providers can be specified in a ``UserImportRecord`` when importing users via
One or more providers can be specified in an ``ImportUserRecord`` when importing users via
``auth.import_users()``.

Args:
Expand Down Expand Up @@ -97,10 +97,10 @@ def to_dict(self):
return {k: v for k, v in payload.items() if v is not None}


class UserImportRecord(object):
class ImportUserRecord(object):
"""Represents a user account to be imported to Firebase Auth.

Must specify the ``uid`` field at a minimum. A sequence of ``UserImportRecord`` objects can be
Must specify the ``uid`` field at a minimum. A sequence of ``ImportUserRecord`` objects can be
passed to the ``auth.import_users()`` function, in order to import those users into Firebase
Auth in bulk. If the ``password_hash`` is set on a user, a hash configuration must be
specified when calling ``import_users()``.
Expand Down Expand Up @@ -259,7 +259,10 @@ class UserImportHash(object):
"""Represents a hash algorithm used to hash user passwords.

An instance of this class must be specified when importing users with passwords via the
``auth.import_users()`` API.
``auth.import_users()`` API. Use one of the provided class methods to obtain new
instances when required. Refer to `documentation`_ for more details.

.. _documentation: https://firebase.google.com/docs/auth/admin/import-users
"""

def __init__(self, name, data=None):
Expand Down Expand Up @@ -298,42 +301,128 @@ def hmac_sha512(cls, key):

@classmethod
def hmac_sha256(cls, key):
"""Creates a new HMAC SHA256 algorithm instance.

Args:
key: Signer key as a byte sequence.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._hmac('HMAC_SHA256', key)

@classmethod
def hmac_sha1(cls, key):
"""Creates a new HMAC SHA1 algorithm instance.

Args:
key: Signer key as a byte sequence.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._hmac('HMAC_SHA1', key)

@classmethod
def hmac_md5(cls, key):
"""Creates a new HMAC MD5 algorithm instance.

Args:
key: Signer key as a byte sequence.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._hmac('HMAC_MD5', key)

@classmethod
def md5(cls, rounds):
"""Creates a new MD5 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('MD5', rounds)

@classmethod
def sha1(cls, rounds):
"""Creates a new SHA1 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('SHA1', rounds)

@classmethod
def sha256(cls, rounds):
"""Creates a new SHA256 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('SHA256', rounds)

@classmethod
def sha512(cls, rounds):
"""Creates a new SHA512 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('SHA512', rounds)

@classmethod
def pbkdf_sha1(cls, rounds):
"""Creates a new PBKDF SHA1 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('PBKDF_SHA1', rounds)

@classmethod
def pbkdf_sha256(cls, rounds):
def pbkdf2_sha256(cls, rounds):
"""Creates a new PBKDF2 SHA256 algorithm instance.

Args:
rounds: Number of rounds. Must be an integer between 0 and 120000.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return cls._basic_hash('PBKDF2_SHA256', rounds)

@classmethod
def scrypt(cls, key, rounds, memory_cost, salt_separator=None):
"""Creates a new Scrypt algorithm instance.

This is the modified Scrypt algorithm used by Firebase Auth. See ``standard_scrypt()``
function for the standard Scrypt algorith,

Args:
key: Signer key as a byte sequence.
rounds: Number of rounds. Must be an integer between 1 and 8.
memory_cost: Memory cost as an integer between 1 and 14.
salt_separator: Salt separator as a byte sequence (optional).

Returns:
UserImportHash: A new ``UserImportHash``.
"""
data = {
'signerKey': b64_encode(_auth_utils.validate_bytes(key, 'key', required=True)),
'rounds': _auth_utils.validate_int(rounds, 'rounds', 1, 8),
Expand All @@ -346,10 +435,26 @@ def scrypt(cls, key, rounds, memory_cost, salt_separator=None):

@classmethod
def bcrypt(cls):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be staticmethod, but good either way.

"""Creates a new Bcrypt algorithm instance.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
return UserImportHash('BCRYPT')

@classmethod
def standard_scrypt(cls, memory_cost, parallelization, block_size, derived_key_length):
"""Creates a new standard Scrypt algorithm instance.

Args:
memory_cost: Memory cost as a non-negaive integer.
parallelization: Parallelization as a non-negative integer.
block_size: Block size as a non-negative integer.
derived_key_length: Derived key length as a non-negative integer.

Returns:
UserImportHash: A new ``UserImportHash``.
"""
data = {
'memoryCost': _auth_utils.validate_int(memory_cost, 'memory_cost', low=0),
'parallelization': _auth_utils.validate_int(parallelization, 'parallelization', low=0),
Expand All @@ -360,7 +465,7 @@ def standard_scrypt(cls, memory_cost, parallelization, block_size, derived_key_l


class ErrorInfo(object):
"""Represents an error encountered while importing a ``UserImportRecord``."""
"""Represents an error encountered while importing an ``ImportUserRecord``."""

def __init__(self, error):
self._index = error['index']
Expand Down
2 changes: 1 addition & 1 deletion firebase_admin/_user_mgt.py
Expand Up @@ -518,7 +518,7 @@ def import_users(self, users, hash_alg=None):
raise ValueError(
'Users must be a non-empty list with no more than {0} elements.'.format(
MAX_IMPORT_USERS_SIZE))
if any([not isinstance(u, _user_import.UserImportRecord) for u in users]):
if any([not isinstance(u, _user_import.ImportUserRecord) for u in users]):
raise ValueError('One or more user objects are invalid.')
except TypeError:
raise ValueError('users must be iterable')
Expand Down
25 changes: 23 additions & 2 deletions firebase_admin/auth.py
Expand Up @@ -39,9 +39,9 @@
'AuthError',
'ErrorInfo',
'ExportedUserRecord',
'ImportUserRecord',
'ListUsersPage',
'UserImportHash',
'UserImportRecord',
'UserImportResult',
'UserInfo',
'UserMetadata',
Expand All @@ -68,7 +68,7 @@
ExportedUserRecord = _user_mgt.ExportedUserRecord
ListUsersPage = _user_mgt.ListUsersPage
UserImportHash = _user_import.UserImportHash
UserImportRecord = _user_import.UserImportRecord
ImportUserRecord = _user_import.ImportUserRecord
UserImportResult = _user_import.UserImportResult
UserInfo = _user_mgt.UserInfo
UserMetadata = _user_mgt.UserMetadata
Expand Down Expand Up @@ -418,6 +418,27 @@ def delete_user(uid, app=None):
raise AuthError(error.code, str(error), error.detail)

def import_users(users, hash_alg=None, app=None):
"""Imports the specified list of users into Firebase Auth.

At most 1000 users can be imported at a time. This operation is optimized for bulk imports and
will ignore checks on identifier uniqueness which could result in duplications. The
``hash_alg`` parameter must be specified when importing users with passwords. Refer to the
``UserImportHash`` class for supported hash algorithms.

Args:
users: A list of ``ImportUserRecord`` instances to import. Length of the list must not
exceed 1000.
hash_alg: A ``UserImportHash`` object (optional). Required when importing users with
passwords.
app: An App instance (optional).

Returns:
UserImportResult: An object summarizing the result of the import operation.

Raises:
ValueError: If the provided arguments are invalid.
AuthError: If an error occurs while importing users.
"""
user_manager = _get_auth_service(app).user_manager
try:
result = user_manager.import_users(users, hash_alg)
Expand Down
4 changes: 2 additions & 2 deletions integration/test_auth.py
Expand Up @@ -321,7 +321,7 @@ def test_verify_session_cookie_revoked(new_user, api_key):

def test_import_users():
uid, email = _random_id()
user = auth.UserImportRecord(uid=uid, email=email)
user = auth.ImportUserRecord(uid=uid, email=email)
result = auth.import_users([user])
try:
assert result.success_count == 1
Expand All @@ -335,7 +335,7 @@ def test_import_users_with_password(api_key):
uid, email = _random_id()
password_hash = base64.b64decode(
'V358E8LdWJXAO7muq0CufVpEOXaj8aFiC7T/rcaGieN04q/ZPJ08WhJEHGjj9lz/2TT+/86N5VjVoc5DdBhBiw==')
user = auth.UserImportRecord(
user = auth.ImportUserRecord(
uid=uid, email=email, password_hash=password_hash, password_salt=b'NaCl')

scrypt_key = base64.b64decode(
Expand Down