Commit 5f961f65 authored by peterhegman's avatar peterhegman

Add "Enterprise" badge to users that are provisioned via SAML/SCIM

Add an "Enterprise" badge to group members that are provisioned via
SAML/SCIM

Changelog: added
EE: true
parent c61122f9
...@@ -175,6 +175,10 @@ We recommend users do this prior to turning on sync, because while synchronizati ...@@ -175,6 +175,10 @@ We recommend users do this prior to turning on sync, because while synchronizati
New users and existing users on subsequent visits can access the group through the identify provider's dashboard or by visiting links directly. New users and existing users on subsequent visits can access the group through the identify provider's dashboard or by visiting links directly.
GitLab users that were created with a SCIM identity will be displayed with an **Enterprise** badge in the **Members** view.
![Enterprise badge for users created with a SCIM identity](img/member_enterprise_badge_v14_0.png)
For role information, please see the [Group SAML page](index.md#user-access-and-management) For role information, please see the [Group SAML page](index.md#user-access-and-management)
### Blocking access ### Blocking access
......
...@@ -32,6 +32,11 @@ export const generateBadges = ({ member, isCurrentUser, canManageMembers }) => [ ...@@ -32,6 +32,11 @@ export const generateBadges = ({ member, isCurrentUser, canManageMembers }) => [
text: __('LDAP'), text: __('LDAP'),
variant: 'info', variant: 'info',
}, },
{
show: member.provisionedByThisGroup,
text: __('Enterprise'),
variant: 'info',
},
]; ];
export const canOverride = (member) => member.canOverride && isDirectMember(member); export const canOverride = (member) => member.canOverride && isDirectMember(member);
...@@ -81,6 +81,10 @@ module EE ...@@ -81,6 +81,10 @@ module EE
end end
end end
def provisioned_by_this_group?
user&.user_detail&.provisioned_by_group_id == source_id
end
private private
override :access_level_inclusion override :access_level_inclusion
...@@ -152,9 +156,5 @@ module EE ...@@ -152,9 +156,5 @@ module EE
def send_welcome_email? def send_welcome_email?
!provisioned_by_this_group? !provisioned_by_this_group?
end end
def provisioned_by_this_group?
user.user_detail.provisioned_by_group_id == source_id
end
end end
end end
...@@ -11,6 +11,7 @@ module EE ...@@ -11,6 +11,7 @@ module EE
ActiveRecord::Associations::Preloader.new.preload(members, user: { group_saml_identities: :saml_provider }) ActiveRecord::Associations::Preloader.new.preload(members, user: { group_saml_identities: :saml_provider })
ActiveRecord::Associations::Preloader.new.preload(members, user: { oncall_participants: { rotation: :schedule } }) ActiveRecord::Associations::Preloader.new.preload(members, user: { oncall_participants: { rotation: :schedule } })
ActiveRecord::Associations::Preloader.new.preload(members, user: :oncall_schedules) ActiveRecord::Associations::Preloader.new.preload(members, user: :oncall_schedules)
ActiveRecord::Associations::Preloader.new.preload(members, user: :user_detail)
end end
end end
end end
...@@ -33,5 +33,9 @@ module EE ...@@ -33,5 +33,9 @@ module EE
errors.add(:user, _('is not in the group enforcing Group Managed Account')) errors.add(:user, _('is not in the group enforcing Group Managed Account'))
end end
end end
def provisioned_by_this_group?
false
end
end end
end end
...@@ -18,6 +18,8 @@ module EE ...@@ -18,6 +18,8 @@ module EE
end end
expose :override, as: :is_overridden expose :override, as: :is_overridden
expose :provisioned_by_this_group?, as: :provisioned_by_this_group
end end
private private
......
...@@ -8,14 +8,16 @@ ...@@ -8,14 +8,16 @@
"group_sso", "group_sso",
"group_managed_account", "group_managed_account",
"can_override", "can_override",
"is_overridden" "is_overridden",
"provisioned_by_this_group"
], ],
"properties": { "properties": {
"using_license": { "type": ["boolean", "null"] }, "using_license": { "type": ["boolean", "null"] },
"group_sso": { "type": ["boolean", "null"] }, "group_sso": { "type": ["boolean", "null"] },
"group_managed_account": { "type": ["boolean", "null"] }, "group_managed_account": { "type": ["boolean", "null"] },
"can_override": { "type": ["boolean"] }, "can_override": { "type": ["boolean"] },
"is_overridden": { "type": ["boolean"] } "is_overridden": { "type": ["boolean"] },
"provisioned_by_this_group": { "type": ["boolean"] }
} }
} }
] ]
......
...@@ -22,11 +22,12 @@ describe('Members Utils', () => { ...@@ -22,11 +22,12 @@ describe('Members Utils', () => {
}); });
it.each` it.each`
member | expected member | expected
${{ ...memberMock, usingLicense: true }} | ${{ show: true, text: 'Is using seat', variant: 'neutral' }} ${{ ...memberMock, usingLicense: true }} | ${{ show: true, text: 'Is using seat', variant: 'neutral' }}
${{ ...memberMock, groupSso: true }} | ${{ show: true, text: 'SAML', variant: 'info' }} ${{ ...memberMock, groupSso: true }} | ${{ show: true, text: 'SAML', variant: 'info' }}
${{ ...memberMock, groupManagedAccount: true }} | ${{ show: true, text: 'Managed Account', variant: 'info' }} ${{ ...memberMock, groupManagedAccount: true }} | ${{ show: true, text: 'Managed Account', variant: 'info' }}
${{ ...memberMock, canOverride: true }} | ${{ show: true, text: 'LDAP', variant: 'info' }} ${{ ...memberMock, canOverride: true }} | ${{ show: true, text: 'LDAP', variant: 'info' }}
${{ ...memberMock, provisionedByThisGroup: true }} | ${{ show: true, text: 'Enterprise', variant: 'info' }}
`('returns expected output for "$expected.text" badge', ({ member, expected }) => { `('returns expected output for "$expected.text" badge', ({ member, expected }) => {
expect( expect(
generateBadges({ member, isCurrentUser: true, canManageMembers: true }), generateBadges({ member, isCurrentUser: true, canManageMembers: true }),
......
...@@ -400,6 +400,32 @@ RSpec.describe GroupMember do ...@@ -400,6 +400,32 @@ RSpec.describe GroupMember do
end end
end end
describe '#provisioned_by_this_group?' do
let_it_be(:group) { create(:group) }
let(:user) { build(:user) }
let(:member) { build(:group_member, group: group, user: user) }
let(:invited) { build(:group_member, :invited, group: group, user: user) }
subject { member.provisioned_by_this_group? }
context 'when user is provisioned by the group' do
let!(:user_detail) { build(:user_detail, user: user, provisioned_by_group_id: group.id) }
it { is_expected.to eq(true) }
end
context 'when user is not provisioned by the group' do
it { is_expected.to eq(false) }
end
context 'when member does not have a related user (invited member)' do
it 'returns `false`' do
expect(invited.provisioned_by_this_group?).to eq(false)
end
end
end
def webhook_data(group_member, event) def webhook_data(group_member, event)
{ {
headers: { 'Content-Type' => 'application/json', 'User-Agent' => "GitLab/#{Gitlab::VERSION}", 'X-Gitlab-Event' => 'Member Hook' }, headers: { 'Content-Type' => 'application/json', 'User-Agent' => "GitLab/#{Gitlab::VERSION}", 'X-Gitlab-Event' => 'Member Hook' },
......
...@@ -88,4 +88,12 @@ RSpec.describe ProjectMember do ...@@ -88,4 +88,12 @@ RSpec.describe ProjectMember do
end end
end end
end end
describe '#provisioned_by_this_group?' do
let_it_be(:member) { build(:project_member) }
subject { member.provisioned_by_this_group? }
it { is_expected.to eq(false) }
end
end end
...@@ -37,6 +37,12 @@ RSpec.describe MemberEntity do ...@@ -37,6 +37,12 @@ RSpec.describe MemberEntity do
expect(entity_hash[:can_override]).to be(true) expect(entity_hash[:can_override]).to be(true)
end end
it 'correctly exposes `provisioned_by_this_group`' do
allow(member).to receive(:provisioned_by_this_group?).and_return(true)
expect(entity_hash[:provisioned_by_this_group]).to be(true)
end
end end
context 'group member' do context 'group member' do
......
...@@ -12382,6 +12382,9 @@ msgstr "" ...@@ -12382,6 +12382,9 @@ msgstr ""
msgid "Enter your password to approve" msgid "Enter your password to approve"
msgstr "" msgstr ""
msgid "Enterprise"
msgstr ""
msgid "Environment" msgid "Environment"
msgstr "" msgstr ""
......
...@@ -30,6 +30,7 @@ export const member = { ...@@ -30,6 +30,7 @@ export const member = {
usingLicense: false, usingLicense: false,
groupSso: false, groupSso: false,
groupManagedAccount: false, groupManagedAccount: false,
provisionedByThisGroup: false,
validRoles: { validRoles: {
Guest: 10, Guest: 10,
Reporter: 20, Reporter: 20,
......
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