Commit f8a18573 authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '347270-feature-flag-rollout-of-scim_token_vue' into 'master'

Remove `scim_token_vue` feature flag

See merge request gitlab-org/gitlab!78220
parents 9bf856f4 a99950d4
---
name: scim_token_vue
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74743
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347270
milestone: '14.6'
type: development
group: group::access
default_enabled: true
import createFlash from '~/flash';
import { __ } from '~/locale';
import SCIMTokenService from './scim_token_service';
export default class SCIMTokenToggleArea {
constructor(generateSelector, formSelector, groupPath) {
this.generateContainer = document.querySelector(generateSelector);
this.formContainer = document.querySelector(formSelector);
this.scimLoadingSpinner = document.querySelector('.js-scim-loading-container');
this.generateButton = this.generateContainer.querySelector('.js-generate-scim-token');
this.resetButton = this.formContainer.querySelector('.js-reset-scim-token');
this.scimTokenInput = this.formContainer.querySelector('#scim_token');
this.scimEndpointUrl = this.formContainer.querySelector('#scim_endpoint_url');
this.generateButton.addEventListener('click', () => this.generateSCIMToken());
this.resetButton.addEventListener('click', () => this.resetSCIMToken());
this.service = new SCIMTokenService(groupPath);
}
setSCIMTokenValue(value) {
this.scimTokenInput.value = value;
}
setSCIMEndpointURL(value) {
this.scimEndpointUrl.value = value;
}
toggleSCIMTokenHelperText() {
this.formContainer.querySelector('.input-group-append').classList.toggle('d-none');
this.formContainer
.querySelector('.js-scim-token-helper-text span:first-of-type')
.classList.toggle('d-none');
this.formContainer
.querySelector('.js-scim-token-helper-text span:last-of-type')
.classList.toggle('d-none');
}
// eslint-disable-next-line class-methods-use-this
toggleFormVisibility(form) {
form.classList.toggle('d-none');
}
setSCIMTokenFormTitle(title) {
this.formContainer.querySelector('label:first-of-type').innerHTML = title;
}
toggleLoading() {
this.scimLoadingSpinner.classList.toggle('d-none');
}
setTokenAndToggleSCIMForm(data) {
this.setSCIMTokenValue(data.scim_token);
this.setSCIMEndpointURL(data.scim_api_url);
this.setSCIMTokenFormTitle(__('Your new SCIM token'));
this.toggleSCIMTokenHelperText();
this.toggleLoading();
this.toggleFormVisibility(this.formContainer);
}
fetchNewToken() {
return this.service.generateNewSCIMToken();
}
handleTokenGeneration(container) {
this.toggleFormVisibility(container);
this.toggleLoading();
return this.fetchNewToken()
.then((response) => {
this.setTokenAndToggleSCIMForm(response.data);
})
.catch((error) => {
createFlash({
message: error,
});
this.toggleLoading();
this.toggleFormVisibility(container);
throw error;
});
}
generateSCIMToken() {
return this.handleTokenGeneration(this.generateContainer);
}
resetSCIMToken() {
if (
// eslint-disable-next-line no-alert
window.confirm(
__(
'Are you sure you want to reset the SCIM token? SCIM provisioning will stop working until the new token is updated.',
),
)
) {
return this.handleTokenGeneration(this.formContainer);
}
return Promise.resolve();
}
}
import Vue from 'vue'; import Vue from 'vue';
import SCIMTokenToggleArea from 'ee/saml_providers/scim_token_toggle_area';
import ScimToken from './components/scim_token.vue'; import ScimToken from './components/scim_token.vue';
import { AUTO_REDIRECT_TO_PROVIDER_BUTTON_SELECTOR } from './constants'; import { AUTO_REDIRECT_TO_PROVIDER_BUTTON_SELECTOR } from './constants';
...@@ -18,19 +16,7 @@ export const redirectUserWithSSOIdentity = () => { ...@@ -18,19 +16,7 @@ export const redirectUserWithSSOIdentity = () => {
export const initScimTokenApp = () => { export const initScimTokenApp = () => {
const el = document.getElementById('js-scim-token-app'); const el = document.getElementById('js-scim-token-app');
if (!el) { if (!el) return null;
// `scim_token_vue` feature flag is disabled, load legacy JS.
const groupPath = document.querySelector('#issuer').value;
// eslint-disable-next-line no-new
new SCIMTokenToggleArea(
'.js-generate-scim-token-container',
'.js-scim-token-container',
groupPath,
);
return false;
}
const { endpointUrl, generateTokenPath } = el.dataset; const { endpointUrl, generateTokenPath } = el.dataset;
......
- value = local_assigns[:value]
= label_tag field, label_text, class: 'label-bold'
.clipboard-input-group.input-group
= text_field_tag field, value, class: "js-select-on-focus form-control", readonly: true, aria: { label: label_text }
.input-group-append{ class: "#{ 'd-none' unless show_clipboard }" }
= clipboard_button(target: "##{field}", title: _("Copy URL"), class: "btn-default btn-gray")
- if Feature.enabled?(:scim_token_vue, default_enabled: :yaml)
#js-scim-token-app{ data: { endpoint_url: @scim_token_url, generate_token_path: group_scim_oauth_path } }
- else
- scim_token_not_present = @scim_token_url.nil?
.gl-mt-3.js-generate-scim-token-container{ class: "#{ 'd-none' unless scim_token_not_present}" }
%p= s_('GroupSAML|Generate a SCIM token to set up your System for Cross-Domain Identity Management.')
%button.btn.gl-button.js-generate-scim-token{ type: 'button' }
= s_('GroupSAML|Generate a SCIM token')
.gl-mt-3.js-scim-token-container{ class: "#{ 'd-none' if scim_token_not_present}" }
.well-segment.borderless.mb-3.col-12.col-lg-9.p-0
= render 'scim_row', value: '********************', field: 'scim_token', label_text: s_('GroupSAML|Your SCIM token'), show_clipboard: false
.form-text.text-muted.js-scim-token-helper-text
%span
= s_('GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to ')
%button.btn.gl-button.btn-confirm.btn-link.d-inline.align-baseline.js-reset-scim-token{ type: 'button' }
= _('reset it.')
%span.d-none
= s_("GroupSAML|Make sure you save this token — you won't be able to access it again.")
.well-segment.borderless.col-12.col-lg-9.p-0
= render 'scim_row', value: @scim_token_url, field: 'scim_endpoint_url', label_text: s_('GroupSAML|SCIM API endpoint URL'), show_clipboard: true
.gl-mt-3.text-center.js-scim-loading-container.d-none
.gl-spinner
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
%h4.page-title %h4.page-title
= s_('GroupSAML|SCIM Token') = s_('GroupSAML|SCIM Token')
.col-lg-9 .col-lg-9
= render 'scim_token' #js-scim-token-app{ data: { endpoint_url: @scim_token_url, generate_token_path: group_scim_oauth_path } }
%section.row.border-top.mt-4 %section.row.border-top.mt-4
.col-lg-3.gl-mb-3 .col-lg-3.gl-mb-3
%h4.page-title %h4.page-title
......
...@@ -13,49 +13,6 @@ RSpec.describe 'SCIM Token handling', :js do ...@@ -13,49 +13,6 @@ RSpec.describe 'SCIM Token handling', :js do
stub_licensed_features(group_saml: true) stub_licensed_features(group_saml: true)
end end
context 'when `scim_token_vue` feature flag is disabled' do
before do
stub_feature_flags(scim_token_vue: false)
end
describe 'group has no existing scim token' do
before do
sign_in(user)
visit group_saml_providers_path(group)
end
it 'displays generate token form' do
expect(page).to have_selector('.js-generate-scim-token-container', visible: true)
expect(page).to have_selector('.js-scim-token-container', visible: false)
page.within '.js-generate-scim-token-container' do
expect(page).to have_content('Generate a SCIM token to set up your System for Cross-Domain Identity Management.')
expect(page).to have_button('Generate a SCIM token')
end
end
end
describe 'group has existing scim token' do
let!(:scim_token) { create(:scim_oauth_access_token, group: group) }
before do
sign_in(user)
visit group_saml_providers_path(group)
end
it 'displays the scim form with an obfuscated token' do
expect(page).to have_selector('.js-generate-scim-token-container', visible: false)
expect(page).to have_selector('.js-scim-token-container', visible: true)
page.within '.js-scim-token-container' do
expect(page).to have_button('reset it.')
expect(page.find('#scim_token').value).to eq('********************')
expect(page.find('#scim_endpoint_url').value).to eq(scim_token.as_entity_json[:scim_api_url])
end
end
end
end
def find_token_field def find_token_field
page.find_field('Your SCIM token') page.find_field('Your SCIM token')
end end
......
...@@ -14,7 +14,6 @@ RSpec.describe Groups::SamlProvidersController, '(JavaScript fixtures)', type: : ...@@ -14,7 +14,6 @@ RSpec.describe Groups::SamlProvidersController, '(JavaScript fixtures)', type: :
group.add_owner(user) group.add_owner(user)
allow(Devise).to receive(:omniauth_providers).and_return(%i(group_saml)) allow(Devise).to receive(:omniauth_providers).and_return(%i(group_saml))
stub_licensed_features(group_saml: true) stub_licensed_features(group_saml: true)
stub_feature_flags(scim_token_vue: false)
end end
it 'groups/saml_providers/show.html' do it 'groups/saml_providers/show.html' do
......
import SCIMTokenToggleArea from 'ee/saml_providers/scim_token_toggle_area';
import { TEST_HOST } from 'spec/test_constants';
const mockData = {
data: {
scim_token: 'foobar',
scim_api_url: `${TEST_HOST}/scim/api`,
},
};
const mockGenerateNewSCIMToken = jest.fn(() => Promise.resolve(mockData));
jest.mock('ee/saml_providers/scim_token_service', () => {
return jest.fn(() => {
return { generateNewSCIMToken: mockGenerateNewSCIMToken };
});
});
describe('SCIMTokenToggleArea', () => {
const FIXTURE = 'groups/saml_providers/show.html';
let scimTokenToggleArea;
beforeEach(() => {
loadFixtures(FIXTURE);
scimTokenToggleArea = new SCIMTokenToggleArea(
'.js-generate-scim-token-container',
'.js-scim-token-container',
);
});
describe('constructor', () => {
it('receives a form which displays an obfuscated token', () => {
expect(scimTokenToggleArea.scimTokenInput.value).toBe('********************');
});
it('displays the generate token form and hides the scim token form', () => {
expect(scimTokenToggleArea.generateContainer).not.toHaveClass('d-none');
expect(scimTokenToggleArea.formContainer).toHaveClass('d-none');
});
});
describe('generateSCIMToken', () => {
it('toggles the generate and scim token forms', (done) => {
scimTokenToggleArea
.generateSCIMToken()
.then(() => {
expect(scimTokenToggleArea.generateContainer).toHaveClass('d-none');
expect(scimTokenToggleArea.formContainer).not.toHaveClass('d-none');
})
.then(done)
.catch(done.fail);
});
it('populates the scim form with the token data', (done) => {
scimTokenToggleArea
.generateSCIMToken()
.then(() => {
expect(scimTokenToggleArea.scimTokenInput.value).toBe(mockData.data.scim_token);
expect(scimTokenToggleArea.scimEndpointUrl.value).toBe(mockData.data.scim_api_url);
})
.then(done)
.catch(done.fail);
});
});
describe('resetSCIMToken', () => {
it('does not trigger token generation when the confirm is canceled', () => {
jest.spyOn(window, 'confirm').mockReturnValue(false);
scimTokenToggleArea.resetSCIMToken();
expect(mockGenerateNewSCIMToken).not.toHaveBeenCalled();
});
it('populates the scim form with the token data if the confirm is accepted', (done) => {
jest.spyOn(window, 'confirm').mockReturnValue(true);
scimTokenToggleArea
.resetSCIMToken()
.then(() => {
expect(scimTokenToggleArea.scimTokenInput.value).toBe(mockData.data.scim_token);
expect(scimTokenToggleArea.scimEndpointUrl.value).toBe(mockData.data.scim_api_url);
})
.then(done)
.catch(done.fail);
});
});
});
...@@ -4712,9 +4712,6 @@ msgstr "" ...@@ -4712,9 +4712,6 @@ msgstr ""
msgid "Are you sure you want to remove this list?" msgid "Are you sure you want to remove this list?"
msgstr "" msgstr ""
msgid "Are you sure you want to reset the SCIM token? SCIM provisioning will stop working until the new token is updated."
msgstr ""
msgid "Are you sure you want to reset the health check token?" msgid "Are you sure you want to reset the health check token?"
msgstr "" msgstr ""
...@@ -17057,18 +17054,12 @@ msgstr "" ...@@ -17057,18 +17054,12 @@ msgstr ""
msgid "GroupSAML|SAML group link was successfully removed." msgid "GroupSAML|SAML group link was successfully removed."
msgstr "" msgstr ""
msgid "GroupSAML|SCIM API endpoint URL"
msgstr ""
msgid "GroupSAML|SCIM Token" msgid "GroupSAML|SCIM Token"
msgstr "" msgstr ""
msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"." msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
msgstr "" msgstr ""
msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to "
msgstr ""
msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to %{linkStart}reset it%{linkEnd}." msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to %{linkStart}reset it%{linkEnd}."
msgstr "" msgstr ""
...@@ -17093,9 +17084,6 @@ msgstr "" ...@@ -17093,9 +17084,6 @@ msgstr ""
msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group." msgid "GroupSAML|With prohibit outer forks flag enabled group members will be able to fork project only inside your group."
msgstr "" msgstr ""
msgid "GroupSAML|Your SCIM token"
msgstr ""
msgid "GroupSAML|as %{access_level}" msgid "GroupSAML|as %{access_level}"
msgstr "" msgstr ""
...@@ -41415,9 +41403,6 @@ msgstr "" ...@@ -41415,9 +41403,6 @@ msgstr ""
msgid "Your new %{type}" msgid "Your new %{type}"
msgstr "" msgstr ""
msgid "Your new SCIM token"
msgstr ""
msgid "Your new access token has been created." msgid "Your new access token has been created."
msgstr "" msgstr ""
...@@ -43156,9 +43141,6 @@ msgstr "" ...@@ -43156,9 +43141,6 @@ msgstr ""
msgid "required" msgid "required"
msgstr "" msgstr ""
msgid "reset it."
msgstr ""
msgid "satisfied" msgid "satisfied"
msgstr "" msgstr ""
......
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