Example #1
0
    def get(self, orgname):
        """
        Return whether or not this org is allowed to create new private repositories.
        """
        permission = CreateRepositoryPermission(orgname)
        if permission.can():
            organization = model.organization.get_organization(orgname)
            private_repos = model.user.get_private_repo_count(
                organization.username)
            data = {"privateAllowed": False}

            if organization.stripe_id:
                cus = stripe.Customer.retrieve(organization.stripe_id)
                if cus.subscription:
                    repos_allowed = 0
                    plan = get_plan(cus.subscription.plan.id)
                    if plan:
                        repos_allowed = plan["privateRepos"]

                    data["privateAllowed"] = private_repos < repos_allowed

            if AdministerOrganizationPermission(orgname).can():
                data["privateCount"] = private_repos

            return data

        raise Unauthorized()
Example #2
0
    def post(self):
        """
        Create a new repository.
        """
        owner = get_authenticated_user()
        req = request.get_json()

        if owner is None and "namespace" not in "req":
            raise InvalidRequest(
                "Must provide a namespace or must be logged in.")

        namespace_name = req[
            "namespace"] if "namespace" in req else owner.username

        permission = CreateRepositoryPermission(namespace_name)
        if permission.can():
            repository_name = req["repository"]
            visibility = req["visibility"]

            if model.repo_exists(namespace_name, repository_name):
                raise request_error(message="Repository already exists")

            visibility = req["visibility"]
            if visibility == "private":
                check_allowed_private_repos(namespace_name)

            # Verify that the repository name is valid.
            if not REPOSITORY_NAME_REGEX.match(repository_name):
                raise InvalidRequest("Invalid repository name")

            kind = req.get("repo_kind", "image") or "image"
            created = model.create_repo(
                namespace_name,
                repository_name,
                owner,
                req["description"],
                visibility=visibility,
                repo_kind=kind,
            )
            if created is None:
                raise InvalidRequest("Could not create repository")

            log_action(
                "create_repo",
                namespace_name,
                {
                    "repo": repository_name,
                    "namespace": namespace_name
                },
                repo_name=repository_name,
            )
            return {
                "namespace": namespace_name,
                "name": repository_name,
                "kind": kind,
            }, 201

        raise Unauthorized()
Example #3
0
    def post(self):
        """Create a new repository."""
        owner = get_authenticated_user()
        req = request.get_json()

        if owner is None and 'namespace' not in 'req':
            raise InvalidRequest(
                'Must provide a namespace or must be logged in.')

        namespace_name = req[
            'namespace'] if 'namespace' in req else owner.username

        permission = CreateRepositoryPermission(namespace_name)
        if permission.can():
            repository_name = req['repository']
            visibility = req['visibility']

            if model.repo_exists(namespace_name, repository_name):
                raise request_error(message='Repository already exists')

            visibility = req['visibility']
            if visibility == 'private':
                check_allowed_private_repos(namespace_name)

            # Verify that the repository name is valid.
            if not REPOSITORY_NAME_REGEX.match(repository_name):
                raise InvalidRequest('Invalid repository name')

            kind = req.get('repo_kind', 'image') or 'image'
            model.create_repo(namespace_name,
                              repository_name,
                              owner,
                              req['description'],
                              visibility=visibility,
                              repo_kind=kind)

            log_action('create_repo',
                       namespace_name, {
                           'repo': repository_name,
                           'namespace': namespace_name
                       },
                       repo_name=repository_name)
            return {
                'namespace': namespace_name,
                'name': repository_name,
                'kind': kind,
            }, 201

        raise Unauthorized()
