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
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)
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})
def user_test(): evt = userevents.get_event(current_user.db_user().username) evt.publish_event_data("test", {"foo": 2}) return "OK"
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
def user_test(): evt = userevents.get_event(current_user.db_user().username) evt.publish_event_data('test', {'foo': 2}) return 'OK'