Commit 5b4f985a authored by James Lopez's avatar James Lopez

Merge branch 'rollout-pat-revoke-gma' into 'master'

PAT revoke for managed account FF cleanup [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!56427
parents 52c4b9a7 82bf4022
---
title: Personal access token revoke for managed accounts (feature flag removed)
merge_request: 56427
author:
type: added
...@@ -84,6 +84,16 @@ To access the Credentials inventory of a group, navigate to **{shield}** **Secur ...@@ -84,6 +84,16 @@ To access the Credentials inventory of a group, navigate to **{shield}** **Secur
This feature is similar to the [Credentials inventory for self-managed instances](../../admin_area/credentials_inventory.md). This feature is similar to the [Credentials inventory for self-managed instances](../../admin_area/credentials_inventory.md).
### Revoke a group-managed account's personal access token
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214811) in GitLab 13.5.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/267184) in GitLab 13.10.
Group owners can revoke the personal access tokens of accounts in their group. To do so, select
the Personal Access Tokens tab, and select Revoke.
When a personal access token is revoked, the group-managed account user is notified by email.
## Limiting lifetime of personal access tokens of users in Group-managed accounts **(ULTIMATE)** ## Limiting lifetime of personal access tokens of users in Group-managed accounts **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118893) in GitLab 12.10. > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118893) in GitLab 12.10.
......
...@@ -6,7 +6,7 @@ class Admin::CredentialsController < Admin::ApplicationController ...@@ -6,7 +6,7 @@ class Admin::CredentialsController < Admin::ApplicationController
include Analytics::UniqueVisitsHelper include Analytics::UniqueVisitsHelper
helper_method :credentials_inventory_path, :user_detail_path, :personal_access_token_revoke_path, helper_method :credentials_inventory_path, :user_detail_path, :personal_access_token_revoke_path,
:revoke_button_available?, :ssh_key_delete_path, :gpg_keys_available? :ssh_key_delete_path, :gpg_keys_available?
before_action :check_license_credentials_inventory_available!, only: [:index, :revoke, :destroy] before_action :check_license_credentials_inventory_available!, only: [:index, :revoke, :destroy]
before_action :check_gpg_keys_list_enabled!, only: [:index] before_action :check_gpg_keys_list_enabled!, only: [:index]
...@@ -50,11 +50,6 @@ class Admin::CredentialsController < Admin::ApplicationController ...@@ -50,11 +50,6 @@ class Admin::CredentialsController < Admin::ApplicationController
revoke_admin_credential_path(token) revoke_admin_credential_path(token)
end end
override :revoke_button_available?
def revoke_button_available?
true
end
override :gpg_keys_available? override :gpg_keys_available?
def gpg_keys_available? def gpg_keys_available?
Feature.enabled?(:credential_inventory_gpg_keys, default_enabled: :yaml) Feature.enabled?(:credential_inventory_gpg_keys, default_enabled: :yaml)
......
...@@ -8,7 +8,7 @@ class Groups::Security::CredentialsController < Groups::ApplicationController ...@@ -8,7 +8,7 @@ class Groups::Security::CredentialsController < Groups::ApplicationController
include Groups::SecurityFeaturesHelper include Groups::SecurityFeaturesHelper
helper_method :credentials_inventory_path, :user_detail_path, :personal_access_token_revoke_path, helper_method :credentials_inventory_path, :user_detail_path, :personal_access_token_revoke_path,
:revoke_button_available?, :ssh_key_delete_path :ssh_key_delete_path
before_action :validate_group_level_credentials_inventory_available!, only: [:index, :revoke, :destroy] before_action :validate_group_level_credentials_inventory_available!, only: [:index, :revoke, :destroy]
before_action :check_gpg_keys_list_enabled!, only: [:index] before_action :check_gpg_keys_list_enabled!, only: [:index]
...@@ -45,11 +45,6 @@ class Groups::Security::CredentialsController < Groups::ApplicationController ...@@ -45,11 +45,6 @@ class Groups::Security::CredentialsController < Groups::ApplicationController
revoke_group_security_credential_path(group, token) revoke_group_security_credential_path(group, token)
end end
override :revoke_button_available?
def revoke_button_available?
::Feature.enabled?(:revoke_managed_users_token, group)
end
override :users override :users
def users def users
group.managed_users group.managed_users
......
...@@ -21,10 +21,6 @@ module CredentialsInventoryHelper ...@@ -21,10 +21,6 @@ module CredentialsInventoryHelper
License.feature_available?(:credentials_inventory) License.feature_available?(:credentials_inventory)
end end
def revoke_button_available?
false
end
def gpg_keys_available? def gpg_keys_available?
false false
end end
......
...@@ -22,7 +22,6 @@ module EE ...@@ -22,7 +22,6 @@ module EE
def managed_user_revocation_allowed? def managed_user_revocation_allowed?
return unless token.present? return unless token.present?
return unless ::Feature.enabled?(:revoke_managed_users_token, group)
token.user&.group_managed_account? && token.user&.group_managed_account? &&
token.user&.managing_group == group && token.user&.managing_group == group &&
......
...@@ -27,5 +27,5 @@ ...@@ -27,5 +27,5 @@
- if personal_access_token.revoked? - if personal_access_token.revoked?
-# We're inferring the revoked date from the last updated_at, see https://gitlab.com/gitlab-org/gitlab/-/issues/218046#note_362875952 -# We're inferring the revoked date from the last updated_at, see https://gitlab.com/gitlab-org/gitlab/-/issues/218046#note_362875952
= personal_access_token.updated_at.to_date = personal_access_token.updated_at.to_date
- elsif revoke_button_available? && personal_access_token.active? - elsif personal_access_token.active?
= link_to _('Revoke'), personal_access_token_revoke_path(personal_access_token), method: :put, data: { confirm: _('Are you sure you want to revoke this personal access token? This action cannot be undone.') }, class: 'btn btn-danger btn-danger-secondary btn-md btn-secondary gl-button' = link_to _('Revoke'), personal_access_token_revoke_path(personal_access_token), method: :put, data: { confirm: _('Are you sure you want to revoke this personal access token? This action cannot be undone.') }, class: 'btn btn-danger btn-danger-secondary btn-md btn-secondary gl-button'
---
name: revoke_managed_users_token
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44783
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267184
milestone: '13.5'
type: development
group: group::compliance
default_enabled: false
...@@ -173,118 +173,81 @@ RSpec.describe Groups::Security::CredentialsController do ...@@ -173,118 +173,81 @@ RSpec.describe Groups::Security::CredentialsController do
context 'when `credentials_inventory` feature is enabled' do context 'when `credentials_inventory` feature is enabled' do
before do before do
stub_licensed_features(credentials_inventory: true, group_saml: true) stub_licensed_features(credentials_inventory: true, group_saml: true)
stub_feature_flags(revoke_managed_users_token: true)
end end
context 'for a group that enforces group managed accounts' do context 'for a group that enforces group managed accounts' do
context 'when `revoke_managed_users_token` feature is enabled' do context 'for a user with access to view credentials inventory' do
before_all do context 'non-existent personal access token specified' do
stub_feature_flags(revoke_managed_users_token: true) let(:token_id) { 999999999999999999999999999999999 }
it_behaves_like 'responds with 404'
end end
context 'for a user with access to view credentials inventory' do describe 'with an existing personal access token' do
context 'non-existent personal access token specified' do context 'personal access token is already revoked' do
let(:token_id) { 999999999999999999999999999999999 } let_it_be(:token_id) { create(:personal_access_token, revoked: true, user: maintainer).id }
it_behaves_like 'responds with 404' it_behaves_like 'displays the flash success message'
end end
describe 'with an existing personal access token' do context 'personal access token is already expired' do
context 'personal access token is already revoked' do let_it_be(:token_id) { create(:personal_access_token, expires_at: 5.days.ago, user: maintainer).id }
let_it_be(:token_id) { create(:personal_access_token, revoked: true, user: maintainer).id }
it_behaves_like 'displays the flash success message'
end
context 'personal access token is already expired' do it_behaves_like 'displays the flash success message'
let_it_be(:token_id) { create(:personal_access_token, expires_at: 5.days.ago, user: maintainer).id } end
it_behaves_like 'displays the flash success message' context 'does not have permissions to revoke the credential' do
end let_it_be(:token_id) { create(:personal_access_token, user: create(:user)).id }
context 'does not have permissions to revoke the credential' do it_behaves_like 'responds with 404'
let_it_be(:token_id) { create(:personal_access_token, user: create(:user)).id } end
it_behaves_like 'responds with 404' context 'personal access token is already revoked' do
end let_it_be(:token_id) { create(:personal_access_token, revoked: true, user: maintainer).id }
context 'personal access token is already revoked' do it_behaves_like 'displays the flash success message'
let_it_be(:token_id) { create(:personal_access_token, revoked: true, user: maintainer).id } end
it_behaves_like 'displays the flash success message' context 'personal access token is already expired' do
end let_it_be(:token_id) { create(:personal_access_token, expires_at: 5.days.ago, user: maintainer).id }
context 'personal access token is already expired' do it_behaves_like 'displays the flash success message'
let_it_be(:token_id) { create(:personal_access_token, expires_at: 5.days.ago, user: maintainer).id } end
it_behaves_like 'displays the flash success message' context 'personal access token is not revoked or expired' do
end let_it_be(:token_id) { personal_access_token.id }
context 'personal access token is not revoked or expired' do it_behaves_like 'displays the flash success message'
let_it_be(:token_id) { personal_access_token.id }
it_behaves_like 'displays the flash success message' it 'informs the token owner' do
expect(CredentialsInventoryMailer).to receive_message_chain(:personal_access_token_revoked_email, :deliver_later)
it 'informs the token owner' do put revoke_group_security_credential_path(group_id: group_id.to_param, id: personal_access_token.id)
expect(CredentialsInventoryMailer).to receive_message_chain(:personal_access_token_revoked_email, :deliver_later) end
put revoke_group_security_credential_path(group_id: group_id.to_param, id: personal_access_token.id) context 'when credentials_inventory_revocation_emails flag is disabled' do
before do
stub_feature_flags(credentials_inventory_revocation_emails: false)
end end
context 'when credentials_inventory_revocation_emails flag is disabled' do it 'does not inform the token owner' do
before do expect do
stub_feature_flags(credentials_inventory_revocation_emails: false) put revoke_group_security_credential_path(group_id: group_id.to_param, id: personal_access_token.id)
end end.not_to change { ActionMailer::Base.deliveries.size }
it 'does not inform the token owner' do
expect do
put revoke_group_security_credential_path(group_id: group_id.to_param, id: personal_access_token.id)
end.not_to change { ActionMailer::Base.deliveries.size }
end
end end
end end
end end
end end
context 'for a user without access to view credentials inventory' do
let_it_be(:token_id) { create(:personal_access_token, user: owner).id }
before do
sign_in(maintainer)
end
it_behaves_like 'responds with 404'
end
end end
context 'when `revoke_managed_users_token` feature is disabled' do context 'for a user without access to view credentials inventory' do
before_all do let_it_be(:token_id) { create(:personal_access_token, user: owner).id }
stub_feature_flags(revoke_managed_users_token: false)
end
context 'for a user with access to view credentials inventory' do
context 'non-existent personal access token specified' do
let(:token_id) { 999999999999999999999999999999999 }
it_behaves_like 'responds with 404'
end
context 'valid personal access token specified' do
let_it_be(:token_id) { create(:personal_access_token, user: create(:user)).id }
it_behaves_like 'responds with 404' before do
end sign_in(maintainer)
end end
context 'for a user without access to view credentials inventory' do it_behaves_like 'responds with 404'
let_it_be(:token_id) { create(:personal_access_token, user: owner).id }
before do
sign_in(maintainer)
end
it_behaves_like 'responds with 404'
end
end end
end end
......
...@@ -42,17 +42,6 @@ RSpec.describe EE::PersonalAccessTokens::RevokeService do ...@@ -42,17 +42,6 @@ RSpec.describe EE::PersonalAccessTokens::RevokeService do
end end
end end
context 'when feature flag is disabled' do
let_it_be(:current_user) { group_owner }
let_it_be(:token) { create(:personal_access_token, user: managed_user) }
before do
stub_feature_flags(revoke_managed_users_token: false)
end
it_behaves_like 'an unsuccessfully revoked token'
end
context 'when current user is a group owner of a different managed group' do context 'when current user is a group owner of a different managed group' do
let_it_be(:group) { create(:group_with_managed_accounts) } let_it_be(:group) { create(:group_with_managed_accounts) }
let_it_be(:group_owner2) { create(:user) } let_it_be(:group_owner2) { create(:user) }
......
...@@ -12,7 +12,6 @@ RSpec.describe('shared/credentials_inventory/personal_access_tokens/_personal_ac ...@@ -12,7 +12,6 @@ RSpec.describe('shared/credentials_inventory/personal_access_tokens/_personal_ac
allow(view).to receive(:user_detail_path).and_return('abcd') allow(view).to receive(:user_detail_path).and_return('abcd')
allow(view).to receive(:personal_access_token_revoke_path).and_return('revoke') allow(view).to receive(:personal_access_token_revoke_path).and_return('revoke')
allow(view).to receive(:revoke_button_available?).and_return(false)
render 'shared/credentials_inventory/personal_access_tokens/personal_access_token', personal_access_token: personal_access_token render 'shared/credentials_inventory/personal_access_tokens/personal_access_token', personal_access_token: personal_access_token
end end
...@@ -36,61 +35,31 @@ RSpec.describe('shared/credentials_inventory/personal_access_tokens/_personal_ac ...@@ -36,61 +35,31 @@ RSpec.describe('shared/credentials_inventory/personal_access_tokens/_personal_ac
context 'revoked date' do context 'revoked date' do
let_it_be(:updated_at_date) { 10.days.ago } let_it_be(:updated_at_date) { 10.days.ago }
context 'without revoke button available' do before do
context 'when revoked is set' do render 'shared/credentials_inventory/personal_access_tokens/personal_access_token', personal_access_token: personal_access_token
let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date, revoked: true)} end
it 'shows the revoked on date' do context 'when revoked is set' do
expect(rendered).to have_text(updated_at_date.to_date.to_s) let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date, revoked: true)}
end
it 'does not show the revoke button' do it 'shows the revoked on date' do
expect(rendered).not_to have_css('a.btn', text: 'Revoke') expect(rendered).to have_text(updated_at_date.to_date.to_s)
end
end end
context 'when revoked is not set' do it 'does not show the revoke button' do
let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date)} expect(rendered).not_to have_css('a.btn', text: 'Revoke')
it 'does not show the revoked on date' do
expect(rendered).not_to have_text(updated_at_date.to_date.to_s)
end
it 'does not show the revoke button' do
expect(rendered).not_to have_css('a.btn', text: 'Revoke')
end
end end
end end
context 'with revoke button available' do context 'when revoked is not set' do
before do let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date)}
allow(view).to receive(:revoke_button_available?).and_return(true)
render 'shared/credentials_inventory/personal_access_tokens/personal_access_token', personal_access_token: personal_access_token it 'does not show the revoked on date' do
expect(rendered).not_to have_text(updated_at_date.to_date.to_s)
end end
context 'when revoked is set' do it 'shows the revoke button' do
let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date, revoked: true)} expect(rendered).to have_css('a.btn', text: 'Revoke')
it 'shows the revoked on date' do
expect(rendered).to have_text(updated_at_date.to_date.to_s)
end
it 'does not show the revoke button' do
expect(rendered).not_to have_css('a.btn', text: 'Revoke')
end
end
context 'when revoked is not set' do
let_it_be(:personal_access_token) { build_stubbed(:personal_access_token, user: user, updated_at: updated_at_date)}
it 'does not show the revoked on date' do
expect(rendered).not_to have_text(updated_at_date.to_date.to_s)
end
it 'shows the revoke button' do
expect(rendered).to have_css('a.btn', text: 'Revoke')
end
end end
end end
end end
......
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