Example #4
0
def push(namespace, package_name):
    reponame = repo_name(namespace, package_name)

    if not REPOSITORY_NAME_REGEX.match(package_name):
        logger.debug("Found invalid repository name CNR push: %s", reponame)
        raise InvalidUsage("invalid repository name: %s" % reponame)

    values = request.get_json(force=True, silent=True) or {}
    private = values.get("visibility", "private")

    owner = get_authenticated_user()
    if not Package.exists(reponame):
        if not CreateRepositoryPermission(namespace).can():
            raise Forbidden(
                "Unauthorized access for: %s" % reponame,
                {
                    "package": reponame,
                    "scopes": ["create"]
                },
            )
        Package.create_repository(reponame, private, owner)
        logs_model.log_action("create_repo",
                              namespace,
                              repository_name=package_name)

    if not ModifyRepositoryPermission(namespace, package_name).can():
        raise Forbidden("Unauthorized access for: %s" % reponame, {
            "package": reponame,
            "scopes": ["push"]
        })

    if not "release" in values:
        raise InvalidUsage("Missing release")

    if not "media_type" in values:
        raise InvalidUsage("Missing media_type")

    if not "blob" in values:
        raise InvalidUsage("Missing blob")

    release_version = str(values["release"])
    media_type = values["media_type"]
    force = request.args.get("force", "false") == "true"

    blob = Blob(reponame, values["blob"])
    app_release = cnr_registry.push(
        reponame,
        release_version,
        media_type,
        blob,
        force,
        package_class=Package,
        user=owner,
        visibility=private,
    )
    logs_model.log_action("push_repo",
                          namespace,
                          repository_name=package_name,
                          metadata={"release": release_version})
    return jsonify(app_release)
Example #5
0
File: user.py Project: rrati/quay
    def org_view(o, user_admin=True):
        admin_org = AdministerOrganizationPermission(o.username)
        org_response = {
            "name": o.username,
            "avatar": avatar.get_data_for_org(o),
            "can_create_repo": CreateRepositoryPermission(o.username).can(),
            "public": o.username in app.config.get("PUBLIC_NAMESPACES", []),
        }

        if user_admin:
            org_response.update(
                {"is_org_admin": admin_org.can(), "preferred_namespace": not (o.stripe_id is None),}
            )

        return org_response
Example #6
0
    def org_view(o, user_admin=True):
        admin_org = AdministerOrganizationPermission(o.username)
        org_response = {
            'name': o.username,
            'avatar': avatar.get_data_for_org(o),
            'can_create_repo': CreateRepositoryPermission(o.username).can(),
            'public': o.username in app.config.get('PUBLIC_NAMESPACES', []),
        }

        if user_admin:
            org_response.update({
                'is_org_admin':
                admin_org.can(),
                'preferred_namespace':
                not (o.stripe_id is None),
            })

        return org_response
Example #7
0
def push(namespace, package_name):
  reponame = repo_name(namespace, package_name)

  if not REPOSITORY_NAME_REGEX.match(package_name):
    logger.debug('Found invalid repository name CNR push: %s', reponame)
    raise InvalidUsage('invalid repository name: %s' % reponame)

  values = request.get_json(force=True, silent=True) or {}
  private = values.get('visibility', 'private')

  owner = get_authenticated_user()
  if not Package.exists(reponame):
    if not CreateRepositoryPermission(namespace).can():
      raise Forbidden("Unauthorized access for: %s" % reponame,
                      {"package": reponame,
                       "scopes": ['create']})
    Package.create_repository(reponame, private, owner)
    logs_model.log_action('create_repo', namespace, repository_name=package_name)

  if not ModifyRepositoryPermission(namespace, package_name).can():
    raise Forbidden("Unauthorized access for: %s" % reponame,
                    {"package": reponame,
                     "scopes": ['push']})

  if not 'release' in values:
    raise InvalidUsage('Missing release')

  if not 'media_type' in values:
    raise InvalidUsage('Missing media_type')

  if not 'blob' in values:
    raise InvalidUsage('Missing blob')

  release_version = str(values['release'])
  media_type = values['media_type']
  force = request.args.get('force', 'false') == 'true'

  blob = Blob(reponame, values['blob'])
  app_release = cnr_registry.push(reponame, release_version, media_type, blob, force,
                                  package_class=Package, user=owner, visibility=private)
  logs_model.log_action('push_repo', namespace, repository_name=package_name,
                        metadata={'release': release_version})
  return jsonify(app_release)
