Commit ec3150db authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 221b1159d254
---
title: Authenticate runner requests in Rack::Attack
merge_request: 21311
author:
type: fixed
---
title: Add service desk information to project graphQL endpoint
merge_request: 20722
author:
type: changed
---
title: Autofocus cluster dropdown search input
merge_request: 21440
author:
type: changed
---
title: Add OmniAuth authentication support to admin mode feature
merge_request: 18214
author: Diego Louzán
type: added
......@@ -113,11 +113,15 @@ class Rack::Attack
class Request
def unauthenticated?
!authenticated_user_id([:api, :rss, :ics])
!(authenticated_user_id([:api, :rss, :ics]) || authenticated_runner_id)
end
def authenticated_user_id(request_formats)
Gitlab::Auth::RequestAuthenticator.new(self).user(request_formats)&.id
request_authenticator.user(request_formats)&.id
end
def authenticated_runner_id
request_authenticator.runner&.id
end
def api_request?
......@@ -150,6 +154,10 @@ def protected_path_regex
private
def request_authenticator
@request_authenticator ||= Gitlab::Auth::RequestAuthenticator.new(self)
end
def protected_paths
Gitlab::CurrentSettings.current_application_settings.protected_paths
end
......
# frozen_string_literal: true
class CreateContainerExpirationPolicies < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
create_table :container_expiration_policies, id: false, primary_key: :project_id do |t|
t.timestamps_with_timezone null: false
t.datetime_with_timezone :next_run_at
t.references :project, primary_key: true, default: nil, index: false, foreign_key: { on_delete: :cascade }
t.string :name_regex, limit: 255
t.string :cadence, null: false, limit: 12, default: '7d'
t.string :older_than, limit: 12
t.integer :keep_n
t.boolean :enabled, null: false, default: false
end
add_index :container_expiration_policies, [:next_run_at, :enabled],
name: 'index_container_expiration_policies_on_next_run_at_and_enabled'
end
end
......@@ -1224,6 +1224,18 @@
t.index ["note_id"], name: "index_commit_user_mentions_on_note_id", unique: true
end
create_table "container_expiration_policies", primary_key: "project_id", id: :bigint, default: nil, force: :cascade do |t|
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.datetime_with_timezone "next_run_at"
t.string "name_regex", limit: 255
t.string "cadence", limit: 12, default: "7d", null: false
t.string "older_than", limit: 12
t.integer "keep_n"
t.boolean "enabled", default: false, null: false
t.index ["next_run_at", "enabled"], name: "index_container_expiration_policies_on_next_run_at_and_enabled"
end
create_table "container_repositories", id: :serial, force: :cascade do |t|
t.integer "project_id", null: false
t.string "name", null: false
......@@ -4410,6 +4422,7 @@
add_foreign_key "clusters_kubernetes_namespaces", "environments", on_delete: :nullify
add_foreign_key "clusters_kubernetes_namespaces", "projects", on_delete: :nullify
add_foreign_key "commit_user_mentions", "notes", on_delete: :cascade
add_foreign_key "container_expiration_policies", "projects", on_delete: :cascade
add_foreign_key "container_repositories", "projects"
add_foreign_key "dependency_proxy_blobs", "namespaces", column: "group_id", on_delete: :cascade
add_foreign_key "dependency_proxy_group_settings", "namespaces", column: "group_id", on_delete: :cascade
......
......@@ -155,8 +155,8 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
| `postgresql['md5_auth_cidr_addresses']` | **Secondary** node's public or VPC private addresses. |
If you are using Google Cloud Platform, SoftLayer, or any other vendor that
provides a virtual private cloud (VPC) you can use the **secondary** node's private
address (corresponds to "internal address" for Google Cloud Platform) for
provides a virtual private cloud (VPC) you can use the **primary** and **secondary** nodes
private addresses (corresponds to "internal address" for Google Cloud Platform) for
`postgresql['md5_auth_cidr_addresses']` and `postgresql['listen_address']`.
The `listen_address` option opens PostgreSQL up to network connections with the interface
......
......@@ -4551,6 +4551,16 @@ type Project {
id: ID!
): SentryDetailedError
"""
E-mail address of the service desk.
"""
serviceDeskAddress: String
"""
Indicates if the project has service desk enabled.
"""
serviceDeskEnabled: Boolean
"""
Indicates if shared runners are enabled on the project
"""
......
......@@ -1314,6 +1314,34 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "serviceDeskAddress",
"description": "E-mail address of the service desk.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "serviceDeskEnabled",
"description": "Indicates if the project has service desk enabled.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "sharedRunnersEnabled",
"description": "Indicates if shared runners are enabled on the project",
......
......@@ -668,6 +668,8 @@ The API can be explored interactively using the [GraphiQL IDE](../index.md#graph
| `mergeRequest` | MergeRequest | A single merge request of the project |
| `issue` | Issue | A single issue of the project |
| `sentryDetailedError` | SentryDetailedError | Detailed version of a Sentry error on the project |
| `serviceDeskEnabled` | Boolean | Indicates if the project has service desk enabled. |
| `serviceDeskAddress` | String | E-mail address of the service desk. |
### ProjectPermissions
......
......@@ -2,7 +2,7 @@
## List project jobs
Get a list of jobs in a project.
Get a list of jobs in a project. Jobs are sorted in descending order of their IDs.
```
GET /projects/:id/jobs
......@@ -33,13 +33,23 @@ Example of response
},
"coverage": null,
"allow_failure": false,
"created_at": "2015-12-24T15:51:21.727Z",
"started_at": "2015-12-24T17:54:24.729Z",
"finished_at": "2015-12-24T17:54:24.921Z",
"duration": 0.192,
"artifacts_expire_at": "2016-01-23T17:54:24.921Z",
"id": 6,
"name": "rspec:other",
"created_at": "2015-12-24T15:51:21.802Z",
"started_at": "2015-12-24T17:54:27.722Z",
"finished_at": "2015-12-24T17:54:27.895Z",
"duration": 0.173,
"artifacts_file": {
"filename": "artifacts.zip",
"size": 1000
},
"artifacts": [
{"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"},
{"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"},
{"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"},
{"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"}
],
"artifacts_expire_at": "2016-01-23T17:54:27.895Z",
"id": 7,
"name": "teaspoon",
"pipeline": {
"id": 6,
"ref": "master",
......@@ -52,7 +62,7 @@ Example of response
"stage": "test",
"status": "failed",
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/6",
"web_url": "https://example.com/foo/bar/-/jobs/7",
"user": {
"id": 1,
"name": "Administrator",
......@@ -83,23 +93,13 @@ Example of response
},
"coverage": null,
"allow_failure": false,
"created_at": "2015-12-24T15:51:21.802Z",
"started_at": "2015-12-24T17:54:27.722Z",
"finished_at": "2015-12-24T17:54:27.895Z",
"duration": 0.173,
"artifacts_file": {
"filename": "artifacts.zip",
"size": 1000
},
"artifacts": [
{"file_type": "archive", "size": 1000, "filename": "artifacts.zip", "file_format": "zip"},
{"file_type": "metadata", "size": 186, "filename": "metadata.gz", "file_format": "gzip"},
{"file_type": "trace", "size": 1500, "filename": "job.log", "file_format": "raw"},
{"file_type": "junit", "size": 750, "filename": "junit.xml.gz", "file_format": "gzip"}
],
"artifacts_expire_at": "2016-01-23T17:54:27.895Z",
"id": 7,
"name": "teaspoon",
"created_at": "2015-12-24T15:51:21.727Z",
"started_at": "2015-12-24T17:54:24.729Z",
"finished_at": "2015-12-24T17:54:24.921Z",
"duration": 0.192,
"artifacts_expire_at": "2016-01-23T17:54:24.921Z",
"id": 6,
"name": "rspec:other",
"pipeline": {
"id": 6,
"ref": "master",
......@@ -112,7 +112,7 @@ Example of response
"stage": "test",
"status": "failed",
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7",
"web_url": "https://example.com/foo/bar/-/jobs/6",
"user": {
"id": 1,
"name": "Administrator",
......
......@@ -44,7 +44,7 @@ def allowed_scopes
# Helper Methods for Grape Endpoint
module HelperMethods
prepend_if_ee('EE::API::APIGuard::HelperMethods') # rubocop: disable Cop/InjectEnterpriseEditionModule
include Gitlab::Auth::UserAuthFinders
include Gitlab::Auth::AuthFinders
def find_current_user!
user = find_user_from_sources
......@@ -56,7 +56,9 @@ def find_current_user!
# Set admin mode for API requests (if admin)
if Feature.enabled?(:user_mode_in_session)
Gitlab::Auth::CurrentUserMode.new(user).enable_admin_mode!(skip_password_validation: true)
current_user_mode = Gitlab::Auth::CurrentUserMode.new(user)
current_user_mode.enable_sessionless_admin_mode!
end
user
......
......@@ -17,8 +17,8 @@ def initialize(scopes)
end
end
module UserAuthFinders
prepend_if_ee('::EE::Gitlab::Auth::UserAuthFinders') # rubocop: disable Cop/InjectEnterpriseEditionModule
module AuthFinders
prepend_if_ee('::EE::Gitlab::Auth::AuthFinders') # rubocop: disable Cop/InjectEnterpriseEditionModule
include Gitlab::Utils::StrongMemoize
......@@ -26,6 +26,7 @@ module UserAuthFinders
PRIVATE_TOKEN_PARAM = :private_token
JOB_TOKEN_HEADER = "HTTP_JOB_TOKEN".freeze
JOB_TOKEN_PARAM = :job_token
RUNNER_TOKEN_PARAM = :token
# Check the Rails session for valid authentication details
def find_user_from_warden
......@@ -85,6 +86,15 @@ def find_user_from_access_token
access_token.user || raise(UnauthorizedError)
end
def find_runner_from_token
return unless api_request?
token = current_request.params[RUNNER_TOKEN_PARAM].presence
return unless token
::Ci::Runner.find_by_token(token) || raise(UnauthorizedError)
end
def validate_access_token!(scopes: [])
return unless access_token
......@@ -201,7 +211,7 @@ def ics_request?
end
def api_request?
current_request.path.starts_with?("/api/")
current_request.path.starts_with?('/api/')
end
def archive_request?
......
......@@ -8,9 +8,13 @@ module Auth
# an administrator must have explicitly enabled admin-mode
# e.g. on web access require re-authentication
class CurrentUserMode
NotRequestedError = Class.new(StandardError)
SESSION_STORE_KEY = :current_user_mode
ADMIN_MODE_START_TIME_KEY = 'admin_mode'
ADMIN_MODE_REQUESTED_TIME_KEY = 'admin_mode_requested'
MAX_ADMIN_MODE_TIME = 6.hours
ADMIN_MODE_REQUESTED_GRACE_PERIOD = 5.minutes
def initialize(user)
@user = user
......@@ -19,8 +23,16 @@ def initialize(user)
def admin_mode?
return false unless user
Gitlab::SafeRequestStore.fetch(request_store_key) do
user&.admin? && any_session_with_admin_mode?
Gitlab::SafeRequestStore.fetch(admin_mode_rs_key) do
user.admin? && any_session_with_admin_mode?
end
end
def admin_mode_requested?
return false unless user
Gitlab::SafeRequestStore.fetch(admin_mode_requested_rs_key) do
user.admin? && admin_mode_requested_in_grace_period?
end
end
......@@ -28,20 +40,45 @@ def enable_admin_mode!(password: nil, skip_password_validation: false)
return unless user&.admin?
return unless skip_password_validation || user&.valid_password?(password)
raise NotRequestedError unless admin_mode_requested?
reset_request_store
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil
current_session_data[ADMIN_MODE_START_TIME_KEY] = Time.now
end
def enable_sessionless_admin_mode!
request_admin_mode! && enable_admin_mode!(skip_password_validation: true)
end
def disable_admin_mode!
return unless user&.admin?
reset_request_store
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = nil
current_session_data[ADMIN_MODE_START_TIME_KEY] = nil
Gitlab::SafeRequestStore.delete(request_store_key)
end
def request_admin_mode!
return unless user&.admin?
reset_request_store
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY] = Time.now
end
private
attr_reader :user
def request_store_key
@request_store_key ||= { res: :current_user_mode, user: user.id }
def admin_mode_rs_key
@admin_mode_rs_key ||= { res: :current_user_mode, user: user.id, method: :admin_mode? }
end
def admin_mode_requested_rs_key
@admin_mode_requested_rs_key ||= { res: :current_user_mode, user: user.id, method: :admin_mode_requested? }
end
def current_session_data
......@@ -61,6 +98,15 @@ def all_sessions
Gitlab::NamespacedSessionStore.new(SESSION_STORE_KEY, session.with_indifferent_access )
end
end
def admin_mode_requested_in_grace_period?
current_session_data[ADMIN_MODE_REQUESTED_TIME_KEY].to_i > ADMIN_MODE_REQUESTED_GRACE_PERIOD.ago.to_i
end
def reset_request_store
Gitlab::SafeRequestStore.delete(admin_mode_rs_key)
Gitlab::SafeRequestStore.delete(admin_mode_requested_rs_key)
end
end
end
end
......@@ -5,7 +5,7 @@
module Gitlab
module Auth
class RequestAuthenticator
include UserAuthFinders
include AuthFinders
attr_reader :request
......@@ -23,6 +23,12 @@ def user(request_formats)
find_user_from_warden
end
def runner
find_runner_from_token
rescue Gitlab::Auth::AuthenticationError
nil
end
def find_sessionless_user(request_format)
find_user_from_web_access_token(request_format) ||
find_user_from_feed_token(request_format) ||
......
......@@ -73,6 +73,7 @@ tree:
- :auto_devops
- :triggers
- :pipeline_schedules
- :container_expiration_policy
- :services
- protected_branches:
- :merge_access_levels
......
......@@ -234,6 +234,9 @@ msgstr[1] ""
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
msgid "%{days} days until tags are automatically removed"
msgstr ""
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr ""
......@@ -380,6 +383,12 @@ msgstr[1] ""
msgid "%{tabname} changed"
msgstr ""
msgid "%{tags} tag per image name"
msgstr ""
msgid "%{tags} tags per image name"
msgstr ""
msgid "%{tag}-evidence.json"
msgstr ""
......@@ -1134,9 +1143,15 @@ msgstr ""
msgid "Admin Section"
msgstr ""
msgid "Admin mode already enabled"
msgstr ""
msgid "Admin mode disabled"
msgstr ""
msgid "Admin mode enabled"
msgstr ""
msgid "Admin notes"
msgstr ""
......@@ -7050,12 +7065,27 @@ msgstr ""
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
msgid "Every day"
msgstr ""
msgid "Every day (at 4:00am)"
msgstr ""
msgid "Every month"
msgstr ""
msgid "Every month (on the 1st at 4:00am)"
msgstr ""
msgid "Every three months"
msgstr ""
msgid "Every two weeks"
msgstr ""
msgid "Every week"
msgstr ""
msgid "Every week (Sundays at 4:00am)"
msgstr ""
......@@ -9678,6 +9708,9 @@ msgstr ""
msgid "Invalid input, please avoid emojis"
msgstr ""
msgid "Invalid login or password"
msgstr ""
msgid "Invalid pin code"
msgstr ""
......@@ -14397,6 +14430,9 @@ msgstr ""
msgid "Raw blob request rate limit per minute"
msgstr ""
msgid "Re-authentication period expired or never requested. Please try again"
msgstr ""
msgid "Re-authentication required"
msgstr ""
......
tmp/
.ruby-version
.ruby-gemset
urls.yml
......@@ -35,6 +35,7 @@ module Runtime
autoload :Logger, 'qa/runtime/logger'
autoload :GPG, 'qa/runtime/gpg'
autoload :MailHog, 'qa/runtime/mail_hog'
autoload :IPAddress, 'qa/runtime/ip_address'
module API
autoload :Client, 'qa/runtime/api/client'
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment