Example #1
0
def test_get_matching_users(initialized_db):
  # Exact match.
  for user in User.select().where(User.organization == False, User.robot == False):
    assert list(get_matching_users(user.username))[0].username == user.username

  # Prefix matching.
  for user in User.select().where(User.organization == False, User.robot == False):
    assert user.username in [r.username for r in get_matching_users(user.username[:2])]
Example #2
0
def _notify_superusers(key):
    notification_metadata = {
        "name": key.name,
        "kid": key.kid,
        "service": key.service,
        "jwk": key.jwk,
        "metadata": key.metadata,
        "created_date": timegm(key.created_date.utctimetuple()),
    }

    if key.expiration_date is not None:
        notification_metadata["expiration_date"] = timegm(
            key.expiration_date.utctimetuple())

    if len(config.app_config["SUPER_USERS"]) > 0:
        superusers = User.select().where(
            User.username << config.app_config["SUPER_USERS"])
        for superuser in superusers:
            create_notification(
                "service_key_submitted",
                superuser,
                metadata=notification_metadata,
                lookup_path="/service_key_approval/{0}/{1}".format(
                    key.kid, superuser.id),
            )
Example #3
0
def change_username(user_id, new_username):
    (username_valid, username_issue) = validate_username(new_username)
    if not username_valid:
        raise InvalidUsernameException("Invalid username %s: %s" %
                                       (new_username, username_issue))

    with db_transaction():
        # Reload the user for update
        user = db_for_update(User.select().where(User.id == user_id)).get()

        # Rename the robots
        for robot in db_for_update(
                _list_entity_robots(user.username,
                                    include_metadata=False,
                                    include_token=False)):
            _, robot_shortname = parse_robot_username(robot.username)
            new_robot_name = format_robot_username(new_username,
                                                   robot_shortname)
            robot.username = new_robot_name
            robot.save()

        # Rename the user
        user.username = new_username
        user.save()

        # Remove any prompts for username.
        remove_user_prompt(user, "confirm_username")

        return user
Example #4
0
File: user.py Project: zhill/quay
def mark_namespace_for_deletion(user, queues, namespace_gc_queue, force=False):
    """ Marks a namespace (as referenced by the given user) for deletion. A queue item will be added
      to delete the namespace's repositories and storage, while the namespace itself will be
      renamed, disabled, and delinked from other tables.
  """
    if not user.enabled:
        return None

    if not force and not user.organization:
        # Ensure that the user is not the sole admin for any organizations. If so, then the user
        # cannot be deleted before those organizations are deleted or reassigned.
        organizations = get_solely_admined_organizations(user)
        if len(organizations) > 0:
            message = (
                "Cannot delete %s as you are the only admin for organizations: "
                % user.username)
            for index, org in enumerate(organizations):
                if index > 0:
                    message = message + ", "

                message = message + org.username

            raise DataModelException(message)

    # Delete all queue items for the user.
    for queue in queues:
        queue.delete_namespaced_items(user.username)

    # Delete non-repository related items. This operation is very quick, so we can do so here.
    _delete_user_linked_data(user)

    with db_transaction():
        original_username = user.username
        user = db_for_update(User.select().where(User.id == user.id)).get()

        # Mark the namespace as deleted and ready for GC.
        try:
            marker = DeletedNamespace.create(
                namespace=user,
                original_username=original_username,
                original_email=user.email)
        except IntegrityError:
            return

        # Disable the namespace itself, and replace its various unique fields with UUIDs.
        user.enabled = False
        user.username = str(uuid4())
        user.email = str(uuid4())
        user.save()

    # Add a queueitem to delete the namespace.
    marker.queue_id = namespace_gc_queue.put(
        [str(user.id)],
        json.dumps({
            "marker_id": marker.id,
            "original_username": original_username,
        }),
    )
    marker.save()
    return marker.id
