Example #1
0
def test_saslprep_exceptions(source, exception):
    with pytest.raises(exception) as ex:
        saslprep(source)
Example #2
0
def user_should_we_change_password(current_role_attrs, user, password,
                                   encrypted):
    """Check if we should change the user's password.

    Compare the proposed password with the existing one, comparing
    hashes if encrypted. If we can't access it assume yes.
    """

    if current_role_attrs is None:
        # on some databases, E.g. AWS RDS instances, there is no access to
        # the pg_authid relation to check the pre-existing password, so we
        # just assume password is different
        return True

    # Do we actually need to do anything?
    pwchanging = False
    if password is not None:
        # Empty password means that the role shouldn't have a password, which
        # means we need to check if the current password is None.
        if password == '':
            if current_role_attrs['rolpassword'] is not None:
                pwchanging = True

        # SCRAM hashes are represented as a special object, containing hash data:
        # `SCRAM-SHA-256$<iteration count>:<salt>$<StoredKey>:<ServerKey>`
        # for reference, see https://www.postgresql.org/docs/current/catalog-pg-authid.html
        elif current_role_attrs['rolpassword'] is not None \
                and pbkdf2_found \
                and re.match(SCRAM_SHA256_REGEX, current_role_attrs['rolpassword']):

            r = re.match(SCRAM_SHA256_REGEX, current_role_attrs['rolpassword'])
            try:
                # extract SCRAM params from rolpassword
                it = int(r.group(1))
                salt = b64decode(r.group(2))
                server_key = b64decode(r.group(4))
                # we'll never need `storedKey` as it is only used for server auth in SCRAM
                # storedKey = b64decode(r.group(3))

                # from RFC5802 https://tools.ietf.org/html/rfc5802#section-3
                # SaltedPassword  := Hi(Normalize(password), salt, i)
                # ServerKey       := HMAC(SaltedPassword, "Server Key")
                normalized_password = saslprep.saslprep(to_text(password))
                salted_password = pbkdf2_hmac('sha256',
                                              to_bytes(normalized_password),
                                              salt, it)

                server_key_verifier = hmac.new(salted_password,
                                               digestmod=sha256)
                server_key_verifier.update(b'Server Key')

                if server_key_verifier.digest() != server_key:
                    pwchanging = True
            except Exception:
                # We assume the password is not scram encrypted
                # or we cannot check it properly, e.g. due to missing dependencies
                pwchanging = True

        # 32: MD5 hashes are represented as a sequence of 32 hexadecimal digits
        #  3: The size of the 'md5' prefix
        # When the provided password looks like a MD5-hash, value of
        # 'encrypted' is ignored.
        elif (password.startswith('md5')
              and len(password) == 32 + 3) or encrypted == 'UNENCRYPTED':
            if password != current_role_attrs['rolpassword']:
                pwchanging = True
        elif encrypted == 'ENCRYPTED':
            hashed_password = '******'.format(
                md5(to_bytes(password) + to_bytes(user)).hexdigest())
            if hashed_password != current_role_attrs['rolpassword']:
                pwchanging = True

    return pwchanging
Example #3
0
def test_saslprep_conversions(source, target):
    assert saslprep(source) == target