Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8b3335043e
commit
8c16344efe
|
|
@ -61,7 +61,6 @@ Gitlab/FeatureFlagWithoutActor:
|
|||
- 'app/views/admin/application_settings/_invitation_flow_enforcement.html.haml'
|
||||
- 'app/views/admin/application_settings/general.html.haml'
|
||||
- 'app/views/admin/projects/show.html.haml'
|
||||
- 'app/views/authentication/_register.html.haml'
|
||||
- 'app/views/devise/shared/_language_switcher.html.haml'
|
||||
- 'app/views/explore/projects/_projects.html.haml'
|
||||
- 'app/views/layouts/notify.html.haml'
|
||||
|
|
|
|||
|
|
@ -19,8 +19,28 @@ const apolloClient = createDefaultClient(
|
|||
const graphiqlContainer = document.getElementById('graphiql-container');
|
||||
|
||||
function apolloFetcher(graphQLParams) {
|
||||
let query = gql(graphQLParams.query);
|
||||
|
||||
/*
|
||||
GraphiQL allows multiple named operations to be declared in the editor.
|
||||
When the user clicks execute, they are prompted to select one of the operations.
|
||||
We must filter the query to only contain the selected operation so we execute the correct query
|
||||
and avoid an `Ambiguous GraphQL document: contains 2 operations` error.
|
||||
*/
|
||||
if (graphQLParams.operationName) {
|
||||
query = {
|
||||
...query,
|
||||
definitions: query.definitions.filter((definition) => {
|
||||
return (
|
||||
definition.kind !== 'OperationDefinition' ||
|
||||
definition.name.value === graphQLParams.operationName
|
||||
);
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
return apolloClient.subscribe({
|
||||
query: gql(graphQLParams.query),
|
||||
query,
|
||||
variables: graphQLParams.variables,
|
||||
operationName: graphQLParams.operationName,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
|||
::Users::ValidateManualOtpService.new(current_user).execute(params[:pin_code])
|
||||
validated = (otp_validation_result[:status] == :success)
|
||||
|
||||
if validated && current_user.otp_backup_codes? && Feature.enabled?(:webauthn_without_totp)
|
||||
if validated && current_user.otp_backup_codes?
|
||||
ActiveSession.destroy_all_but_current(current_user, session)
|
||||
Users::UpdateService.new(current_user, user: current_user, otp_required_for_login: true).execute!
|
||||
redirect_to profile_two_factor_auth_path, notice: _("Your Time-based OTP device was registered!")
|
||||
|
|
@ -50,21 +50,16 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
|||
if @webauthn_registration.persisted?
|
||||
session.delete(:challenge)
|
||||
|
||||
if Feature.enabled?(:webauthn_without_totp)
|
||||
|
||||
if current_user.otp_backup_codes?
|
||||
redirect_to profile_two_factor_auth_path, notice: notice
|
||||
else
|
||||
|
||||
Users::UpdateService.new(current_user, user: current_user).execute! do |user|
|
||||
@codes = current_user.generate_otp_backup_codes!
|
||||
end
|
||||
helpers.dismiss_two_factor_auth_recovery_settings_check
|
||||
flash[:notice] = notice
|
||||
render 'create'
|
||||
end
|
||||
else
|
||||
if current_user.otp_backup_codes?
|
||||
redirect_to profile_two_factor_auth_path, notice: notice
|
||||
else
|
||||
|
||||
Users::UpdateService.new(current_user, user: current_user).execute! do |user|
|
||||
@codes = current_user.generate_otp_backup_codes!
|
||||
end
|
||||
helpers.dismiss_two_factor_auth_recovery_settings_check
|
||||
flash[:notice] = notice
|
||||
render 'create'
|
||||
end
|
||||
else
|
||||
@qr_code = build_qr_code
|
||||
|
|
@ -131,7 +126,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
|||
end
|
||||
|
||||
def validate_current_password
|
||||
return if Feature.disabled?(:webauthn_without_totp) && params[:action] == 'create_webauthn'
|
||||
return if current_user.valid_password?(params[:current_password])
|
||||
|
||||
current_user.increment_failed_attempts!
|
||||
|
|
|
|||
|
|
@ -1464,11 +1464,6 @@ class User < ApplicationRecord
|
|||
Gitlab::CurrentSettings.password_authentication_enabled_for_git?
|
||||
end
|
||||
|
||||
# method overriden in EE
|
||||
def password_based_login_forbidden?
|
||||
false
|
||||
end
|
||||
|
||||
def can_change_username?
|
||||
gitlab_config.username_changing_enabled
|
||||
end
|
||||
|
|
|
|||
|
|
@ -135,6 +135,8 @@ module Ci
|
|||
job.drop!(:api_failure)
|
||||
when 'canceled'
|
||||
job.cancel!
|
||||
when 'skipped'
|
||||
job.skip!
|
||||
else
|
||||
raise('invalid state')
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
- if Feature.enabled?(:webauthn_without_totp)
|
||||
#js-device-registration{ data: device_registration_data(current_password_required: current_password_required?, target_path: target_path, webauthn_error: @webauthn_error) }
|
||||
- else
|
||||
#js-register-token-2fa
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-2fa-message{ type: "text/template" }
|
||||
%p <%= message %>
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-setup{ type: "text/template" }
|
||||
- if current_user.two_factor_otp_enabled?
|
||||
.row.gl-mb-3
|
||||
.col-md-5
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm,
|
||||
button_options: { id: 'js-setup-token-2fa-device' }) do
|
||||
= _("Set up new device")
|
||||
.col-md-7
|
||||
%p= _("Your device needs to be set up. Plug it in (if needed) and click the button on the left.")
|
||||
- else
|
||||
.row.gl-mb-3
|
||||
.col-md-4
|
||||
= render Pajamas::ButtonComponent.new(variant: :confirm,
|
||||
disabled: true,
|
||||
button_options: { id: 'js-setup-token-2fa-device' }) do
|
||||
= _("Set up new device")
|
||||
.col-md-8
|
||||
%p= _("You need to register a two-factor authentication app before you can set up a device.")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-error{ type: "text/template" }
|
||||
%div
|
||||
%p
|
||||
%span <%= error_message %> (<%= error_name %>)
|
||||
= render Pajamas::ButtonComponent.new(button_options: { id: 'js-token-2fa-try-again' }) do
|
||||
= _("Try again?")
|
||||
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
%script#js-register-token-2fa-registered{ type: "text/template" }
|
||||
.row.gl-mb-3
|
||||
.col-md-12
|
||||
%p= _("Your device was successfully set up! Give it a name and register it with the GitLab server.")
|
||||
= form_tag(target_path, method: :post) do
|
||||
.row.gl-mb-3
|
||||
.col-md-3
|
||||
= text_field_tag 'device_registration[name]', nil, class: 'form-control', placeholder: _("Pick a name")
|
||||
.col-md-3
|
||||
= hidden_field_tag 'device_registration[device_response]', nil, class: 'form-control', required: true, id: "js-device-response"
|
||||
= render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm) do
|
||||
= _("Register device")
|
||||
|
|
@ -91,7 +91,8 @@
|
|||
- elsif show_recaptcha_sign_up?
|
||||
= recaptcha_tags nonce: content_security_policy_nonce
|
||||
|
||||
= render 'devise/shared/terms_of_service_notice', button_text: button_text
|
||||
= render_if_exists 'devise/registrations/opt_in_to_email', f: f
|
||||
= render 'devise/shared/terms_of_service_notice', button_text: button_text, css_class: 'gl-mt-2'
|
||||
|
||||
= render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, block: true,
|
||||
button_options: { class: "#{button_class} gl-mt-4",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
- button_options = { class: local_assigns[:classes], data: data }
|
||||
- button_options = { class: local_assigns[:classes], data: data, form: { class: 'js-omniauth-form' } }
|
||||
|
||||
= render Pajamas::ButtonComponent.new(href: href, method: :post, form: true, block: true, button_options: button_options) do
|
||||
- if provider_has_icon?(provider)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
- return unless Gitlab::CurrentSettings.current_application_settings.enforce_terms?
|
||||
|
||||
%p.gl-text-gray-500.gl-mt-5.gl-mb-0
|
||||
- css_class = local_assigns.fetch(:css_class, 'gl-mt-5')
|
||||
|
||||
%p.gl-text-gray-500.gl-mb-0{ class: css_class }
|
||||
= terms_service_notice_link(button_text)
|
||||
|
|
|
|||
|
|
@ -77,14 +77,11 @@
|
|||
%p
|
||||
= _('Set up a hardware device to enable two-factor authentication (2FA).')
|
||||
%p
|
||||
- if Feature.enabled?(:webauthn_without_totp)
|
||||
= _("Not all browsers support WebAuthn. You must save your recovery codes after you first register a two-factor authenticator to be able to sign in, even from an unsupported browser.")
|
||||
- else
|
||||
= _("Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in, even from an unsupported browser.")
|
||||
= _("Not all browsers support WebAuthn. You must save your recovery codes after you first register a two-factor authenticator to be able to sign in, even from an unsupported browser.")
|
||||
.col-lg-8
|
||||
- if @webauthn_registration.errors.present?
|
||||
= form_errors(@webauthn_registration)
|
||||
= render "authentication/register", target_path: create_webauthn_profile_two_factor_auth_path
|
||||
#js-device-registration{ data: device_registration_data(current_password_required: current_password_required?, target_path: create_webauthn_profile_two_factor_auth_path, webauthn_error: @webauthn_error) }
|
||||
|
||||
%hr
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: webauthn_without_totp
|
||||
introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107438"
|
||||
rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/386270"
|
||||
milestone: '15.9'
|
||||
type: development
|
||||
group: group::authentication
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: block_password_auth_for_saml_users
|
||||
introduced_by_url:
|
||||
rollout_issue_url:
|
||||
milestone: '13.11'
|
||||
type: ops
|
||||
group: group::authentication
|
||||
default_enabled: false
|
||||
|
|
@ -779,17 +779,17 @@ the API call must target the commit in the merge request's source branch.
|
|||
POST /projects/:id/statuses/:sha
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-paths) |
|
||||
| `sha` | string | yes | The commit SHA |
|
||||
| `state` | string | yes | The state of the status. Can be one of the following: `pending`, `running`, `success`, `failed`, `canceled` |
|
||||
| `ref` | string | no | The `ref` (branch or tag) to which the status refers |
|
||||
| `name` or `context` | string | no | The label to differentiate this status from the status of other systems. Default value is `default` |
|
||||
| `target_url` | string | no | The target URL to associate with this status |
|
||||
| `description` | string | no | The short description of the status |
|
||||
| `coverage` | float | no | The total code coverage |
|
||||
| `pipeline_id` | integer | no | The ID of the pipeline to set status. Use in case of several pipeline on same SHA. |
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- |-----------------------------------------------------------------------------------------------------------------------|
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](rest/index.md#namespaced-paths) |
|
||||
| `sha` | string | yes | The commit SHA |
|
||||
| `state` | string | yes | The state of the status. Can be one of the following: `pending`, `running`, `success`, `failed`, `canceled`, `skipped` |
|
||||
| `ref` | string | no | The `ref` (branch or tag) to which the status refers |
|
||||
| `name` or `context` | string | no | The label to differentiate this status from the status of other systems. Default value is `default` |
|
||||
| `target_url` | string | no | The target URL to associate with this status |
|
||||
| `description` | string | no | The short description of the status |
|
||||
| `coverage` | float | no | The total code coverage |
|
||||
| `pipeline_id` | integer | no | The ID of the pipeline to set status. Use in case of several pipeline on same SHA. |
|
||||
|
||||
```shell
|
||||
curl --request POST \
|
||||
|
|
|
|||
|
|
@ -277,12 +277,6 @@ Configure FortiToken Cloud in GitLab. On your GitLab server:
|
|||
|
||||
### Set up a WebAuthn device
|
||||
|
||||
> - Optional one-time password authentication for WebAuthn devices [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378844) in GitLab 15.10 [with a flag](../../../administration/feature_flags.md) named `webauthn_without_totp`. [Enabled on GitLab.com and self-managed by default](https://gitlab.com/gitlab-org/gitlab/-/issues/232671).
|
||||
|
||||
FLAG:
|
||||
On self-managed GitLab, by default, optional one-time password authentication for WebAuthn devices is not available. To enable the feature, an administrator can [enable the feature flag](../../../administration/feature_flags.md) named `webauthn_without_totp`.
|
||||
On GitLab.com, this feature is available. On GitLab Dedicated, this feature is not available.
|
||||
|
||||
WebAuthn is [supported by](https://caniuse.com/#search=webauthn) the following:
|
||||
|
||||
- Desktop browsers:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ module Keeps
|
|||
# -k Keeps::MarkOldAdvancedSearchMigrationsAsObsolete
|
||||
# ```
|
||||
class MarkOldAdvancedSearchMigrationsAsObsolete < ::Gitlab::Housekeeper::Keep
|
||||
CUTOFF_MILESTONE = '16.11' # Only obsolete migrations added before this
|
||||
# Only obsolete migrations added before this
|
||||
# milestones are stored in config/upgrade_path.yml
|
||||
CUTOFF_MILESTONE = '17.3'
|
||||
|
||||
MIGRATIONS_PATH = 'ee/elastic/migrate'
|
||||
MIGRATION_REGEXP = /\A([0-9]+)_([_a-z0-9]*)\.rb\z/
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ module API
|
|||
requires :sha, type: String, desc: 'The commit hash',
|
||||
documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
|
||||
requires :state, type: String, desc: 'The state of the status',
|
||||
values: %w[pending running success failed canceled],
|
||||
values: %w[pending running success failed canceled skipped],
|
||||
documentation: { example: 'pending' }
|
||||
optional :ref, type: String, desc: 'The ref',
|
||||
documentation: { example: 'develop' }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ module Gitlab
|
|||
class Authentication < Gitlab::Auth::OAuth::Authentication
|
||||
def login(login, password)
|
||||
return false unless Gitlab::CurrentSettings.password_authentication_enabled_for_git?
|
||||
return false if user.password_based_login_forbidden?
|
||||
|
||||
return user if user&.valid_password?(password)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -134,8 +134,6 @@ module Gitlab
|
|||
log.info "Correct LDAP account has been found. identity to user: #{gl_user.username}."
|
||||
gl_user.identities.build(provider: ldap_person.provider, extern_uid: ldap_person.dn)
|
||||
end
|
||||
|
||||
identity
|
||||
end
|
||||
|
||||
def find_or_build_ldap_user
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def low_timeout_for_host_queries?
|
||||
Feature.enabled?(:load_balancer_low_statement_timeout)
|
||||
Feature.enabled?(:load_balancer_low_statement_timeout, Feature.current_pod)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20827,9 +20827,6 @@ msgstr ""
|
|||
msgid "Email the pipeline status to a list of recipients."
|
||||
msgstr ""
|
||||
|
||||
msgid "Email updates (optional)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Email:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27556,6 +27553,9 @@ msgstr ""
|
|||
msgid "HttpDestinationValidator validates only http external audit event destinations."
|
||||
msgstr ""
|
||||
|
||||
msgid "I agree that by clicking continue or registering through a third party GitLab may contact me via email and telephone about its product, services and events."
|
||||
msgstr ""
|
||||
|
||||
msgid "I forgot my password"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27574,9 +27574,6 @@ msgstr ""
|
|||
msgid "I want to use GitLab CI with my existing repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'd like to receive updates about GitLab via email"
|
||||
msgstr ""
|
||||
|
||||
msgid "I'm signing up for GitLab because:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -36448,9 +36445,6 @@ msgstr ""
|
|||
msgid "Not adopted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Not all browsers support WebAuthn. Therefore, we require that you set up a two-factor authentication app first. That way you'll always be able to sign in, even from an unsupported browser."
|
||||
msgstr ""
|
||||
|
||||
msgid "Not all browsers support WebAuthn. You must save your recovery codes after you first register a two-factor authenticator to be able to sign in, even from an unsupported browser."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39806,9 +39800,6 @@ msgstr ""
|
|||
msgid "Pick a group or project"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pick a name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -63542,9 +63533,6 @@ msgstr ""
|
|||
msgid "You need permission."
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to register a two-factor authentication app before you can set up a device."
|
||||
msgstr ""
|
||||
|
||||
msgid "You need to set terms to be enforced"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ module QA
|
|||
end
|
||||
|
||||
it(
|
||||
'successfully imports ci pipeline',
|
||||
'successfully imports ci pipeline', :blocking,
|
||||
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354650'
|
||||
) do
|
||||
expect_project_import_finished_successfully
|
||||
|
|
|
|||
|
|
@ -38,13 +38,13 @@ namespace :ci do
|
|||
append_to_file(env_file, "QA_SKIP_ALL_TESTS=true")
|
||||
end
|
||||
|
||||
# on run-all label of framework changes do not infer specific tests
|
||||
# on run-all label or framework changes do not infer specific tests
|
||||
tests = run_all_label_present || qa_changes.framework_changes? ? nil : qa_changes.qa_tests
|
||||
|
||||
# When QA_TESTS only contain folders or exceeds certain size, use KNAPSACK_FILE_PATTERN to limit what specs to run
|
||||
files_pattern = ""
|
||||
files_pattern = nil
|
||||
tests_array = tests&.split(' ')
|
||||
if tests_array&.none? { |item| item.include?('_spec') }
|
||||
if tests_array&.none? { |item| item.include?('_spec.rb') }
|
||||
test_paths = tests_array.map { |item| "#{item}**/*" }
|
||||
|
||||
files_pattern = "{#{test_paths.join(',')}}"
|
||||
|
|
@ -55,12 +55,6 @@ namespace :ci do
|
|||
tests = nil # Unset QA_TESTS when KNAPSACK_FILE_PATTERN is set
|
||||
end
|
||||
|
||||
logger.info(" Files pattern for tests: #{files_pattern}")
|
||||
|
||||
append_to_file(env_file, <<~TXT)
|
||||
KNAPSACK_TEST_FILE_PATTERN='#{files_pattern}'
|
||||
TXT
|
||||
|
||||
if run_all_label_present
|
||||
logger.info(" merge request has pipeline:run-all-e2e label, full test suite will be executed")
|
||||
append_to_file(env_file, "QA_RUN_ALL_E2E_LABEL=true\n")
|
||||
|
|
@ -70,6 +64,7 @@ namespace :ci do
|
|||
elsif tests
|
||||
logger.info(" detected following specs to execute: '#{tests}'")
|
||||
elsif files_pattern
|
||||
append_to_file(env_file, "KNAPSACK_TEST_FILE_PATTERN='#{files_pattern}'\n")
|
||||
logger.info(" detected following specs to execute in parallel: '#{files_pattern}'")
|
||||
else
|
||||
logger.info(" no specific specs to execute detected")
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ else
|
|||
echo "$rev" > "$gem_target/REVISION"
|
||||
git add "$gem_target/REVISION"
|
||||
changelog=$(git -C "$tmp" log --no-merges --pretty="- %h: %s" "$prev_rev..$rev" -- clients/ruby/)
|
||||
git commit -m "Updating Topology Service Client Gem to $short_rev" -m "$changelog" -m 'changelog: other'
|
||||
git commit -m "Updating Topology Service Client Gem to $short_rev" -m "$changelog" -m 'Changelog: other'
|
||||
fi
|
||||
|
||||
rm -rf "$tmp"
|
||||
|
|
|
|||
|
|
@ -202,51 +202,6 @@ RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :system_acc
|
|||
expect(ActiveSession).to receive(:destroy_all_but_current)
|
||||
go
|
||||
end
|
||||
|
||||
context 'when webauthn_without_totp flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(webauthn_without_totp: false)
|
||||
expect(user).to receive(:validate_and_consume_otp!).with(pin).and_return(true)
|
||||
end
|
||||
|
||||
it 'enables 2fa for the user' do
|
||||
go
|
||||
|
||||
user.reload
|
||||
expect(user).to be_two_factor_enabled
|
||||
end
|
||||
|
||||
it 'presents plaintext codes for the user to save' do
|
||||
expect(user).to receive(:generate_otp_backup_codes!).and_return(%w[a b c])
|
||||
|
||||
go
|
||||
|
||||
expect(assigns[:codes]).to match_array %w[a b c]
|
||||
end
|
||||
|
||||
it 'calls to delete other sessions' do
|
||||
expect(ActiveSession).to receive(:destroy_all_but_current)
|
||||
|
||||
go
|
||||
end
|
||||
|
||||
it 'dismisses the `TWO_FACTOR_AUTH_RECOVERY_SETTINGS_CHECK` callout' do
|
||||
expect(controller.helpers).to receive(:dismiss_two_factor_auth_recovery_settings_check)
|
||||
|
||||
go
|
||||
end
|
||||
|
||||
it 'renders create' do
|
||||
go
|
||||
expect(response).to render_template(:create)
|
||||
end
|
||||
|
||||
it 'renders create even if backup code already exists' do
|
||||
expect(user).to receive(:otp_backup_codes?).and_return(true)
|
||||
go
|
||||
expect(response).to render_template(:create)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid pin' do
|
||||
|
|
@ -364,22 +319,6 @@ RSpec.describe Profiles::TwoFactorAuthsController, feature_category: :system_acc
|
|||
expect(flash[:notice]).to match(/Your WebAuthn device was registered!/)
|
||||
end
|
||||
end
|
||||
|
||||
context "when the feature flag 'webauthn_without_totp' is disabled" do
|
||||
before do
|
||||
stub_feature_flags(webauthn_without_totp: false)
|
||||
session[:challenge] = challenge
|
||||
end
|
||||
|
||||
let(:params) { { device_registration: { name: 'touch id', device_response: device_response } } } # rubocop:disable Rails/SaveBang
|
||||
|
||||
it "does not validate the current_password" do
|
||||
go
|
||||
|
||||
expect(flash[:notice]).to match(/Your WebAuthn device was registered!/)
|
||||
expect(response).to redirect_to(profile_two_factor_auth_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE destroy' do
|
||||
|
|
|
|||
|
|
@ -44,6 +44,22 @@ RSpec.describe 'GraphQL Explorer', :js, feature_category: :api do
|
|||
expect_response(%("currentUser": { "id": "#{user.to_gid}" }))
|
||||
end
|
||||
|
||||
it 'allows user to execute one of multiple named queries' do
|
||||
visit '/-/graphql-explorer'
|
||||
|
||||
fill_in_editor(
|
||||
'query currentUserId { currentUser { ...UserIdFragment } } ' \
|
||||
'query currentUsername { currentUser { username } } ' \
|
||||
'fragment UserIdFragment on User { id }'
|
||||
)
|
||||
sleep 0.1 # GraphiQL needs to parse the query in the background before we click execute
|
||||
|
||||
click_execute_button
|
||||
find('.graphiql-dropdown-item', text: 'currentUserId').click
|
||||
|
||||
expect_response(%("currentUser": { "id": "#{user.to_gid}" }))
|
||||
end
|
||||
|
||||
it 'allows user to execute a mutation' do
|
||||
visit '/-/graphql-explorer'
|
||||
|
||||
|
|
|
|||
|
|
@ -10,67 +10,65 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
|
|||
WebAuthn.configuration.origin = app_id
|
||||
end
|
||||
|
||||
context 'when the webauth_without_totp feature flag is enabled' do
|
||||
# Some of the shared tests don't apply. After removing U2F support and the `webauthn_without_totp` feature flag, refactor the shared tests.
|
||||
# TODO: it_behaves_like 'hardware device for 2fa', 'WebAuthn'
|
||||
it_behaves_like 'hardware device for 2fa', 'WebAuthn'
|
||||
|
||||
describe 'registration' do
|
||||
let(:user) { create(:user) }
|
||||
describe 'registration' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
gitlab_sign_in(user)
|
||||
end
|
||||
before do
|
||||
gitlab_sign_in(user)
|
||||
end
|
||||
|
||||
it 'shows an error when using a wrong password' do
|
||||
visit profile_account_path
|
||||
it 'shows an error when using a wrong password' do
|
||||
visit profile_account_path
|
||||
|
||||
# First device
|
||||
enable_two_factor_authentication
|
||||
webauthn_device_registration(password: 'fake')
|
||||
expect(page).to have_content(_('You must provide a valid current password.'))
|
||||
end
|
||||
# First device
|
||||
enable_two_factor_authentication
|
||||
webauthn_device_registration(password: 'fake')
|
||||
expect(page).to have_content(_('You must provide a valid current password.'))
|
||||
end
|
||||
|
||||
it 'allows registering more than one device' do
|
||||
visit profile_account_path
|
||||
it 'allows registering more than one device' do
|
||||
visit profile_account_path
|
||||
|
||||
# First device
|
||||
enable_two_factor_authentication
|
||||
first_device = webauthn_device_registration(password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
copy_recovery_codes
|
||||
manage_two_factor_authentication
|
||||
# First device
|
||||
enable_two_factor_authentication
|
||||
first_device = webauthn_device_registration(password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
copy_recovery_codes
|
||||
manage_two_factor_authentication
|
||||
|
||||
# Second device
|
||||
second_device = webauthn_device_registration(name: 'My other device', password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
# Second device
|
||||
second_device = webauthn_device_registration(name: 'My other device', password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
|
||||
expect(page).to have_content(first_device.name)
|
||||
expect(page).to have_content(second_device.name)
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
end
|
||||
expect(page).to have_content(first_device.name)
|
||||
expect(page).to have_content(second_device.name)
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
end
|
||||
|
||||
it 'allows the same device to be registered for multiple users' do
|
||||
# First user
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
webauthn_device = webauthn_device_registration(password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
gitlab_sign_out
|
||||
it 'allows the same device to be registered for multiple users' do
|
||||
# First user
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
webauthn_device = webauthn_device_registration(password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
gitlab_sign_out
|
||||
|
||||
# Second user
|
||||
user = create(:user)
|
||||
gitlab_sign_in(user)
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
webauthn_device_registration(webauthn_device: webauthn_device, name: 'My other device', password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
# Second user
|
||||
user = create(:user)
|
||||
gitlab_sign_in(user)
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
webauthn_device_registration(webauthn_device: webauthn_device, name: 'My other device', password: user.password)
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
end
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
end
|
||||
|
||||
context 'when there are form errors' do
|
||||
let(:mock_register_js) do
|
||||
<<~JS
|
||||
context 'when there are form errors' do
|
||||
let(:mock_register_js) do
|
||||
<<~JS
|
||||
const mockResponse = {
|
||||
type: 'public-key',
|
||||
id: '',
|
||||
|
|
@ -82,145 +80,37 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
|
|||
getClientExtensionResults: () => {},
|
||||
};
|
||||
navigator.credentials.create = () => Promise.resolve(mockResponse);
|
||||
JS
|
||||
end
|
||||
|
||||
it "doesn't register the device if there are errors" do
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
|
||||
# Have the "webauthn device" respond with bad data
|
||||
page.execute_script(mock_register_js)
|
||||
click_on _('Set up new device')
|
||||
webauthn_fill_form_and_submit(password: user.password)
|
||||
expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
|
||||
|
||||
expect(WebauthnRegistration.count).to eq(0)
|
||||
end
|
||||
|
||||
it 'allows retrying registration' do
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
|
||||
# Failed registration
|
||||
page.execute_script(mock_register_js)
|
||||
click_on _('Set up new device')
|
||||
webauthn_fill_form_and_submit(password: user.password)
|
||||
expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
|
||||
|
||||
# Successful registration
|
||||
webauthn_device_registration(password: user.password)
|
||||
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
expect(WebauthnRegistration.count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the webauth_without_totp feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(webauthn_without_totp: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'hardware device for 2fa', 'WebAuthn'
|
||||
|
||||
describe 'registration' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
gitlab_sign_in(user)
|
||||
user.update_attribute(:otp_required_for_login, true)
|
||||
JS
|
||||
end
|
||||
|
||||
describe 'when 2FA via OTP is enabled' do
|
||||
it 'allows registering more than one device' do
|
||||
visit profile_account_path
|
||||
|
||||
# First device
|
||||
manage_two_factor_authentication
|
||||
first_device = register_webauthn_device
|
||||
expect(page).to have_content('Your WebAuthn device was registered')
|
||||
|
||||
# Second device
|
||||
second_device = register_webauthn_device(name: 'My other device')
|
||||
expect(page).to have_content('Your WebAuthn device was registered')
|
||||
|
||||
expect(page).to have_content(first_device.name)
|
||||
expect(page).to have_content(second_device.name)
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
it 'allows the same device to be registered for multiple users' do
|
||||
# First user
|
||||
it "doesn't register the device if there are errors" do
|
||||
visit profile_account_path
|
||||
manage_two_factor_authentication
|
||||
webauthn_device = register_webauthn_device
|
||||
expect(page).to have_content('Your WebAuthn device was registered')
|
||||
gitlab_sign_out
|
||||
enable_two_factor_authentication
|
||||
|
||||
# Second user
|
||||
user = create(:user)
|
||||
gitlab_sign_in(user)
|
||||
user.update_attribute(:otp_required_for_login, true)
|
||||
visit profile_account_path
|
||||
manage_two_factor_authentication
|
||||
register_webauthn_device(webauthn_device, name: 'My other device')
|
||||
expect(page).to have_content('Your WebAuthn device was registered')
|
||||
# Have the "webauthn device" respond with bad data
|
||||
page.execute_script(mock_register_js)
|
||||
click_on _('Set up new device')
|
||||
webauthn_fill_form_and_submit(password: user.password)
|
||||
expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
|
||||
|
||||
expect(WebauthnRegistration.count).to eq(2)
|
||||
expect(WebauthnRegistration.count).to eq(0)
|
||||
end
|
||||
|
||||
context 'when there are form errors' do
|
||||
let(:mock_register_js) do
|
||||
<<~JS
|
||||
const mockResponse = {
|
||||
type: 'public-key',
|
||||
id: '',
|
||||
rawId: '',
|
||||
response: {
|
||||
clientDataJSON: '',
|
||||
attestationObject: '',
|
||||
},
|
||||
getClientExtensionResults: () => {},
|
||||
};
|
||||
navigator.credentials.create = function(_) {return Promise.resolve(mockResponse);}
|
||||
JS
|
||||
end
|
||||
it 'allows retrying registration' do
|
||||
visit profile_account_path
|
||||
enable_two_factor_authentication
|
||||
|
||||
it "doesn't register the device if there are errors" do
|
||||
visit profile_account_path
|
||||
manage_two_factor_authentication
|
||||
# Failed registration
|
||||
page.execute_script(mock_register_js)
|
||||
click_on _('Set up new device')
|
||||
webauthn_fill_form_and_submit(password: user.password)
|
||||
expect(page).to have_content(_('Your WebAuthn device did not send a valid JSON response.'))
|
||||
|
||||
# Have the "webauthn device" respond with bad data
|
||||
page.execute_script(mock_register_js)
|
||||
click_on 'Set up new device'
|
||||
expect(page).to have_content('Your device was successfully set up')
|
||||
click_on 'Register device'
|
||||
# Successful registration
|
||||
webauthn_device_registration(password: user.password)
|
||||
|
||||
expect(WebauthnRegistration.count).to eq(0)
|
||||
expect(page).to have_content('The form contains the following error')
|
||||
expect(page).to have_content('did not send a valid JSON response')
|
||||
end
|
||||
|
||||
it 'allows retrying registration' do
|
||||
visit profile_account_path
|
||||
manage_two_factor_authentication
|
||||
|
||||
# Failed registration
|
||||
page.execute_script(mock_register_js)
|
||||
click_on 'Set up new device'
|
||||
expect(page).to have_content('Your device was successfully set up')
|
||||
click_on 'Register device'
|
||||
expect(page).to have_content('The form contains the following error')
|
||||
|
||||
# Successful registration
|
||||
register_webauthn_device
|
||||
|
||||
expect(page).to have_content('Your WebAuthn device was registered')
|
||||
expect(WebauthnRegistration.count).to eq(1)
|
||||
end
|
||||
expect(page).to have_content('Your WebAuthn device was registered!')
|
||||
expect(WebauthnRegistration.count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -280,8 +170,9 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
|
|||
current_user = create(:user)
|
||||
gitlab_sign_in(current_user)
|
||||
visit profile_account_path
|
||||
manage_two_factor_authentication
|
||||
register_webauthn_device(webauthn_device)
|
||||
enable_two_factor_authentication
|
||||
webauthn_device_registration(webauthn_device: webauthn_device, password: current_user.password)
|
||||
copy_recovery_codes
|
||||
gitlab_sign_out
|
||||
|
||||
# Try authenticating user with the same WebAuthn device
|
||||
|
|
@ -311,7 +202,7 @@ RSpec.describe 'Using WebAuthn Devices for Authentication', :js, feature_categor
|
|||
# Authenticate as both devices
|
||||
[first_device, second_device].each do |device|
|
||||
gitlab_sign_in(user)
|
||||
# register_webauthn_device(device)
|
||||
|
||||
device.respond_to_webauthn_authentication
|
||||
|
||||
expect(page).to have_css('.sign-out-link', visible: false)
|
||||
|
|
|
|||
|
|
@ -1,135 +0,0 @@
|
|||
import $ from 'jquery';
|
||||
import htmlWebauthnRegister from 'test_fixtures/webauthn/register.html';
|
||||
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
|
||||
import { trimText } from 'helpers/text_helper';
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import WebAuthnRegister from '~/authentication/webauthn/register';
|
||||
import MockWebAuthnDevice from './mock_webauthn_device';
|
||||
import { useMockNavigatorCredentials } from './util';
|
||||
|
||||
describe('WebAuthnRegister', () => {
|
||||
useMockNavigatorCredentials();
|
||||
|
||||
const mockResponse = {
|
||||
type: 'public-key',
|
||||
id: '',
|
||||
rawId: '',
|
||||
response: {
|
||||
clientDataJSON: '',
|
||||
attestationObject: '',
|
||||
},
|
||||
getClientExtensionResults: () => {},
|
||||
};
|
||||
let webAuthnDevice;
|
||||
let container;
|
||||
let component;
|
||||
|
||||
beforeEach(() => {
|
||||
setHTMLFixture(htmlWebauthnRegister);
|
||||
webAuthnDevice = new MockWebAuthnDevice();
|
||||
container = $('#js-register-token-2fa');
|
||||
component = new WebAuthnRegister(container, {
|
||||
options: {
|
||||
rp: '',
|
||||
user: {
|
||||
id: '',
|
||||
name: '',
|
||||
displayName: '',
|
||||
},
|
||||
challenge: '',
|
||||
pubKeyCredParams: '',
|
||||
},
|
||||
});
|
||||
component.start();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
resetHTMLFixture();
|
||||
});
|
||||
|
||||
const findSetupButton = () => container.find('#js-setup-token-2fa-device');
|
||||
const findMessage = () => container.find('p');
|
||||
const findDeviceResponse = () => container.find('#js-device-response');
|
||||
const findRetryButton = () => container.find('#js-token-2fa-try-again');
|
||||
|
||||
it('shows setup button', () => {
|
||||
expect(trimText(findSetupButton().text())).toBe('Set up new device');
|
||||
});
|
||||
|
||||
describe('when unsupported', () => {
|
||||
const { PublicKeyCredential } = window;
|
||||
|
||||
beforeEach(() => {
|
||||
delete window.credentials;
|
||||
window.PublicKeyCredential = undefined;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.PublicKeyCredential = PublicKeyCredential;
|
||||
});
|
||||
|
||||
it.each`
|
||||
httpsEnabled | expectedText
|
||||
${false} | ${'WebAuthn only works with HTTPS-enabled websites'}
|
||||
${true} | ${'Please use a supported browser, e.g. Chrome (67+) or Firefox'}
|
||||
`('when https is $httpsEnabled', ({ httpsEnabled, expectedText }) => {
|
||||
setWindowLocation(`${httpsEnabled ? 'https:' : 'http:'}//localhost`);
|
||||
component.start();
|
||||
|
||||
expect(findMessage().text()).toContain(expectedText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when setup', () => {
|
||||
beforeEach(() => {
|
||||
findSetupButton().trigger('click');
|
||||
});
|
||||
|
||||
it('shows in progress message', () => {
|
||||
expect(findMessage().text()).toContain('Trying to communicate with your device');
|
||||
});
|
||||
|
||||
it('registers device', () => {
|
||||
webAuthnDevice.respondToRegisterRequest(mockResponse);
|
||||
|
||||
return waitForPromises().then(() => {
|
||||
expect(findMessage().text()).toContain('Your device was successfully set up!');
|
||||
expect(findDeviceResponse().val()).toBe(JSON.stringify(mockResponse));
|
||||
});
|
||||
});
|
||||
|
||||
it.each`
|
||||
errorName | expectedText
|
||||
${'NotSupportedError'} | ${'Your device is not compatible with GitLab'}
|
||||
${'NotAllowedError'} | ${'There was a problem communicating with your device'}
|
||||
`('when fails with $errorName', ({ errorName, expectedText }) => {
|
||||
webAuthnDevice.rejectRegisterRequest(new DOMException('', errorName));
|
||||
|
||||
return waitForPromises().then(() => {
|
||||
expect(findMessage().text()).toContain(expectedText);
|
||||
expect(findRetryButton().length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
it('can retry', () => {
|
||||
webAuthnDevice.respondToRegisterRequest({
|
||||
errorCode: 'error!',
|
||||
});
|
||||
|
||||
return waitForPromises()
|
||||
.then(() => {
|
||||
findRetryButton().click();
|
||||
|
||||
expect(findMessage().text()).toContain('Trying to communicate with your device');
|
||||
|
||||
webAuthnDevice.respondToRegisterRequest(mockResponse);
|
||||
return waitForPromises();
|
||||
})
|
||||
.then(() => {
|
||||
expect(findMessage().text()).toContain('Your device was successfully set up!');
|
||||
expect(findDeviceResponse().val()).toBe(JSON.stringify(mockResponse));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -23,22 +23,4 @@ RSpec.context 'WebAuthn' do
|
|||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe Profiles::TwoFactorAuthsController, '(JavaScript fixtures)', type: :controller do
|
||||
render_views
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
allow_next_instance_of(Profiles::TwoFactorAuthsController) do |instance|
|
||||
allow(instance).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares')
|
||||
end
|
||||
stub_feature_flags(webauthn_without_totp: false)
|
||||
end
|
||||
|
||||
it 'webauthn/register.html' do
|
||||
get :show
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::Host, feature_category: :databas
|
|||
|
||||
context 'with the flag set' do
|
||||
before do
|
||||
stub_feature_flags(load_balancer_low_statement_timeout: true)
|
||||
stub_feature_flags(load_balancer_low_statement_timeout: Feature.current_pod)
|
||||
end
|
||||
|
||||
it 'returns quickly if the underlying query takes a long time' do
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ RSpec.describe API::CommitStatuses, :clean_gitlab_redis_cache, feature_category:
|
|||
|
||||
context 'developer user' do
|
||||
context 'uses only required parameters' do
|
||||
valid_statues = %w[pending running success failed canceled]
|
||||
valid_statues = %w[pending running success failed canceled skipped]
|
||||
valid_statues.each do |status|
|
||||
context "for #{status}" do
|
||||
context 'when pipeline for sha does not exists' do
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ RSpec.describe Ci::CreateCommitStatusService, :clean_gitlab_redis_cache, feature
|
|||
let(:params) { { state: 'pending' } }
|
||||
let(:job) { response.payload[:job] }
|
||||
|
||||
%w[pending running success failed canceled].each do |status|
|
||||
%w[pending running success failed canceled skipped].each do |status|
|
||||
context "for #{status}" do
|
||||
let(:params) { { state: status } }
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ RSpec.describe Ci::CreateCommitStatusService, :clean_gitlab_redis_cache, feature
|
|||
execute_service(state: 'pending')
|
||||
end
|
||||
|
||||
%w[running success failed canceled].each do |status|
|
||||
%w[running success failed canceled skipped].each do |status|
|
||||
context "for #{status}" do
|
||||
let(:params) { { state: status } }
|
||||
|
||||
|
|
|
|||
|
|
@ -29,17 +29,6 @@ module Features
|
|||
end
|
||||
|
||||
# Registers webauthn device via UI
|
||||
# Remove after `webauthn_without_totp` feature flag is deleted.
|
||||
def register_webauthn_device(webauthn_device = nil, name: 'My device')
|
||||
webauthn_device ||= FakeWebauthnDevice.new(page, name)
|
||||
webauthn_device.respond_to_webauthn_registration
|
||||
click_on 'Set up new device'
|
||||
expect(page).to have_content('Your device was successfully set up')
|
||||
fill_in 'Pick a name', with: name
|
||||
click_on 'Register device'
|
||||
webauthn_device
|
||||
end
|
||||
|
||||
def webauthn_device_registration(webauthn_device: nil, name: 'My device', password: 'fake')
|
||||
webauthn_device ||= FakeWebauthnDevice.new(page, name)
|
||||
webauthn_device.respond_to_webauthn_registration
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@
|
|||
- './ee/spec/features/groups/iterations/user_views_iteration_cadence_spec.rb'
|
||||
- './ee/spec/features/groups/iterations/user_views_iteration_spec.rb'
|
||||
- './ee/spec/features/groups/ldap_group_links_spec.rb'
|
||||
- './ee/spec/features/groups/members/leave_group_spec.rb'
|
||||
- './ee/spec/features/groups/members/list_members_spec.rb'
|
||||
- './ee/spec/features/groups/members/manage_groups_spec.rb'
|
||||
- './ee/spec/features/groups/members/manage_members_spec.rb'
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
|
|||
def register_device(device_type, **kwargs)
|
||||
case device_type
|
||||
when 'WebAuthn'
|
||||
register_webauthn_device(**kwargs)
|
||||
webauthn_device_registration(**kwargs)
|
||||
else
|
||||
raise "Unknown device type #{device_type}"
|
||||
end
|
||||
|
|
@ -26,11 +26,16 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
|
|||
user.update_attribute(:otp_required_for_login, false)
|
||||
end
|
||||
|
||||
it 'does not allow registering a new device' do
|
||||
it 'allows registering a new device' do
|
||||
visit profile_account_path
|
||||
click_on 'Enable two-factor authentication'
|
||||
click_on _('Enable two-factor authentication')
|
||||
|
||||
expect(page).to have_button("Set up new device", disabled: true)
|
||||
device = register_device(device_type, password: user.password)
|
||||
expect(page).to have_content("Your #{device_type} device was registered")
|
||||
copy_recovery_codes
|
||||
manage_two_factor_authentication
|
||||
|
||||
expect(page).to have_content(device.name)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -40,10 +45,12 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
|
|||
manage_two_factor_authentication
|
||||
expect(page).to have_content(_("You've already enabled two-factor authentication using a one-time password authenticator. In order to register a different device, you must first delete this authenticator."))
|
||||
|
||||
device = register_device(device_type)
|
||||
device = register_device(device_type, password: user.password)
|
||||
expect(page).to have_content("Your #{device_type} device was registered")
|
||||
copy_recovery_codes
|
||||
manage_two_factor_authentication
|
||||
|
||||
expect(page).to have_content(device.name)
|
||||
expect(page).to have_content("Your #{device_type} device was registered")
|
||||
end
|
||||
|
||||
it 'allows deleting a device' do
|
||||
|
|
@ -51,8 +58,10 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
|
|||
manage_two_factor_authentication
|
||||
expect(page).to have_content(_("You've already enabled two-factor authentication using a one-time password authenticator. In order to register a different device, you must first delete this authenticator."))
|
||||
|
||||
first_device = register_device(device_type)
|
||||
second_device = register_device(device_type, name: 'My other device')
|
||||
first_device = register_device(device_type, password: user.password)
|
||||
copy_recovery_codes
|
||||
manage_two_factor_authentication
|
||||
second_device = register_device(device_type, name: 'My other device', password: user.password)
|
||||
|
||||
expect(page).to have_content(first_device.name)
|
||||
expect(page).to have_content(second_device.name)
|
||||
|
|
@ -95,7 +104,7 @@ RSpec.shared_examples 'hardware device for 2fa' do |device_type|
|
|||
describe 'when a device is registered' do
|
||||
before do
|
||||
manage_two_factor_authentication
|
||||
register_device(device_type)
|
||||
register_device(device_type, password: user.password)
|
||||
gitlab_sign_out
|
||||
gitlab_sign_in(user)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
722480422308f4bdba9e5ab874b6d4752667e51a
|
||||
d88ee3c1078fee452e03170cc74da0db5732c8a7
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ require_relative "topology_service/version"
|
|||
require "proto/claim_service_services_pb"
|
||||
require "proto/classify_service_services_pb"
|
||||
require "proto/health_service_services_pb"
|
||||
require "proto/sequence_service_services_pb"
|
||||
require "proto/cell_service_services_pb"
|
||||
|
|
|
|||
|
|
@ -5,16 +5,21 @@ require 'google/protobuf'
|
|||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/cell_info.proto", :syntax => :proto3) do
|
||||
add_message "gitlab.cells.topology_service.SequenceRange" do
|
||||
optional :minval, :int64, 1, json_name: "minval"
|
||||
optional :maxval, :int64, 2, json_name: "maxval"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.CellInfo" do
|
||||
optional :id, :int64, 1
|
||||
optional :name, :string, 2
|
||||
optional :address, :string, 3
|
||||
optional :session_prefix, :string, 4
|
||||
optional :id, :int64, 1, json_name: "id"
|
||||
optional :name, :string, 2, json_name: "name"
|
||||
optional :address, :string, 3, json_name: "address"
|
||||
optional :session_prefix, :string, 4, json_name: "sessionPrefix"
|
||||
optional :sequence_range, :message, 5, "gitlab.cells.topology_service.SequenceRange", json_name: "sequenceRange"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.GetCellsRequest" do
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.GetCellsResponse" do
|
||||
repeated :cells, :message, 1, "gitlab.cells.topology_service.CellInfo"
|
||||
repeated :cells, :message, 1, "gitlab.cells.topology_service.CellInfo", json_name: "cells"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -22,6 +27,7 @@ end
|
|||
module Gitlab
|
||||
module Cells
|
||||
module TopologyService
|
||||
SequenceRange = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.SequenceRange").msgclass
|
||||
CellInfo = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.CellInfo").msgclass
|
||||
GetCellsRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.GetCellsRequest").msgclass
|
||||
GetCellsResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.GetCellsResponse").msgclass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: proto/cell_service.proto
|
||||
|
||||
require 'google/protobuf'
|
||||
|
||||
require 'proto/cell_info_pb'
|
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/cell_service.proto", :syntax => :proto3) do
|
||||
add_message "gitlab.cells.topology_service.GetCellRequest" do
|
||||
optional :cell_name, :string, 1, json_name: "cellName"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.GetCellResponse" do
|
||||
optional :cell_info, :message, 1, "gitlab.cells.topology_service.CellInfo", json_name: "cellInfo"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Gitlab
|
||||
module Cells
|
||||
module TopologyService
|
||||
GetCellRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.GetCellRequest").msgclass
|
||||
GetCellResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitlab.cells.topology_service.GetCellResponse").msgclass
|
||||
end
|
||||
end
|
||||
end
|
||||
26
vendor/gems/gitlab-topology-service-client/lib/proto/cell_service_services_pb.rb
vendored
Normal file
26
vendor/gems/gitlab-topology-service-client/lib/proto/cell_service_services_pb.rb
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# Source: proto/cell_service.proto for package 'Gitlab.Cells.TopologyService'
|
||||
|
||||
require 'grpc'
|
||||
require 'proto/cell_service_pb'
|
||||
|
||||
module Gitlab
|
||||
module Cells
|
||||
module TopologyService
|
||||
module CellService
|
||||
class Service
|
||||
|
||||
include ::GRPC::GenericService
|
||||
|
||||
self.marshal_class_method = :encode
|
||||
self.unmarshal_class_method = :decode
|
||||
self.service_name = 'gitlab.cells.topology_service.CellService'
|
||||
|
||||
rpc :GetCell, ::Gitlab::Cells::TopologyService::GetCellRequest, ::Gitlab::Cells::TopologyService::GetCellResponse
|
||||
end
|
||||
|
||||
Stub = Service.rpc_stub_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -4,49 +4,50 @@
|
|||
require 'google/protobuf'
|
||||
|
||||
require 'proto/cell_info_pb'
|
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/claim_service.proto", :syntax => :proto3) do
|
||||
add_message "gitlab.cells.topology_service.ClaimRecord" do
|
||||
optional :bucket, :enum, 1, "gitlab.cells.topology_service.ClaimRecord.Bucket"
|
||||
optional :value, :string, 2
|
||||
optional :bucket, :enum, 1, "gitlab.cells.topology_service.ClaimRecord.Bucket", json_name: "bucket"
|
||||
optional :value, :string, 2, json_name: "value"
|
||||
end
|
||||
add_enum "gitlab.cells.topology_service.ClaimRecord.Bucket" do
|
||||
value :Unknown, 0
|
||||
value :Routes, 1
|
||||
value :UNSPECIFIED, 0
|
||||
value :ROUTES, 1
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.ParentRecord" do
|
||||
optional :model, :enum, 1, "gitlab.cells.topology_service.ParentRecord.ApplicationModel"
|
||||
optional :id, :int64, 2
|
||||
optional :model, :enum, 1, "gitlab.cells.topology_service.ParentRecord.ApplicationModel", json_name: "model"
|
||||
optional :id, :int64, 2, json_name: "id"
|
||||
end
|
||||
add_enum "gitlab.cells.topology_service.ParentRecord.ApplicationModel" do
|
||||
value :Unknown, 0
|
||||
value :Group, 1
|
||||
value :Project, 2
|
||||
value :UserNamespace, 3
|
||||
value :UNSPECIFIED, 0
|
||||
value :GROUP, 1
|
||||
value :PROJECT, 2
|
||||
value :USER_NAMESPACE, 3
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.OwnerRecord" do
|
||||
optional :table, :enum, 1, "gitlab.cells.topology_service.OwnerRecord.Table"
|
||||
optional :id, :int64, 2
|
||||
optional :table, :enum, 1, "gitlab.cells.topology_service.OwnerRecord.Table", json_name: "table"
|
||||
optional :id, :int64, 2, json_name: "id"
|
||||
end
|
||||
add_enum "gitlab.cells.topology_service.OwnerRecord.Table" do
|
||||
value :Unknown, 0
|
||||
value :routes, 1
|
||||
value :UNSPECIFIED, 0
|
||||
value :ROUTES, 1
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.ClaimDetails" do
|
||||
optional :claim, :message, 1, "gitlab.cells.topology_service.ClaimRecord"
|
||||
optional :parent, :message, 2, "gitlab.cells.topology_service.ParentRecord"
|
||||
optional :owner, :message, 3, "gitlab.cells.topology_service.OwnerRecord"
|
||||
optional :claim, :message, 1, "gitlab.cells.topology_service.ClaimRecord", json_name: "claim"
|
||||
optional :parent, :message, 2, "gitlab.cells.topology_service.ParentRecord", json_name: "parent"
|
||||
optional :owner, :message, 3, "gitlab.cells.topology_service.OwnerRecord", json_name: "owner"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.ClaimInfo" do
|
||||
optional :id, :int64, 1
|
||||
optional :details, :message, 2, "gitlab.cells.topology_service.ClaimDetails"
|
||||
proto3_optional :cell_info, :message, 3, "gitlab.cells.topology_service.CellInfo"
|
||||
optional :id, :int64, 1, json_name: "id"
|
||||
optional :details, :message, 2, "gitlab.cells.topology_service.ClaimDetails", json_name: "details"
|
||||
proto3_optional :cell_info, :message, 3, "gitlab.cells.topology_service.CellInfo", json_name: "cellInfo"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.CreateClaimRequest" do
|
||||
optional :details, :message, 1, "gitlab.cells.topology_service.ClaimDetails"
|
||||
optional :details, :message, 1, "gitlab.cells.topology_service.ClaimDetails", json_name: "details"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.CreateClaimResponse" do
|
||||
optional :claim, :message, 1, "gitlab.cells.topology_service.ClaimInfo"
|
||||
optional :claim, :message, 1, "gitlab.cells.topology_service.ClaimInfo", json_name: "claim"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ module Gitlab
|
|||
# Restricted read-write service to claim global uniqueness on resources
|
||||
class Service
|
||||
|
||||
include GRPC::GenericService
|
||||
include ::GRPC::GenericService
|
||||
|
||||
self.marshal_class_method = :encode
|
||||
self.unmarshal_class_method = :decode
|
||||
self.service_name = 'gitlab.cells.topology_service.ClaimService'
|
||||
|
||||
rpc :GetCells, Gitlab::Cells::TopologyService::GetCellsRequest, Gitlab::Cells::TopologyService::GetCellsResponse
|
||||
rpc :CreateClaim, Gitlab::Cells::TopologyService::CreateClaimRequest, Gitlab::Cells::TopologyService::CreateClaimResponse
|
||||
rpc :GetCells, ::Gitlab::Cells::TopologyService::GetCellsRequest, ::Gitlab::Cells::TopologyService::GetCellsResponse
|
||||
rpc :CreateClaim, ::Gitlab::Cells::TopologyService::CreateClaimRequest, ::Gitlab::Cells::TopologyService::CreateClaimResponse
|
||||
end
|
||||
|
||||
Stub = Service.rpc_stub_class
|
||||
|
|
|
|||
|
|
@ -3,29 +3,30 @@
|
|||
|
||||
require 'google/protobuf'
|
||||
|
||||
require 'proto/cell_info_pb'
|
||||
require 'google/api/annotations_pb'
|
||||
require 'proto/cell_info_pb'
|
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/classify_service.proto", :syntax => :proto3) do
|
||||
add_message "gitlab.cells.topology_service.ClassifyRequest" do
|
||||
optional :type, :enum, 2, "gitlab.cells.topology_service.ClassifyType"
|
||||
optional :value, :string, 3
|
||||
optional :type, :enum, 2, "gitlab.cells.topology_service.ClassifyType", json_name: "type"
|
||||
optional :value, :string, 3, json_name: "value"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.ProxyInfo" do
|
||||
optional :address, :string, 1
|
||||
optional :address, :string, 1, json_name: "address"
|
||||
end
|
||||
add_message "gitlab.cells.topology_service.ClassifyResponse" do
|
||||
optional :action, :enum, 1, "gitlab.cells.topology_service.ClassifyAction"
|
||||
optional :proxy, :message, 2, "gitlab.cells.topology_service.ProxyInfo"
|
||||
optional :action, :enum, 1, "gitlab.cells.topology_service.ClassifyAction", json_name: "action"
|
||||
optional :proxy, :message, 2, "gitlab.cells.topology_service.ProxyInfo", json_name: "proxy"
|
||||
end
|
||||
add_enum "gitlab.cells.topology_service.ClassifyType" do
|
||||
value :UnknownType, 0
|
||||
value :FirstCell, 1
|
||||
value :SessionPrefix, 2
|
||||
value :UNSPECIFIED, 0
|
||||
value :FIRST_CELL, 1
|
||||
value :SESSION_PREFIX, 2
|
||||
end
|
||||
add_enum "gitlab.cells.topology_service.ClassifyAction" do
|
||||
value :UnknownAction, 0
|
||||
value :Proxy, 1
|
||||
value :ACTION_UNSPECIFIED, 0
|
||||
value :PROXY, 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@ module Gitlab
|
|||
# Public read-only service used by various Routing Services
|
||||
class Service
|
||||
|
||||
include GRPC::GenericService
|
||||
include ::GRPC::GenericService
|
||||
|
||||
self.marshal_class_method = :encode
|
||||
self.unmarshal_class_method = :decode
|
||||
self.service_name = 'gitlab.cells.topology_service.ClassifyService'
|
||||
|
||||
rpc :GetCells, Gitlab::Cells::TopologyService::GetCellsRequest, Gitlab::Cells::TopologyService::GetCellsResponse
|
||||
rpc :Classify, Gitlab::Cells::TopologyService::ClassifyRequest, Gitlab::Cells::TopologyService::ClassifyResponse
|
||||
rpc :GetCells, ::Gitlab::Cells::TopologyService::GetCellsRequest, ::Gitlab::Cells::TopologyService::GetCellsResponse
|
||||
rpc :Classify, ::Gitlab::Cells::TopologyService::ClassifyRequest, ::Gitlab::Cells::TopologyService::ClassifyResponse
|
||||
end
|
||||
|
||||
Stub = Service.rpc_stub_class
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
require 'google/protobuf'
|
||||
|
||||
require 'google/api/annotations_pb'
|
||||
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/health_service.proto", :syntax => :proto3) do
|
||||
add_message "gitlab.cells.topology_service.ReadinessProbeRequest" do
|
||||
|
|
|
|||
|
|
@ -11,16 +11,16 @@ module Gitlab
|
|||
# Public read-only service
|
||||
class Service
|
||||
|
||||
include GRPC::GenericService
|
||||
include ::GRPC::GenericService
|
||||
|
||||
self.marshal_class_method = :encode
|
||||
self.unmarshal_class_method = :decode
|
||||
self.service_name = 'gitlab.cells.topology_service.HealthService'
|
||||
|
||||
# (Lightweight) Used for checking if application is ready to accept requests
|
||||
rpc :ReadinessProbe, Gitlab::Cells::TopologyService::ReadinessProbeRequest, Gitlab::Cells::TopologyService::ReadinessProbeResponse
|
||||
rpc :ReadinessProbe, ::Gitlab::Cells::TopologyService::ReadinessProbeRequest, ::Gitlab::Cells::TopologyService::ReadinessProbeResponse
|
||||
# (Lightweight) Used for checking if application is alive, or whether it should be restarted
|
||||
rpc :LivenessProbe, Gitlab::Cells::TopologyService::LivenessProbeRequest, Gitlab::Cells::TopologyService::LivenessProbeResponse
|
||||
rpc :LivenessProbe, ::Gitlab::Cells::TopologyService::LivenessProbeRequest, ::Gitlab::Cells::TopologyService::LivenessProbeResponse
|
||||
end
|
||||
|
||||
Stub = Service.rpc_stub_class
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: proto/sequence_service.proto
|
||||
|
||||
require 'google/protobuf'
|
||||
|
||||
require 'proto/cell_info_pb'
|
||||
Google::Protobuf::DescriptorPool.generated_pool.build do
|
||||
add_file("proto/sequence_service.proto", :syntax => :proto3) do
|
||||
end
|
||||
end
|
||||
|
||||
module Gitlab
|
||||
module Cells
|
||||
module TopologyService
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# Source: proto/sequence_service.proto for package 'Gitlab.Cells.TopologyService'
|
||||
|
||||
require 'grpc'
|
||||
require 'proto/sequence_service_pb'
|
||||
|
||||
module Gitlab
|
||||
module Cells
|
||||
module TopologyService
|
||||
module SequenceService
|
||||
# Restricted read-write service to provide cluster-wide primary key uniqueness
|
||||
class Service
|
||||
|
||||
include GRPC::GenericService
|
||||
|
||||
self.marshal_class_method = :encode
|
||||
self.unmarshal_class_method = :decode
|
||||
self.service_name = 'gitlab.cells.topology_service.SequenceService'
|
||||
|
||||
rpc :GetCells, Gitlab::Cells::TopologyService::GetCellsRequest, Gitlab::Cells::TopologyService::GetCellsResponse
|
||||
end
|
||||
|
||||
Stub = Service.rpc_stub_class
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in New Issue