Example #1
0
def create_user():
    user_data = request.get_json()
    if not user_data or not "username" in user_data:
        abort(400, "Missing username")

    username = user_data["username"]
    password = user_data.get("password", "")

    # UGH! we have to use this response when the login actually worked, in order
    # to get the CLI to try again with a get, and then tell us login succeeded.
    success = make_response('"Username or email already exists"', 400)
    result, kind = validate_credentials(username, password)
    if not result.auth_valid:
        if kind == CredentialKind.token:
            abort(400, "Invalid access token.", issue="invalid-access-token")

        if kind == CredentialKind.robot:
            abort(400,
                  "Invalid robot account or password.",
                  issue="robot-login-failure")

        if kind == CredentialKind.oauth_token:
            abort(400,
                  "Invalid oauth access token.",
                  issue="invalid-oauth-access-token")

        if kind == CredentialKind.user:
            # Mark that the login failed.
            event = userevents.get_event(username)
            event.publish_event_data("docker-cli", {"action": "loginfailure"})
            abort(400, result.error_message, issue="login-failure")

        # Default case: Just fail.
        abort(400, result.error_message, issue="login-failure")

    if result.has_nonrobot_user:
        # Mark that the user was logged in.
        event = userevents.get_event(username)
        event.publish_event_data("docker-cli", {"action": "login"})

    return success
Example #2
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 #3
0
def generate_registry_jwt(auth_result):
    """
    This endpoint will generate a JWT conforming to the Docker Registry v2 Auth Spec:

    https://docs.docker.com/registry/spec/auth/token/
    """
    audience_param = request.args.get("service")
    logger.debug("Request audience: %s", audience_param)

    scope_params = request.args.getlist("scope") or []
    logger.debug("Scope request: %s", scope_params)

    auth_header = request.headers.get("authorization", "")
    auth_credentials_sent = bool(auth_header)

    # Load the auth context and verify thatg we've directly received credentials.
    has_valid_auth_context = False
    if get_authenticated_context():
        has_valid_auth_context = not get_authenticated_context().is_anonymous

    if auth_credentials_sent and not has_valid_auth_context:
        # The auth credentials sent for the user are invalid.
        raise InvalidLogin(auth_result.error_message)

    if not has_valid_auth_context and len(scope_params) == 0:
        # 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()

    # Build the access list for the authenticated context.
    access = []
    scope_results = []
    for scope_param in scope_params:
        scope_result = _authorize_or_downscope_request(scope_param,
                                                       has_valid_auth_context)
        if scope_result is None:
            continue

        scope_results.append(scope_result)
        access.append({
            "type": "repository",
            "name": scope_result.registry_and_repo,
            "actions": scope_result.actions,
        })

    # Issue user events.
    user_event_data = {
        "action": "login",
    }

    # Set the user event data for when authed.
    if len(scope_results) > 0:
        if "push" in scope_results[0].actions:
            user_action = "push_start"
        elif "pull" in scope_results[0].actions:
            user_action = "pull_start"
        else:
            user_action = "login"

        user_event_data = {
            "action": user_action,
            "namespace": scope_results[0].namespace,
            "repository": scope_results[0].repository,
        }

    # Send the user event.
    if get_authenticated_user() is not None:
        event = userevents.get_event(get_authenticated_user().username)
        event.publish_event_data("docker-cli", user_event_data)

    # Build the signed JWT.
    tuf_roots = {
        "%s/%s" % (scope_result.namespace, scope_result.repository):
        scope_result.tuf_root
        for scope_result in scope_results
    }
    context, subject = build_context_and_subject(get_authenticated_context(),
                                                 tuf_roots=tuf_roots)
    token = generate_bearer_token(audience_param, subject, context, access,
                                  TOKEN_VALIDITY_LIFETIME_S, instance_keys)
    return jsonify({"token": token})
Example #4
0
def user_test():
    evt = userevents.get_event(current_user.db_user().username)
    evt.publish_event_data("test", {"foo": 2})
    return "OK"
Example #5
0
def track_and_log(event_name,
                  repo_obj,
                  analytics_name=None,
                  analytics_sample=1,
                  **kwargs):
    repo_name = repo_obj.name
    namespace_name = repo_obj.namespace_name
    metadata = {
        "repo": repo_name,
        "namespace": namespace_name,
        "user-agent": request.user_agent.string,
    }
    metadata.update(kwargs)

    is_free_namespace = False
    if hasattr(repo_obj, "is_free_namespace"):
        is_free_namespace = repo_obj.is_free_namespace

    # Add auth context metadata.
    analytics_id = "anonymous"
    auth_context = get_authenticated_context()
    if auth_context is not None:
        analytics_id, context_metadata = auth_context.analytics_id_and_public_metadata(
        )
        metadata.update(context_metadata)

    # Publish the user event (if applicable)
    logger.debug("Checking publishing %s to the user events system",
                 event_name)
    if auth_context and auth_context.has_nonrobot_user:
        logger.debug("Publishing %s to the user events system", event_name)
        user_event_data = {
            "action": event_name,
            "repository": repo_name,
            "namespace": namespace_name,
        }

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

    # Save the action to mixpanel.
    if random.random() < analytics_sample:
        if analytics_name is None:
            analytics_name = event_name

        logger.debug("Logging the %s to analytics engine", analytics_name)

        request_parsed = urlparse(request.url_root)
        extra_params = {
            "repository": "%s/%s" % (namespace_name, repo_name),
            "user-agent": request.user_agent.string,
            "hostname": request_parsed.hostname,
        }

        analytics.track(analytics_id, analytics_name, extra_params)

    # Add the resolved information to the metadata.
    logger.debug("Resolving IP address %s", get_request_ip())
    resolved_ip = ip_resolver.resolve_ip(get_request_ip())
    if resolved_ip is not None:
        metadata["resolved_ip"] = resolved_ip._asdict()

    logger.debug("Resolved IP address %s", get_request_ip())

    # Log the action to the database.
    logger.debug("Logging the %s to logs system", event_name)
    try:
        logs_model.log_action(
            event_name,
            namespace_name,
            performer=get_authenticated_user(),
            ip=get_request_ip(),
            metadata=metadata,
            repository=repo_obj,
            is_free_namespace=is_free_namespace,
        )
        logger.debug("Track and log of %s complete", event_name)
    except ReadOnlyModeException:
        pass
Example #6
0
def user_test():
  evt = userevents.get_event(current_user.db_user().username)
  evt.publish_event_data('test', {'foo': 2})
  return 'OK'