Example #5
0
def get_solely_admined_organizations(user_obj):
    """ Returns the organizations admined solely by the given user. """
    orgs = (
        User.select()
        .where(User.organization == True)
        .join(Team)
        .join(TeamRole)
        .where(TeamRole.name == "admin")
        .switch(Team)
        .join(TeamMember)
        .where(TeamMember.user == user_obj)
        .distinct()
    )

    # Filter to organizations where the user is the sole admin.
    solely_admined = []
    for org in orgs:
        admin_user_count = (
            TeamMember.select()
            .join(Team)
            .join(TeamRole)
            .where(Team.organization == org, TeamRole.name == "admin")
            .switch(TeamMember)
            .join(User)
            .where(User.robot == False)
            .distinct()
            .count()
        )

        if admin_user_count == 1:
            solely_admined.append(org)

    return solely_admined
Example #6
0
def get_organization_member_set(org, include_robots=False, users_filter=None):
    """
    Returns the set of all member usernames under the given organization, with optional filtering by
    robots and/or by a specific set of User objects.
    """
    Org = User.alias()
    org_users = (
        User.select(User.username)
        .join(TeamMember)
        .join(Team)
        .where(Team.organization == org)
        .distinct()
    )

    if not include_robots:
        org_users = org_users.where(User.robot == False)

    if users_filter is not None:
        ids_list = [u.id for u in users_filter if u is not None]
        if not ids_list:
            return set()

        org_users = org_users.where(User.id << ids_list)

    return {user.username for user in org_users}
Example #7
0
def get_organizations(deleted=False):
    query = User.select().where(User.organization == True, User.robot == False)

    if not deleted:
        query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace)))

    return query
Example #8
0
def get_user_map_by_ids(namespace_ids):
    id_user = {namespace_id: None for namespace_id in namespace_ids}
    users = User.select().where(User.id << namespace_ids, User.organization == False)
    for user in users:
        id_user[user.id] = user

    return id_user
Example #9
0
def list_team_robots(team):
    """
    Returns an iterator of all the *robots* found in a team.

    Does not include users.
    """
    return User.select().join(TeamMember).join(Team).where(
        Team.id == team, User.robot == True)
Example #10
0
def __get_org_admin_users(org):
    return (
        User.select()
        .join(TeamMember)
        .join(Team)
        .join(TeamRole)
        .where(Team.organization == org, TeamRole.name == "admin", User.robot == False)
        .distinct()
    )
Example #11
0
def _list_entity_robots(entity_name, include_metadata=True, include_token=True):
    """
    Return the list of robots for the specified entity.

    This MUST return a query, not a materialized list so that callers can use db_for_update.
    """
    if include_metadata or include_token:
        query = (
            User.select(User, RobotAccountToken, RobotAccountMetadata)
            .join(RobotAccountMetadata, JOIN.LEFT_OUTER)
            .switch(User)
            .join(RobotAccountToken)
            .where(User.robot == True, User.username ** (entity_name + "+%"))
        )
    else:
        query = User.select(User).where(User.robot == True, User.username ** (entity_name + "+%"))

    return query
Example #12
0
File: user.py Project: zhill/quay
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
Example #13
0
def get_active_users(disabled=True, deleted=False):
    query = User.select().where(User.organization == False, User.robot == False)

    if not disabled:
        query = query.where(User.enabled == True)

    if not deleted:
        query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace)))

    return query
Example #14
0
def get_organizations(disabled=True, deleted=False):
    query = User.select().where(User.organization == True, User.robot == False)

    if not disabled:
        query = query.where(User.enabled == True)
    else:
        # NOTE: Deleted users are already disabled, so we don't need this extra check.
        if not deleted:
            query = query.where(User.id.not_in(DeletedNamespace.select(DeletedNamespace.namespace)))

    return query
Example #15
0
def _list_entity_robots(entity_name, include_metadata=True, include_token=True):
    """ Return the list of robots for the specified entity. This MUST return a query, not a
      materialized list so that callers can use db_for_update.
  """
    # TODO(remove-unenc): Remove FederatedLogin and LEFT_OUTER on RobotAccountToken once migration
    # is complete.
    if include_metadata or include_token:
        query = (
            User.select(User, RobotAccountToken, FederatedLogin, RobotAccountMetadata)
            .join(FederatedLogin)
            .switch(User)
            .join(RobotAccountMetadata, JOIN.LEFT_OUTER)
            .switch(User)
            .join(RobotAccountToken, JOIN.LEFT_OUTER)
            .where(User.robot == True, User.username ** (entity_name + "+%"))
        )
    else:
        query = User.select(User).where(User.robot == True, User.username ** (entity_name + "+%"))

    return query
Example #16
0
def get_all_repo_users_transitive_via_teams(namespace_name, repository_name):
    return (
        User.select()
        .distinct()
        .join(TeamMember)
        .join(Team)
        .join(RepositoryPermission)
        .join(Repository)
        .join(Namespace, on=(Repository.namespace_user == Namespace.id))
        .where(Namespace.username == namespace_name, Repository.name == repository_name)
    )
Example #17
0
def get_matching_robots(name_prefix, username, limit=10):
    admined_orgs = (_basequery.get_user_organizations(username).switch(
        Team).join(TeamRole).where(TeamRole.name == "admin"))

    prefix_checks = False

    for org in admined_orgs:
        org_search = prefix_search(User.username,
                                   org.username + "+" + name_prefix)
        prefix_checks = prefix_checks | org_search

    user_search = prefix_search(User.username, username + "+" + name_prefix)
    prefix_checks = prefix_checks | user_search

    return User.select().where(prefix_checks).limit(limit)
Example #18
0
def cleanup_old_robots(page_size=50, force=False):
    """ Deletes any robots that live under namespaces that no longer exist. """
    if not force and not app.config.get("SETUP_COMPLETE", False):
        return

    # Collect the robot accounts to delete.
    page_number = 1
    to_delete = []
    encountered_namespaces = {}

    while True:
        found_bots = False
        for robot in list(User.select().where(User.robot == True).paginate(
                page_number, page_size)):
            found_bots = True
            logger.info("Checking robot %s (page %s)", robot.username,
                        page_number)
            parsed = parse_robot_username(robot.username)
            if parsed is None:
                continue

            namespace, _ = parsed
            if namespace in encountered_namespaces:
                if not encountered_namespaces[namespace]:
                    logger.info("Marking %s to be deleted", robot.username)
                    to_delete.append(robot)
            else:
                try:
                    User.get(username=namespace)
                    encountered_namespaces[namespace] = True
                except User.DoesNotExist:
                    # Save the robot account for deletion.
                    logger.info("Marking %s to be deleted", robot.username)
                    to_delete.append(robot)
                    encountered_namespaces[namespace] = False

        if not found_bots:
            break

        page_number = page_number + 1

    # Cleanup any robot accounts whose corresponding namespace doesn't exist.
    logger.info("Found %s robots to delete", len(to_delete))
    for index, robot in enumerate(to_delete):
        logger.info("Deleting robot %s of %s (%s)", index, len(to_delete),
                    robot.username)
        robot.delete_instance(recursive=True, delete_nullable=True)