Example #8
0
def create_repository(namespace_name, repo_name):
    # Verify that the repository name is valid.
    if not REPOSITORY_NAME_REGEX.match(repo_name):
        abort(
            400,
            message=
            "Invalid repository name. Repository names cannot contain slashes."
        )

    logger.debug("Looking up repository %s/%s", namespace_name, repo_name)
    repository_ref = registry_model.lookup_repository(namespace_name,
                                                      repo_name)
    if repository_ref is None and get_authenticated_user() is None:
        logger.debug("Attempt to create repository %s/%s without user auth",
                     namespace_name, repo_name)
        abort(
            401,
            message=
            'Cannot create a repository as a guest. Please login via "docker login" first.',
            issue="no-login",
        )
    elif repository_ref:
        modify_perm = ModifyRepositoryPermission(namespace_name, repo_name)
        if not modify_perm.can():
            abort(
                403,
                message=
                "You do not have permission to modify repository %(namespace)s/%(repository)s",
                issue="no-repo-write-permission",
                namespace=namespace_name,
                repository=repo_name,
            )
        elif repository_ref.kind != "image":
            msg = (
                "This repository is for managing %s resources and not container images."
                % repository_ref.kind)
            abort(405, message=msg, namespace=namespace_name)
    else:
        create_perm = CreateRepositoryPermission(namespace_name)
        if not create_perm.can():
            logger.warning(
                "Attempt to create a new repo %s/%s with insufficient perms",
                namespace_name,
                repo_name,
            )
            msg = 'You do not have permission to create repositories in namespace "%(namespace)s"'
            abort(403,
                  message=msg,
                  issue="no-create-permission",
                  namespace=namespace_name)

        # Attempt to create the new repository.
        logger.debug(
            "Creating repository %s/%s with owner: %s",
            namespace_name,
            repo_name,
            get_authenticated_user().username,
        )

        repository_ref = model.repository.create_repository(
            namespace_name, repo_name, get_authenticated_user())

    if get_authenticated_user():
        user_event_data = {
            "action": "push_start",
            "repository": repo_name,
            "namespace": namespace_name,
        }

        event = userevents.get_event(get_authenticated_user().username)
        event.publish_event_data("docker-cli", user_event_data)

    # Start a new builder for the repository and save its ID in the session.
    assert repository_ref
    builder = create_manifest_builder(repository_ref, storage,
                                      docker_v2_signing_key)
    logger.debug("Started repo push with manifest builder %s", builder)
    if builder is None:
        abort(404, message="Unknown repository", issue="unknown-repo")

    session["manifest_builder"] = builder.builder_id
    return make_response("Created", 201)
