Example #1
0
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != 'disabled',
                                       User.tid == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

        # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563
        if State.tenant_cache[1].creation_date < 1551740400:
            u_password = '******'' + u.password + '\''
            if GCE.check_password(u.hash_alg, password, u.salt, u_password):
                user = u
                break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    crypto_prv_key = ''
    if State.tenant_cache[tid].encryption:
        if user.crypto_prv_key:
            user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
            crypto_prv_key = GCE.symmetric_decrypt(user_key,
                                                   user.crypto_prv_key)
        else:
            # Force the password change on which the user key will be created
            user.password_change_needed = True

    if user.two_factor_enable:
        if authcode != '':
            if user.crypto_pub_key:
                two_factor_secret = GCE.asymmetric_decrypt(
                    crypto_prv_key, user.two_factor_secret).decode('utf-8')
            else:
                two_factor_secret = user.two_factor_secret.decode('utf-8')

            # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec
            if not pyotp.TOTP(two_factor_secret).verify(authcode,
                                                        valid_window=1):
                raise errors.InvalidTwoFactorAuthCode

        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    return Sessions.new(tid, user.id, user.tid, user.role,
                        user.password_change_needed, user.two_factor_enable,
                        crypto_prv_key)
Example #2
0
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    Login transaction for users' access

    :param session: An ORM session
    :param tid: A tenant ID
    :param username: A provided username
    :param password: A provided password
    :param authcode: A provided authcode
    :param client_using_tor: A boolean signaling Tor usage
    :param client_ip:  The client IP
    :return: Returns a user session in case of success
    """
    user = None

    for u in session.query(User).filter(User.username == username,
                                        User.state == 'enabled',
                                        User.tid == tid):
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        login_error(tid)

    connection_check(tid, client_ip, user.role, client_using_tor)

    crypto_prv_key = ''
    if user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode(), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(
            user_key, Base64Encoder.decode(user.crypto_prv_key))
    elif State.tenant_cache[tid].encryption:
        # Force the password change on which the user key will be created
        user.password_change_needed = True

    # Require password change if password change threshold is exceeded
    if State.tenant_cache[tid].password_change_period > 0 and \
       user.password_change_date < datetime_now() - timedelta(days=State.tenant_cache[tid].password_change_period):
        user.password_change_needed = True

    if user.two_factor_enable:
        if authcode != '':
            # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec
            if not pyotp.TOTP(user.two_factor_secret).verify(authcode,
                                                             valid_window=1):
                raise errors.InvalidTwoFactorAuthCode

        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    return Sessions.new(tid, user.id, user.tid, user.role,
                        user.password_change_needed, user.two_factor_enable,
                        crypto_prv_key, user.crypto_escrow_prv_key)
Example #3
0
def db_user_update_user(session, tid, user_session, request):
    """
    Transaction for updating an existing user

    :param session: An ORM session
    :param tid: A tenant ID
    :param user_session: A session of the user invoking the transaction
    :param request: A user request data
    :return: A user model
    """
    from globaleaks.handlers.admin.notification import db_get_notification
    from globaleaks.handlers.admin.node import db_admin_serialize_node

    user = models.db_get(session, models.User,
                         models.User.id == user_session.user_id)

    user.language = request.get('language',
                                State.tenant_cache[tid].default_language)
    user.name = request['name']
    user.public_name = request['public_name'] if request[
        'public_name'] else request['name']

    if request['password']:
        if user.password_change_needed:
            user.password_change_needed = False
        else:
            if not GCE.check_password(user.hash_alg, request['old_password'],
                                      user.salt, user.password):
                raise errors.InvalidOldPassword

        user_session.cc = set_user_password(tid, user, request['password'],
                                            user_session.cc)

    # If the email address changed, send a validation email
    if request['mail_address'] != user.mail_address:
        user.change_email_address = request['mail_address']
        user.change_email_date = datetime_now()
        user.change_email_token = generateRandomKey()

        user_desc = user_serialize_user(session, user, user.language)

        user_desc['mail_address'] = request['mail_address']

        template_vars = {
            'type': 'email_validation',
            'user': user_desc,
            'new_email_address': request['mail_address'],
            'validation_token': user.change_email_token,
            'node': db_admin_serialize_node(session, tid, user.language),
            'notification': db_get_notification(session, tid, user.language)
        }

        State.format_and_send_mail(session, tid, user_desc, template_vars)

    parse_pgp_options(user, request)

    return user
Example #4
0
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    if State.tenant_cache[
            1].two_factor_auth and user.last_login != datetime_null():
        token = TwoFactorTokens.get(user.id)

        if token is not None and authcode != '':
            if token.token == authcode:
                TwoFactorTokens.revoke(user.id)
            else:
                raise errors.InvalidTwoFactorAuthCode

        elif token is None and authcode == '':
            token = TwoFactorTokens.new(user.id)

            data = {'type': '2fa', 'authcode': str(token.token)}

            data['node'] = db_admin_serialize_node(session, tid, user.language)
            data['notification'] = db_get_notification(session, tid,
                                                       user.language)

            subject, body = Templating().get_mail_subject_and_body(data)
            State.sendmail(1, user.mail_address, subject, body)
            raise errors.TwoFactorAuthCodeRequired
        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed,
                        crypto_prv_key)
Example #5
0
def login(session, tid, username, password, client_using_tor, client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    if not client_using_tor and not State.tenant_cache[tid]['https_' +
                                                            user.role]:
        log.err("Denied login request over Web for role '%s'" % user.role)
        raise errors.TorNetworkRequired

    # Check if we're doing IP address checks today
    if State.tenant_cache[tid]['ip_filter_authenticated_enable']:
        ip_networks = parse_csv_ip_ranges_to_ip_networks(
            State.tenant_cache[tid]['ip_filter_authenticated'])

        if isinstance(client_ip, binary_type):
            client_ip = client_ip.decode()

        client_ip_obj = ipaddress.ip_address(client_ip)

        # Safety check, we always allow localhost to log in
        success = False
        if client_ip_obj.is_loopback is True:
            success = True

        for ip_network in ip_networks:
            if client_ip_obj in ip_network:
                success = True

        if success is not True:
            raise errors.AccessLocationInvalid

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed,
                        crypto_prv_key)
Example #6
0
 def test_check_password(self):
     hash = GCE.hash_password(password, salt)
     self.assertTrue(GCE.check_password(GCE.HASH, password, salt, hash))
     self.assertFalse(
         GCE.check_password(GCE.HASH, password, salt, 'nohashnoparty'))
Example #7
0
def db_user_update_user(session, tid, user_session, request):
    """
    Updates the specified user.
    This version of the function is specific for users that with comparison with
    admins can change only few things:
      - real name
      - email address
      - preferred language
      - the password (with old password check)
      - pgp key
    raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist.
    """
    from globaleaks.handlers.admin.notification import db_get_notification
    from globaleaks.handlers.admin.node import db_admin_serialize_node

    user = models.db_get(session, models.User,
                         models.User.id == user_session.user_id)

    user.language = request.get('language',
                                State.tenant_cache[tid].default_language)
    user.name = request['name']
    new_password = request['password']
    old_password = request['old_password']

    if new_password:
        if user.password_change_needed:
            user.password_change_needed = False
        else:
            if not GCE.check_password(user.hash_alg, old_password, user.salt,
                                      user.password):
                raise errors.InvalidOldPassword

        # Regenerate the password hash only if different from the best choice on the platform
        if user.hash_alg != GCE.HASH:
            user.hash_alg = GCE.HASH
            user.salt = GCE.generate_salt()

        password_hash = GCE.hash_password(new_password, user.salt)

        # Check that the new password is different form the current password
        if user.password == password_hash:
            raise errors.PasswordReuseError

        user.password = password_hash
        user.password_change_date = datetime_now()

        if State.tenant_cache[tid].encryption:
            enc_key = GCE.derive_key(request['password'].encode(), user.salt)
            if not user_session.cc:
                # Th First first password change triggers the generation
                # of the user encryption private key and its backup
                user_session.cc, user.crypto_pub_key = GCE.generate_keypair()
                user.crypto_bkp_key, user.crypto_rec_key = GCE.generate_recovery_key(
                    user_session.cc)

                # If the user had already enabled two factor before encryption was not enable
                # encrypt the two factor secret
                if user.two_factor_secret:
                    user.two_factor_secret = GCE.asymmetric_encrypt(
                        user.crypto_pub_key, user.two_factor_secret)

            user.crypto_prv_key = GCE.symmetric_encrypt(
                enc_key, user_session.cc)

    # If the email address changed, send a validation email
    if request['mail_address'] != user.mail_address:
        user.change_email_address = request['mail_address']
        user.change_email_date = datetime_now()
        user.change_email_token = generateRandomKey(32)

        user_desc = user_serialize_user(session, user, user.language)

        user_desc['mail_address'] = request['mail_address']

        template_vars = {
            'type': 'email_validation',
            'user': user_desc,
            'new_email_address': request['mail_address'],
            'validation_token': user.change_email_token,
            'node': db_admin_serialize_node(session, tid, user.language),
            'notification': db_get_notification(session, tid, user.language)
        }

        State.format_and_send_mail(session, tid, user_desc, template_vars)

    # If the platform allows users to change PGP keys, process it
    if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True:
        parse_pgp_options(user, request)

    return user
Example #8
0
def db_user_update_user(session, tid, user_session, request):
    """
    Updates the specified user.
    This version of the function is specific for users that with comparison with
    admins can change only few things:
      - real name
      - email address
      - preferred language
      - the password (with old password check)
      - pgp key
    raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist.
    """
    from globaleaks.handlers.admin.notification import db_get_notification
    from globaleaks.handlers.admin.node import db_admin_serialize_node

    user = models.db_get(session,
                         models.User,
                         models.User.id == user_session.user_id)

    user.language = request.get('language', State.tenant_cache[tid].default_language)
    user.name = request['name']
    new_password = request['password']
    old_password = request['old_password']

    if new_password:
        if user.password_change_needed:
            user.password_change_needed = False
        else:
            if not GCE.check_password(user.hash_alg,
                                      old_password,
                                      user.salt,
                                      user.password):
                raise errors.InvalidOldPassword

        user.hash_alg = GCE.HASH
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(new_password, user.salt)
        user.password_change_date = datetime_now()

        if State.tenant_cache[1].encryption:
            enc_key = GCE.derive_key(request['password'].encode(), user.salt)
            if not user_session.cc:
                user_session.cc, user.crypto_pub_key = GCE.generate_keypair()

            user.crypto_prv_key = GCE.symmetric_encrypt(enc_key, user_session.cc)

    # If the email address changed, send a validation email
    if request['mail_address'] != user.mail_address:
        user.change_email_address = request['mail_address']
        user.change_email_date = datetime_now()
        user.change_email_token = generateRandomKey(32)

        user_desc = user_serialize_user(session, user, user.language)

        template_vars = {
            'type': 'email_validation',
            'user': user_desc,
            'new_email_address': request['mail_address'],
            'validation_token': user.change_email_token,
            'node': db_admin_serialize_node(session, 1, user.language),
            'notification': db_get_notification(session, tid, user.language)
        }

        State.format_and_send_mail(session, tid, user_desc, template_vars)

    # If the platform allows users to change PGP keys, process it
    if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True:
        parse_pgp_options(user, request)

    return user
Example #9
0
def db_user_update_user(session, state, tid, user_session, request):
    """
    Updates the specified user.
    This version of the function is specific for users that with comparison with
    admins can change only few things:
      - real name
      - email address
      - preferred language
      - the password (with old password check)
      - pgp key
    raises: globaleaks.errors.ResourceNotFound` if the receiver does not exist.
    """
    from globaleaks.handlers.admin.notification import db_get_notification
    from globaleaks.handlers.admin.node import db_admin_serialize_node

    user = models.db_get(session, models.User,
                         models.User.id == user_session.user_id)

    user.language = request.get('language',
                                State.tenant_cache[tid].default_language)
    user.name = request['name']
    new_password = request['password']
    old_password = request['old_password']

    if new_password:
        if user.password_change_needed:
            user.password_change_needed = False
        else:
            if not GCE.check_password(user.hash_alg, old_password, user.salt,
                                      user.password):
                raise errors.InvalidOldPassword

        user.hash_alg = GCE.HASH
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(new_password, user.salt)
        user.password_change_date = datetime_now()

        if State.tenant_cache[1].encryption:
            enc_key = GCE.derive_key(request['password'].encode(), user.salt)
            if not user_session.cc:
                user_session.cc, user.crypto_pub_key = GCE.generate_keypair()

            user.crypto_prv_key = GCE.symmetric_encrypt(
                enc_key, user_session.cc)

    # If the email address changed, send a validation email
    if request['mail_address'] != user.mail_address:
        user.change_email_address = request['mail_address']
        user.change_email_date = datetime_now()
        user.change_email_token = generateRandomKey(32)

        user_desc = user_serialize_user(session, user, user.language)

        template_vars = {
            'type': 'email_validation',
            'user': user_desc,
            'new_email_address': request['mail_address'],
            'validation_token': user.change_email_token,
            'node': db_admin_serialize_node(session, 1, user.language),
            'notification': db_get_notification(session, tid, user.language)
        }

        state.format_and_send_mail(session, tid, user_desc, template_vars)

    # If the platform allows users to change PGP keys, process it
    if State.tenant_cache[tid]['enable_user_pgp_key_upload'] is True:
        parse_pgp_options(state, user, request)

    return user
Example #10
0
 def test_check_password_scrypt(self):
     self.assertTrue(
         GCE.check_password('SCRYPT', password, salt, hash_scrypt))
     self.assertFalse(
         GCE.check_password('SCRYPT', password, salt, 'nohashnoparty'))
Example #11
0
 def test_check_password_argon2(self):
     self.assertTrue(
         GCE.check_password('ARGON2', password, salt, hash_argon2))
     self.assertFalse(
         GCE.check_password('ARGON2', password, salt, 'nohashnoparty'))
Example #12
0
def login(session, tid, username, password, authcode, client_using_tor, client_ip):
    """
    login returns a session
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != u'disabled',
                                       UserTenant.user_id == User.id,
                                       UserTenant.tenant_id == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

        # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563
        if State.tenant_cache[1].creation_date < datetime.timestamp(datetime(2019, 5, 3, 0, 0)):
            u_password = '******'' + u.password + '\''
            if GCE.check_password(u.hash_alg, password, u.salt, u_password):
                user = u
                break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    if State.tenant_cache[1].two_factor_auth and user.last_login != datetime_null():
        token = TwoFactorTokens.get(user.id)

        if token is not None and authcode != '':
            if token.token == authcode:
                TwoFactorTokens.revoke(user.id)
            else:
                raise errors.InvalidTwoFactorAuthCode

        elif token is None and authcode == '':
            token = TwoFactorTokens.new(user.id)

            data = {
                'type': '2fa',
                'authcode': str(token.token)
            }

            data['node'] = db_admin_serialize_node(session, tid, user.language)
            data['notification'] = db_get_notification(session, tid, user.language)

            subject, body = Templating().get_mail_subject_and_body(data)
            State.sendmail(1, user.mail_address, subject, body)
            raise errors.TwoFactorAuthCodeRequired
        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    crypto_prv_key = ''
    if State.tenant_cache[1].encryption and user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode('utf-8'), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(user_key, user.crypto_prv_key)

    return Sessions.new(tid, user.id, user.role, user.password_change_needed, crypto_prv_key)
def login(session, tid, username, password, authcode, client_using_tor,
          client_ip):
    """
    Login transaction for users' access

    :param session: An ORM session
    :param tid: A tenant ID
    :param username: A provided username
    :param password: A provided password
    :param authcode: A provided authcode
    :param client_using_tor: A boolean signaling Tor usage
    :param client_ip:  The client IP
    :return: Returns a user session in case of success
    """
    user = None

    users = session.query(User).filter(User.username == username,
                                       User.state != 'disabled',
                                       User.tid == tid).distinct()
    for u in users:
        if GCE.check_password(u.hash_alg, password, u.salt, u.password):
            user = u
            break

        # Fix for issue: https://github.com/globaleaks/GlobaLeaks/issues/2563
        if State.tenant_cache[1].creation_date < 1551740400:
            u_password = '******'' + u.password + '\''
            if GCE.check_password(u.hash_alg, password, u.salt, u_password):
                user = u
                break

    if user is None:
        log.debug("Login: Invalid credentials")
        Settings.failed_login_attempts += 1
        raise errors.InvalidAuthentication

    connection_check(client_ip, tid, user.role, client_using_tor)

    crypto_prv_key = ''
    if user.crypto_prv_key:
        user_key = GCE.derive_key(password.encode(), user.salt)
        crypto_prv_key = GCE.symmetric_decrypt(
            user_key, Base64Encoder.decode(user.crypto_prv_key))
    elif State.tenant_cache[tid].encryption:
        # Force the password change on which the user key will be created
        user.password_change_needed = True

    if user.two_factor_enable:
        if authcode != '':
            # RFC 6238: step size 30 sec; valid_window = 1; total size of the window: 1.30 sec
            if not pyotp.TOTP(user.two_factor_secret).verify(authcode,
                                                             valid_window=1):
                raise errors.InvalidTwoFactorAuthCode

        else:
            raise errors.TwoFactorAuthCodeRequired

    user.last_login = datetime_now()

    return Sessions.new(tid, user.id, user.tid, user.role,
                        user.password_change_needed, user.two_factor_enable,
                        crypto_prv_key, user.crypto_escrow_prv_key)
Example #14
0
 def test_check_password(self):
     hash = GCE.hash_password(password, salt)
     self.assertTrue(GCE.check_password(GCE.HASH, password, salt, hash))
     self.assertFalse(GCE.check_password(GCE.HASH, password, salt, 'nohashnoparty'))