Example #19
0
def _get_matching_users(username_prefix,
                        robot_namespace=None,
                        organization=None,
                        limit=20,
                        exact_matches_only=False):
    user_search = prefix_search(User.username, username_prefix)
    if exact_matches_only:
        user_search = User.username == username_prefix

    direct_user_query = user_search & (User.organization
                                       == False) & (User.robot == False)

    if robot_namespace:
        robot_prefix = format_robot_username(robot_namespace, username_prefix)
        robot_search = prefix_search(User.username, robot_prefix)
        direct_user_query = (robot_search &
                             (User.robot == True)) | direct_user_query

    query = (User.select(User.id, User.username,
                         User.email, User.robot).group_by(
                             User.id, User.username, User.email,
                             User.robot).where(direct_user_query))

    if organization:
        query = (query.select(User.id, User.username, User.email, User.robot,
                              fn.Sum(Team.id)).join(
                                  TeamMember, JOIN.LEFT_OUTER).join(
                                      Team,
                                      JOIN.LEFT_OUTER,
                                      on=((Team.id == TeamMember.team) &
                                          (Team.organization == organization)),
                                  ).order_by(User.robot.desc()))

    class MatchingUserResult(object):
        def __init__(self, *args):
            self.id = args[0]
            self.username = args[1]
            self.email = args[2]
            self.robot = args[3]

            if organization:
                self.is_org_member = args[3] != None
            else:
                self.is_org_member = None

    return (MatchingUserResult(*args) for args in query.tuples().limit(limit))
Example #20
0
def _notify_superusers(key):
  notification_metadata = {
    'name': key.name,
    'kid': key.kid,
    'service': key.service,
    'jwk': key.jwk,
    'metadata': key.metadata,
    'created_date': timegm(key.created_date.utctimetuple()),
  }

  if key.expiration_date is not None:
    notification_metadata['expiration_date'] = timegm(key.expiration_date.utctimetuple())

  if len(config.app_config['SUPER_USERS']) > 0:
    superusers = User.select().where(User.username << config.app_config['SUPER_USERS'])
    for superuser in superusers:
      create_notification('service_key_submitted', superuser, metadata=notification_metadata,
                          lookup_path='/service_key_approval/{0}/{1}'.format(key.kid, superuser.id))
Example #21
0
  def test_config_file_with_no_db_users(self):
    with FreshConfigProvider():
      # Write some config.
      self.putJsonResponse(SuperUserConfig, data=dict(config={}, hostname='foobar'))

      # Delete all the users in the DB.
      for user in list(User.select()):
        model.user.delete_user(user, all_queues)

      # This method should now succeed.
      data = dict(username='******', password='******', email='*****@*****.**')
      result = self.postJsonResponse(SuperUserCreateInitialSuperUser, data=data)
      self.assertTrue(result['status'])

      # Verify the superuser was created.
      User.get(User.username == 'cooluser')

      # Verify the superuser was placed into the config.
      result = self.getJsonResponse(SuperUserConfig)
      self.assertEquals(['cooluser'], result['config']['SUPER_USERS'])
Example #22
0
def test_cleanup_old_robots(initialized_db):
  before_robot_count = User.select().where(User.robot == True).count()
  before_user_count = User.select().count()

  # Run the cleanup once, and ensure it does nothing.
  cleanup_old_robots(force=True)

  after_robot_count = User.select().where(User.robot == True).count()
  after_user_count = User.select().count()

  assert before_robot_count == after_robot_count
  assert before_user_count == after_user_count

  # Create some orphan robots.
  created = set()
  for index in range(0, 50):
    created.add('doesnotexist+a%s' % index)
    created.add('anothernamespace+b%s' % index)

    User.create(username='******' % index, robot=True)
    User.create(username='******' % index, robot=True)

  before_robot_count = User.select().where(User.robot == True).count()
  before_user_count = User.select().count()

  cleanup_old_robots(page_size=10, force=True)

  after_robot_count = User.select().where(User.robot == True).count()
  after_user_count = User.select().count()

  assert before_robot_count == after_robot_count + len(created)
  assert before_user_count == after_user_count + len(created)

  for name in created:
    with pytest.raises(User.DoesNotExist):
      User.get(username=name)