Example #9
0
def _authorize_or_downscope_request(scope_param, has_valid_auth_context):
    # TODO: The complexity of this function is difficult to follow and maintain. Refactor/Cleanup.
    if len(scope_param) == 0:
        if not has_valid_auth_context:
            # In this case, we are doing an auth flow, and it's not an anonymous pull.
            logger.debug("No user and no token sent for empty scope list")
            raise Unauthorized()

        return None

    match = _get_scope_regex().match(scope_param)
    if match is None:
        logger.debug("Match: %s", match)
        logger.debug("len: %s", len(scope_param))
        logger.warning("Unable to decode repository and actions: %s",
                       scope_param)
        raise InvalidRequest("Unable to decode repository and actions: %s" %
                             scope_param)

    logger.debug("Match: %s", match.groups())

    registry_and_repo = match.group(1)
    namespace_and_repo = match.group(2)
    requested_actions = match.group(3).split(",")

    lib_namespace = app.config["LIBRARY_NAMESPACE"]
    namespace, reponame = parse_namespace_repository(namespace_and_repo,
                                                     lib_namespace)

    # Ensure that we are never creating an invalid repository.
    if not REPOSITORY_NAME_REGEX.match(reponame):
        logger.debug("Found invalid repository name in auth flow: %s",
                     reponame)
        if len(namespace_and_repo.split("/")) > 1:
            msg = "Nested repositories are not supported. Found: %s" % namespace_and_repo
            raise NameInvalid(message=msg)

        raise NameInvalid(message="Invalid repository name: %s" %
                          namespace_and_repo)

    # Ensure the namespace is enabled.
    if registry_model.is_existing_disabled_namespace(namespace):
        msg = "Namespace %s has been disabled. Please contact a system administrator." % namespace
        raise NamespaceDisabled(message=msg)

    final_actions = []

    repository_ref = registry_model.lookup_repository(namespace, reponame)
    repo_is_public = repository_ref is not None and repository_ref.is_public
    invalid_repo_message = ""
    if repository_ref is not None and repository_ref.kind != "image":
        invalid_repo_message = (
            "This repository is for managing %s " +
            "and not container images.") % repository_ref.kind

    # Ensure the repository is not marked for deletion.
    if repository_ref is not None and repository_ref.state == RepositoryState.MARKED_FOR_DELETION:
        raise Unknown(message="Unknown repository")

    if "push" in requested_actions:
        # Check if there is a valid user or token, as otherwise the repository cannot be
        # accessed.
        if has_valid_auth_context:
            user = get_authenticated_user()

            # Lookup the repository. If it exists, make sure the entity has modify
            # permission. Otherwise, make sure the entity has create permission.
            if repository_ref:
                if ModifyRepositoryPermission(namespace, reponame).can():
                    if repository_ref is not None and repository_ref.kind != "image":
                        raise Unsupported(message=invalid_repo_message)

                    # Check for different repository states.
                    if repository_ref.state == RepositoryState.NORMAL:
                        # In NORMAL mode, if the user has permission, then they can push.
                        final_actions.append("push")
                    elif repository_ref.state == RepositoryState.MIRROR:
                        # In MIRROR mode, only the mirroring robot can push.
                        mirror = model.repo_mirror.get_mirror(
                            repository_ref.id)
                        robot = mirror.internal_robot if mirror is not None else None
                        if robot is not None and user is not None and robot == user:
                            assert robot.robot
                            final_actions.append("push")
                        else:
                            logger.debug(
                                "Repository %s/%s push requested for non-mirror robot %s: %s",
                                namespace,
                                reponame,
                                robot,
                                user,
                            )
                    elif repository_ref.state == RepositoryState.READ_ONLY:
                        # No pushing allowed in read-only state.
                        pass
                    else:
                        logger.warning(
                            "Unknown state for repository %s: %s",
                            repository_ref,
                            repository_ref.state,
                        )
                else:
                    logger.debug("No permission to modify repository %s/%s",
                                 namespace, reponame)
            else:
                # TODO: Push-to-create functionality should be configurable
                if CreateRepositoryPermission(
                        namespace).can() and user is not None:
                    logger.debug("Creating repository: %s/%s", namespace,
                                 reponame)
                    repository_ref = RepositoryReference.for_repo_obj(
                        model.repository.create_repository(
                            namespace, reponame, user))
                    final_actions.append("push")
                else:
                    logger.debug("No permission to create repository %s/%s",
                                 namespace, reponame)

    if "pull" in requested_actions:
        # Grant pull if the user can read the repo or it is public.
        if ReadRepositoryPermission(namespace,
                                    reponame).can() or repo_is_public:
            if repository_ref is not None and repository_ref.kind != "image":
                raise Unsupported(message=invalid_repo_message)

            final_actions.append("pull")
        else:
            logger.debug("No permission to pull repository %s/%s", namespace,
                         reponame)

    if "*" in requested_actions:
        # Grant * user is admin
        if AdministerRepositoryPermission(namespace, reponame).can():
            if repository_ref is not None and repository_ref.kind != "image":
                raise Unsupported(message=invalid_repo_message)

            if repository_ref and repository_ref.state in (
                    RepositoryState.MIRROR,
                    RepositoryState.READ_ONLY,
            ):
                logger.debug("No permission to administer repository %s/%s",
                             namespace, reponame)
            else:
                assert repository_ref.state == RepositoryState.NORMAL
                final_actions.append("*")
        else:
            logger.debug("No permission to administer repository %s/%s",
                         namespace, reponame)

    # Final sanity checks.
    if "push" in final_actions:
        assert repository_ref.state != RepositoryState.READ_ONLY

    if "*" in final_actions:
        assert repository_ref.state == RepositoryState.NORMAL

    return scopeResult(
        actions=final_actions,
        namespace=namespace,
        repository=reponame,
        registry_and_repo=registry_and_repo,
        tuf_root=_get_tuf_root(repository_ref, namespace, reponame),
    )