Exemple #1
0
def access_valid_token(token_code):
    """
    Looks up an unexpired app specific token with the given token code.

    If found, the token's last_accessed field is set to now and the token is returned. If not found,
    returns None.
    """
    token_code = remove_unicode(token_code)

    prefix = token_code[:TOKEN_NAME_PREFIX_LENGTH]
    if len(prefix) != TOKEN_NAME_PREFIX_LENGTH:
        return None

    suffix = token_code[TOKEN_NAME_PREFIX_LENGTH:]

    # Lookup the token by its prefix.
    try:
        token = (AppSpecificAuthToken.select(
            AppSpecificAuthToken, User).join(User).where(
                AppSpecificAuthToken.token_name == prefix,
                ((AppSpecificAuthToken.expiration > datetime.now())
                 | (AppSpecificAuthToken.expiration >> None)),
            ).get())

        if not token.token_secret.matches(suffix):
            return None

        assert len(prefix) == TOKEN_NAME_PREFIX_LENGTH
        assert len(suffix) >= MINIMUM_TOKEN_SUFFIX_LENGTH
        update_last_accessed(token)
        return token
    except AppSpecificAuthToken.DoesNotExist:
        pass

    return None
Exemple #2
0
def verify_robot(robot_username, password):
  try:
    password = remove_unicode(password)
  except UnicodeEncodeError:
    msg = ('Could not find robot with username: %s and supplied password.' %
            robot_username)
    raise InvalidRobotException(msg)

  result = parse_robot_username(robot_username)
  if result is None:
    raise InvalidRobotException('%s is an invalid robot name' % robot_username)

  robot = lookup_robot(robot_username)
  assert robot.robot

  # Lookup the token for the robot.
  try:
    token_data = RobotAccountToken.get(robot_account=robot)
    if not token_data.token.matches(password):
      msg = ('Could not find robot with username: %s and supplied password.' %
             robot_username)
      raise InvalidRobotException(msg)
  except RobotAccountToken.DoesNotExist:
    # TODO(remove-unenc): Remove once migrated.
    if not ActiveDataMigration.has_flag(ERTMigrationFlags.READ_OLD_FIELDS):
      raise InvalidRobotException(msg)

    if password.find('robot:') >= 0:
      # Just to be sure.
      raise InvalidRobotException(msg)

    query = (User
             .select()
             .join(FederatedLogin)
             .join(LoginService)
             .where(FederatedLogin.service_ident == password, LoginService.name == 'quayrobot',
                    User.username == robot_username))

    try:
      robot = query.get()
    except User.DoesNotExist:
      msg = ('Could not find robot with username: %s and supplied password.' %
             robot_username)
      raise InvalidRobotException(msg)

  # Find the owner user and ensure it is not disabled.
  try:
    owner = User.get(User.username == result[0])
  except User.DoesNotExist:
    raise InvalidRobotException('Robot %s owner does not exist' % robot_username)

  if not owner.enabled:
    raise InvalidRobotException('This user has been disabled. Please contact your administrator.')

  # Mark that the robot was accessed.
  _basequery.update_last_accessed(robot)

  return robot
Exemple #3
0
def verify_federated_login(service_id, service_ident):
    try:
        found = (FederatedLogin.select(
            FederatedLogin,
            User).join(LoginService).switch(FederatedLogin).join(User).where(
                FederatedLogin.service_ident == service_ident,
                LoginService.name == service_id).get())

        # Mark that the user was accessed.
        _basequery.update_last_accessed(found.user)

        return found.user
    except FederatedLogin.DoesNotExist:
        return None
Exemple #4
0
def verify_robot(robot_username, password):
    try:
        password.encode("ascii")
    except UnicodeEncodeError:
        msg = "Could not find robot with username: %s and supplied password." % robot_username
        raise InvalidRobotException(msg)

    result = parse_robot_username(robot_username)
    if result is None:
        raise InvalidRobotException("%s is an invalid robot name" %
                                    robot_username)

    robot = lookup_robot(robot_username)
    assert robot.robot

    # Lookup the token for the robot.
    try:
        token_data = RobotAccountToken.get(robot_account=robot)
        if not token_data.token.matches(password):
            msg = "Could not find robot with username: %s and supplied password." % robot_username
            raise InvalidRobotException(msg)
    except RobotAccountToken.DoesNotExist:
        msg = "Could not find robot with username: %s and supplied password." % robot_username
        raise InvalidRobotException(msg)

    # Find the owner user and ensure it is not disabled.
    try:
        owner = User.get(User.username == result[0])
    except User.DoesNotExist:
        raise InvalidRobotException("Robot %s owner does not exist" %
                                    robot_username)

    if not owner.enabled:
        raise InvalidRobotException(
            "This user has been disabled. Please contact your administrator.")

    # Mark that the robot was accessed.
    _basequery.update_last_accessed(robot)

    return robot
Exemple #5
0
def verify_user(username_or_email, password):
    """
    Verifies that the given username/email + password pair is valid.

    If the username or e-mail address is invalid, returns None. If the password specified does not
    match for the given user, either returns None or raises TooManyLoginAttemptsException if there
    have been too many invalid login attempts. Returns the user object if the login was valid.
    """

    # Make sure we didn't get any unicode for the username.
    try:
        username_or_email.encode("ascii")
    except UnicodeEncodeError:
        return None

    # Fetch the user with the matching username or e-mail address.
    try:
        fetched = User.get((User.username == username_or_email)
                           | (User.email == username_or_email))
    except User.DoesNotExist:
        return None

    # If the user has any invalid login attempts, check to see if we are within the exponential
    # backoff window for the user. If so, we raise an exception indicating that the user cannot
    # login.
    now = datetime.utcnow()
    if fetched.invalid_login_attempts > 0:
        can_retry_at = exponential_backoff(fetched.invalid_login_attempts,
                                           EXPONENTIAL_BACKOFF_SCALE,
                                           fetched.last_invalid_login)

        if can_retry_at > now:
            retry_after = can_retry_at - now
            raise TooManyLoginAttemptsException("Too many login attempts.",
                                                retry_after.total_seconds())

    # Hash the given password and compare it to the specified password.
    if (fetched.password_hash
            and hash_password(password, fetched.password_hash).decode("ascii")
            == fetched.password_hash):
        # If the user previously had any invalid login attempts, clear them out now.
        if fetched.invalid_login_attempts > 0:
            try:
                (User.update(invalid_login_attempts=0).where(
                    User.id == fetched.id).execute())

                # Mark that the user was accessed.
                _basequery.update_last_accessed(fetched)
            except ReadOnlyModeException:
                pass

        # Return the valid user.
        return fetched

    # Otherwise, update the user's invalid login attempts.
    try:
        (User.update(
            invalid_login_attempts=User.invalid_login_attempts + 1,
            last_invalid_login=now).where(User.id == fetched.id).execute())
    except ReadOnlyModeException:
        pass

    # We weren't able to authorize the user
    return None