Example #23
0
def upgrade(tables, tester, progress_reporter):
    op = ProgressWrapper(original_op, progress_reporter)

    from app import app

    if app.config.get("SETUP_COMPLETE", False) or tester.is_testing():
        # Empty all access token names to fix the bug where we put the wrong name and code
        # in for some tokens.
        (
            AccessToken.update(token_name=None)
            .where(~(AccessToken.token_name >> None), AccessToken.temporary == False)
            .execute()
        )

        # AccessToken.
        logger.info("Backfilling encrypted credentials for access tokens")
        for access_token in _iterate(
            AccessToken, ((AccessToken.token_name >> None) | (AccessToken.token_name == ""))
        ):
            logger.info("Backfilling encrypted credentials for access token %s", access_token.id)
            assert access_token.code is not None
            assert access_token.code[:ACCESS_TOKEN_NAME_PREFIX_LENGTH]
            assert access_token.code[ACCESS_TOKEN_NAME_PREFIX_LENGTH:]

            token_name = access_token.code[:ACCESS_TOKEN_NAME_PREFIX_LENGTH]
            token_code = _decrypted(access_token.code[ACCESS_TOKEN_NAME_PREFIX_LENGTH:])

            (
                AccessToken.update(token_name=token_name, token_code=token_code)
                .where(AccessToken.id == access_token.id, AccessToken.code == access_token.code)
                .execute()
            )

        assert AccessToken.select().where(AccessToken.token_name >> None).count() == 0

        # Robots.
        logger.info("Backfilling encrypted credentials for robots")
        while True:
            has_row = False
            query = (
                User.select()
                .join(RobotAccountToken, JOIN.LEFT_OUTER)
                .where(User.robot == True, RobotAccountToken.id >> None)
                .limit(BATCH_SIZE)
            )

            for robot_user in query:
                logger.info("Backfilling encrypted credentials for robot %s", robot_user.id)
                has_row = True
                try:
                    RobotAccountToken.create(
                        robot_account=robot_user,
                        token=_decrypted(robot_user.email),
                        fully_migrated=False,
                    )
                except IntegrityError:
                    break

            if not has_row:
                break

        # RepositoryBuildTrigger
        logger.info("Backfilling encrypted credentials for repo build triggers")
        for repo_build_trigger in _iterate(
            RepositoryBuildTrigger, (RepositoryBuildTrigger.fully_migrated == False)
        ):
            logger.info(
                "Backfilling encrypted credentials for repo build trigger %s", repo_build_trigger.id
            )

            (
                RepositoryBuildTrigger.update(
                    secure_auth_token=_decrypted(repo_build_trigger.auth_token),
                    secure_private_key=_decrypted(repo_build_trigger.private_key),
                    fully_migrated=True,
                )
                .where(
                    RepositoryBuildTrigger.id == repo_build_trigger.id,
                    RepositoryBuildTrigger.uuid == repo_build_trigger.uuid,
                )
                .execute()
            )

        assert (
            RepositoryBuildTrigger.select()
            .where(RepositoryBuildTrigger.fully_migrated == False)
            .count()
        ) == 0

        # AppSpecificAuthToken
        logger.info("Backfilling encrypted credentials for app specific auth tokens")
        for token in _iterate(
            AppSpecificAuthToken,
            (
                (AppSpecificAuthToken.token_name >> None)
                | (AppSpecificAuthToken.token_name == "")
                | (AppSpecificAuthToken.token_secret >> None)
            ),
        ):
            logger.info("Backfilling encrypted credentials for app specific auth %s", token.id)
            assert token.token_code[AST_TOKEN_NAME_PREFIX_LENGTH:]

            token_name = token.token_code[:AST_TOKEN_NAME_PREFIX_LENGTH]
            token_secret = _decrypted(token.token_code[AST_TOKEN_NAME_PREFIX_LENGTH:])
            assert token_name
            assert token_secret

            (
                AppSpecificAuthToken.update(token_name=token_name, token_secret=token_secret)
                .where(
                    AppSpecificAuthToken.id == token.id,
                    AppSpecificAuthToken.token_code == token.token_code,
                )
                .execute()
            )

        assert (
            AppSpecificAuthToken.select().where(AppSpecificAuthToken.token_name >> None).count()
        ) == 0

        # OAuthAccessToken
        logger.info("Backfilling credentials for OAuth access tokens")
        for token in _iterate(
            OAuthAccessToken,
            ((OAuthAccessToken.token_name >> None) | (OAuthAccessToken.token_name == "")),
        ):
            logger.info("Backfilling credentials for OAuth access token %s", token.id)
            token_name = token.access_token[:OAUTH_ACCESS_TOKEN_PREFIX_LENGTH]
            token_code = Credential.from_string(
                token.access_token[OAUTH_ACCESS_TOKEN_PREFIX_LENGTH:]
            )
            assert token_name
            assert token.access_token[OAUTH_ACCESS_TOKEN_PREFIX_LENGTH:]

            (
                OAuthAccessToken.update(token_name=token_name, token_code=token_code)
                .where(
                    OAuthAccessToken.id == token.id,
                    OAuthAccessToken.access_token == token.access_token,
                )
                .execute()
            )

        assert (OAuthAccessToken.select().where(OAuthAccessToken.token_name >> None).count()) == 0

        # OAuthAuthorizationCode
        logger.info("Backfilling credentials for OAuth auth code")
        for code in _iterate(
            OAuthAuthorizationCode,
            ((OAuthAuthorizationCode.code_name >> None) | (OAuthAuthorizationCode.code_name == "")),
        ):
            logger.info("Backfilling credentials for OAuth auth code %s", code.id)
            user_code = code.code or random_string_generator(AUTHORIZATION_CODE_PREFIX_LENGTH * 2)()
            code_name = user_code[:AUTHORIZATION_CODE_PREFIX_LENGTH]
            code_credential = Credential.from_string(user_code[AUTHORIZATION_CODE_PREFIX_LENGTH:])
            assert code_name
            assert user_code[AUTHORIZATION_CODE_PREFIX_LENGTH:]

            (
                OAuthAuthorizationCode.update(code_name=code_name, code_credential=code_credential)
                .where(OAuthAuthorizationCode.id == code.id)
                .execute()
            )

        assert (
            OAuthAuthorizationCode.select().where(OAuthAuthorizationCode.code_name >> None).count()
        ) == 0

        # OAuthApplication
        logger.info("Backfilling secret for OAuth applications")
        for app in _iterate(OAuthApplication, OAuthApplication.fully_migrated == False):
            logger.info("Backfilling secret for OAuth application %s", app.id)
            client_secret = app.client_secret or str(uuid.uuid4())
            secure_client_secret = _decrypted(client_secret)

            (
                OAuthApplication.update(
                    secure_client_secret=secure_client_secret, fully_migrated=True
                )
                .where(OAuthApplication.id == app.id, OAuthApplication.fully_migrated == False)
                .execute()
            )

        assert (
            OAuthApplication.select().where(OAuthApplication.fully_migrated == False).count()
        ) == 0

    # Adjust existing fields to be nullable.
    op.alter_column("accesstoken", "code", nullable=True, existing_type=sa.String(length=255))
    op.alter_column(
        "oauthaccesstoken", "access_token", nullable=True, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "oauthauthorizationcode", "code", nullable=True, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "appspecificauthtoken", "token_code", nullable=True, existing_type=sa.String(length=255)
    )

    # Adjust new fields to be non-nullable.
    op.alter_column(
        "accesstoken", "token_name", nullable=False, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "accesstoken", "token_code", nullable=False, existing_type=sa.String(length=255)
    )

    op.alter_column(
        "appspecificauthtoken", "token_name", nullable=False, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "appspecificauthtoken", "token_secret", nullable=False, existing_type=sa.String(length=255)
    )

    op.alter_column(
        "oauthaccesstoken", "token_name", nullable=False, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "oauthaccesstoken", "token_code", nullable=False, existing_type=sa.String(length=255)
    )

    op.alter_column(
        "oauthauthorizationcode", "code_name", nullable=False, existing_type=sa.String(length=255)
    )
    op.alter_column(
        "oauthauthorizationcode",
        "code_credential",
        nullable=False,
        existing_type=sa.String(length=255),
    )
Example #24
0
def upgrade(tables, tester, progress_reporter):
    op = ProgressWrapper(original_op, progress_reporter)

    # NOTE: Disconnects the Alembic database connection. We do this because the Peewee calls below
    # use a *different* connection, and if we leave the alembic connection open, it'll time out.
    # See: https://github.com/sqlalchemy/alembic/issues/630
    op.get_bind().execute("COMMIT")
    op.get_bind().invalidate()

    from app import app

    if app.config.get("SETUP_COMPLETE", False) or tester.is_testing():
        # AccessToken.
        logger.info("Backfilling encrypted credentials for access tokens")
        for access_token in _iterate(AccessToken,
                                     ((AccessToken.token_name >> None) |
                                      (AccessToken.token_name == ""))):
            logger.info(
                "Backfilling encrypted credentials for access token %s",
                access_token.id)
            assert access_token.code is not None
            assert access_token.code[:ACCESS_TOKEN_NAME_PREFIX_LENGTH]
            assert access_token.code[ACCESS_TOKEN_NAME_PREFIX_LENGTH:]

            token_name = access_token.code[:ACCESS_TOKEN_NAME_PREFIX_LENGTH]
            token_code = _decrypted(
                access_token.code[ACCESS_TOKEN_NAME_PREFIX_LENGTH:])

            (AccessToken.update(
                token_name=token_name, token_code=token_code).where(
                    AccessToken.id == access_token.id,
                    AccessToken.code == access_token.code).execute())

        assert AccessToken.select().where(
            AccessToken.token_name >> None).count() == 0

        # Robots.
        logger.info("Backfilling encrypted credentials for robots")
        while True:
            has_row = False
            query = (User.select().join(
                RobotAccountToken, JOIN.LEFT_OUTER).where(
                    User.robot == True,
                    RobotAccountToken.id >> None).limit(BATCH_SIZE))

            for robot_user in query:
                logger.info("Backfilling encrypted credentials for robot %s",
                            robot_user.id)
                has_row = True
                try:
                    RobotAccountToken.create(
                        robot_account=robot_user,
                        token=_decrypted(robot_user.email),
                        fully_migrated=False,
                    )
                except IntegrityError:
                    break

            if not has_row:
                break

        # RepositoryBuildTrigger
        logger.info(
            "Backfilling encrypted credentials for repo build triggers")
        for repo_build_trigger in _iterate(
                RepositoryBuildTrigger,
            (RepositoryBuildTrigger.fully_migrated == False)):
            logger.info(
                "Backfilling encrypted credentials for repo build trigger %s",
                repo_build_trigger.id)

            (RepositoryBuildTrigger.update(
                secure_auth_token=_decrypted(repo_build_trigger.auth_token),
                secure_private_key=_decrypted(repo_build_trigger.private_key),
                fully_migrated=True,
            ).where(
                RepositoryBuildTrigger.id == repo_build_trigger.id,
                RepositoryBuildTrigger.uuid == repo_build_trigger.uuid,
            ).execute())

        assert (RepositoryBuildTrigger.select().where(
            RepositoryBuildTrigger.fully_migrated == False).count()) == 0

        # AppSpecificAuthToken
        logger.info(
            "Backfilling encrypted credentials for app specific auth tokens")
        for token in _iterate(
                AppSpecificAuthToken,
            ((AppSpecificAuthToken.token_name >> None)
             | (AppSpecificAuthToken.token_name == "")
             | (AppSpecificAuthToken.token_secret >> None)),
        ):
            logger.info(
                "Backfilling encrypted credentials for app specific auth %s",
                token.id)
            assert token.token_code[AST_TOKEN_NAME_PREFIX_LENGTH:]

            token_name = token.token_code[:AST_TOKEN_NAME_PREFIX_LENGTH]
            token_secret = _decrypted(
                token.token_code[AST_TOKEN_NAME_PREFIX_LENGTH:])
            assert token_name
            assert token_secret

            (AppSpecificAuthToken.update(
                token_name=token_name, token_secret=token_secret).where(
                    AppSpecificAuthToken.id == token.id,
                    AppSpecificAuthToken.token_code == token.token_code,
                ).execute())

        assert (AppSpecificAuthToken.select().where(
            AppSpecificAuthToken.token_name >> None).count()) == 0

        # OAuthAccessToken
        logger.info("Backfilling credentials for OAuth access tokens")
        for token in _iterate(
                OAuthAccessToken,
            ((OAuthAccessToken.token_name >> None) |
             (OAuthAccessToken.token_name == "")),
        ):
            logger.info("Backfilling credentials for OAuth access token %s",
                        token.id)
            token_name = token.access_token[:OAUTH_ACCESS_TOKEN_PREFIX_LENGTH]
            token_code = Credential.from_string(
                token.access_token[OAUTH_ACCESS_TOKEN_PREFIX_LENGTH:])
            assert token_name
            assert token.access_token[OAUTH_ACCESS_TOKEN_PREFIX_LENGTH:]

            (OAuthAccessToken.update(
                token_name=token_name, token_code=token_code).where(
                    OAuthAccessToken.id == token.id,
                    OAuthAccessToken.access_token == token.access_token,
                ).execute())

        assert (OAuthAccessToken.select().where(
            OAuthAccessToken.token_name >> None).count()) == 0

        # OAuthAuthorizationCode
        logger.info("Backfilling credentials for OAuth auth code")
        for code in _iterate(
                OAuthAuthorizationCode,
            ((OAuthAuthorizationCode.code_name >> None) |
             (OAuthAuthorizationCode.code_name == "")),
        ):
            logger.info("Backfilling credentials for OAuth auth code %s",
                        code.id)
            user_code = code.code or random_string_generator(
                AUTHORIZATION_CODE_PREFIX_LENGTH * 2)()
            code_name = user_code[:AUTHORIZATION_CODE_PREFIX_LENGTH]
            code_credential = Credential.from_string(
                user_code[AUTHORIZATION_CODE_PREFIX_LENGTH:])
            assert code_name
            assert user_code[AUTHORIZATION_CODE_PREFIX_LENGTH:]

            (OAuthAuthorizationCode.update(
                code_name=code_name, code_credential=code_credential).where(
                    OAuthAuthorizationCode.id == code.id).execute())

        assert (OAuthAuthorizationCode.select().where(
            OAuthAuthorizationCode.code_name >> None).count()) == 0

        # OAuthApplication
        logger.info("Backfilling secret for OAuth applications")
        for app in _iterate(OAuthApplication,
                            OAuthApplication.fully_migrated == False):
            logger.info("Backfilling secret for OAuth application %s", app.id)
            client_secret = app.client_secret or str(uuid.uuid4())
            secure_client_secret = _decrypted(client_secret)

            (OAuthApplication.update(
                secure_client_secret=secure_client_secret,
                fully_migrated=True).where(
                    OAuthApplication.id == app.id,
                    OAuthApplication.fully_migrated == False).execute())

        assert (OAuthApplication.select().where(
            OAuthApplication.fully_migrated == False).count()) == 0
Example #25
0
def get_minimum_user_id():
    return User.select(fn.Min(User.id)).tuples().get()[0]
Example #26
0
def get_user_organizations(username):
    UserAlias = User.alias()
    return (User.select().distinct().join(Team).join(TeamMember).join(
        UserAlias, on=(UserAlias.id == TeamMember.user)).where(
            User.organization == True, UserAlias.username == username))
Example #27
0
 def has_users(self):
     return bool(list(User.select().limit(1)))
Example #28
0
def get_robot_count():
    return User.select().where(User.robot == True).count()
Example #29
0
 def is_valid(self):
     try:
         list(User.select().limit(1))
         return True
     except:
         return False
Example #30
0
def has_users():
    """
    Return false if no users in database yet
    """
    return bool(User.select().limit(1))