Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Indiquer si l'utilisateur se connecte via SSO sur Pix admin (PIX-14788) #11310

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions admin/app/components/users/user-overview.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ export default class UserOverview extends Component {
@service pixToast;
@service references;
@service store;
@service oidcIdentityProviders;

@tracked displayAnonymizeModal = false;
@tracked isEditionMode = false;
@tracked authenticationMethods = [];

languages = this.references.availableLanguages;
locales = this.references.availableLocales;
Expand All @@ -39,6 +41,9 @@ export default class UserOverview extends Component {
constructor() {
super(...arguments);
this.form = this.store.createRecord('user-form');
Promise.resolve(this.args.user.authenticationMethods).then((authenticationMethods) => {
this.authenticationMethods = authenticationMethods;
});
}

get externalURL() {
Expand Down Expand Up @@ -86,6 +91,14 @@ export default class UserOverview extends Component {
return this.args.user.username ? null : 'obligatoire';
}

get useOidcAuthentication() {
const oidcProvidersCodes = this.oidcIdentityProviders.list.map((provider) => provider.code);
const userHasThisOidcAuthenticationMethod = this.authenticationMethods.any((authenticationMethod) =>
oidcProvidersCodes.includes(authenticationMethod.identityProvider),
);
return userHasThisOidcAuthenticationMethod ? 'common.words.no' : 'common.words.yes';
}

_initForm() {
this.form.firstName = this.args.user.firstName;
this.form.lastName = this.args.user.lastName;
Expand Down Expand Up @@ -331,6 +344,9 @@ export default class UserOverview extends Component {
{{/if}}
</span>
</li>
<li class="user-detail-personal-information-section__user-informations flex space-between gap-4x">
<span>{{t "components.users.user-overview.sso"}} : {{t this.useOidcAuthentication}}</span>
</li>
</ul>

<ul class="user-detail-personal-information-section__infogroup">
Expand Down
71 changes: 71 additions & 0 deletions admin/tests/integration/components/users/user-overview-test.gjs
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,14 @@ module('Integration | Component | users | user-overview', function (hooks) {

test('displays the update button', async function (assert) {
// given
const store = this.owner.lookup('service:store');
const user = {
firstName: 'John',
lastName: 'Harry',
email: '[email protected]',
username: 'john.harry0102',
};
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];

// when
const screen = await render(<template><UserOverview @user={{user}} /></template>);
Expand Down Expand Up @@ -392,13 +394,15 @@ module('Integration | Component | users | user-overview', function (hooks) {
module('When the admin member click to update user details', function () {
test('displays the edit and cancel buttons', async function (assert) {
// given
const store = this.owner.lookup('service:store');
const user = {
firstName: 'John',
lastName: 'Harry',
email: '[email protected]',
username: null,
lang: null,
};
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];

// when
const screen = await render(<template><UserOverview @user={{user}} /></template>);
Expand All @@ -416,6 +420,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

// when
Expand Down Expand Up @@ -450,6 +455,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

// when
Expand All @@ -469,6 +475,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

// when
Expand All @@ -486,6 +493,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

// when
Expand All @@ -505,6 +513,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: null,
username: 'user.name1212',
authenticationMethods: [],
});

// when
Expand All @@ -522,6 +531,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: null,
username: 'user.name1212',
authenticationMethods: [],
});

// when
Expand All @@ -543,6 +553,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: null,
username: undefined,
authenticationMethods: [],
});

// when
Expand All @@ -563,6 +574,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

const screen = await render(<template><UserOverview @user={{user}} /></template>);
Expand All @@ -588,6 +600,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
username: null,
authenticationMethods: [],
});

const screen = await render(<template><UserOverview @user={{user}} /></template>);
Expand Down Expand Up @@ -660,6 +673,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
firstName: 'John',
email: '[email protected]',
isPixAgent: true,
authenticationMethods: [],
});

// when
Expand All @@ -675,11 +689,67 @@ module('Integration | Component | users | user-overview', function (hooks) {
assert.dom(anonymizationDisabledTooltip).exists();
});
});

module('Displays OIDC information', function (hooks) {
class OidcIdentityProvidersStub extends Service {
get list() {
return [
{
code: 'SUNLIGHT_NAVIGATIONS',
organizationName: 'Sunlight Navigations',
},
];
}
}

hooks.beforeEach(function () {
this.owner.register('service:oidc-identity-providers', OidcIdentityProvidersStub);
});

test('When user has not OIDC authentication method', async function (assert) {
// given
const store = this.owner.lookup('service:store');
const user = {
firstName: 'John',
lastName: 'Harry',
email: '[email protected]',
username: 'john.harry0102',
};
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];

// when
const screen = await render(<template><UserOverview @user={{user}} /></template>);

// then
assert.dom(screen.getByText('SSO : Non')).exists();
});

test('When user has OIDC authentication method', async function (assert) {
// given
const store = this.owner.lookup('service:store');
const user = {
firstName: 'John',
lastName: 'Harry',
email: '[email protected]',
username: 'john.harry0102',
};
user.authenticationMethods = [
await store.createRecord('authentication-method', { identityProvider: 'SUNLIGHT_NAVIGATIONS' }),
];

// when
const screen = await render(<template><UserOverview @user={{user}} /></template>);

// then
assert.dom(screen.getByText('SSO : Oui')).exists();
});
});
});

module('When the admin member does not have access to users actions scope', function () {
test('does not display the action buttons "Modifier" and "Anonymiser cet utilisateur"', async function (assert) {
// given
const store = this.owner.lookup('service:store');
class AccessControlStub extends Service {
hasAccessToUsersActionsScope = false;
}
Expand All @@ -690,6 +760,7 @@ module('Integration | Component | users | user-overview', function (hooks) {
email: '[email protected]',
username: 'john.harry0102',
};
user.authenticationMethods = [await store.createRecord('authentication-method', { identityProvider: 'abc' })];
this.owner.register('service:access-control', AccessControlStub);

// when
Expand Down
50 changes: 21 additions & 29 deletions admin/tests/unit/components/users/user-overview-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,15 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('#externalURL', function () {
test('it should generate dashboard URL based on environment and object', async function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');

const args = {
const baseUrl = 'https://metabase.pix.fr/dashboard/132?id=';
ENV.APP.USER_DASHBOARD_URL = baseUrl;
const component = createGlimmerComponent('component:users/user-overview', {
user: {
id: 1,
authenticationMethods: [],
},
};
const baseUrl = 'https://metabase.pix.fr/dashboard/132?id=';
const expectedUrl = baseUrl + args.user.id;

ENV.APP.USER_DASHBOARD_URL = baseUrl;
component.args = args;
});
const expectedUrl = baseUrl + '1';

// when
const actualUrl = component.externalURL;
Expand All @@ -38,9 +35,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user already has an email', function () {
test('it should allow email modification', async function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { email: '[email protected]', firstName: 'Lisa', lastName: 'Dupont' };
component.args.user = user;
const user = { email: '[email protected]', firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });

// when & then
assert.true(component.canModifyEmail);
Expand All @@ -50,9 +46,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user has an username', function () {
test('it should also allow email modification', async function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { username: 'lisa.dupont', firstName: 'Lisa', lastName: 'Dupont' };
component.args.user = user;
const user = { username: 'lisa.dupont', firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });

// when & then
assert.true(component.canModifyEmail);
Expand All @@ -62,9 +57,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user has neither a username nor an email', function () {
test('it should not allow email modification', async function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { firstName: 'Lisa', lastName: 'Dupont' };
component.args.user = user;
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });

// when & then
assert.false(component.canModifyEmail);
Expand All @@ -76,7 +70,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user has no login informations yet', function () {
test('should not display temporary blocked date', function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });

// when && then
assert.false(component.shouldDisplayTemporaryBlockedDate);
Expand All @@ -86,9 +81,8 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user has login but not temporary blocked', function () {
test('should not display temporary blocked date', function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { firstName: 'Lisa', lastName: 'Dupont' };
component.args.user = user;
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });
const getTemporaryBlockedUntilProperty = () => null;
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
component.args.user.userLogin = userLoginProxy;
Expand All @@ -101,11 +95,10 @@ module('Unit | Component | users | user-overview', function (hooks) {
module('when user has login and temporary blocked date', function () {
test('should display temporary blocked date when now date is after temporaty blocked date', function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { firstName: 'Lisa', lastName: 'Dupont' };
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const getTemporaryBlockedUntilProperty = () => new Date(Date.now() + 3600 * 1000);
const component = createGlimmerComponent('component:users/user-overview', { user });
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
component.args.user = user;
component.args.user.userLogin = userLoginProxy;

// when && then
Expand All @@ -114,9 +107,8 @@ module('Unit | Component | users | user-overview', function (hooks) {

test('should not display temporary blocked date when now date is before temporaty blocked date', function (assert) {
// given
const component = createGlimmerComponent('component:users/user-overview');
const user = { firstName: 'Lisa', lastName: 'Dupont' };
component.args.user = user;
const user = { firstName: 'Lisa', lastName: 'Dupont', authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });
const getTemporaryBlockedUntilProperty = () => new Date(Date.now() - 3600 * 1000);
const userLoginProxy = { get: getTemporaryBlockedUntilProperty };
component.args.user.userLogin = userLoginProxy;
Expand All @@ -131,7 +123,7 @@ module('Unit | Component | users | user-overview', function (hooks) {
test('should empty organization learners', async function (assert) {
// given
const organizationLearners = [{ firstName: 'fanny', lastName: 'epi' }];
const user = { organizationLearners, save: sinon.stub().resolves() };
const user = { organizationLearners, save: sinon.stub().resolves(), authenticationMethods: [] };
const component = createGlimmerComponent('component:users/user-overview', { user });

// when
Expand Down
3 changes: 3 additions & 0 deletions admin/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,9 @@
}
},
"copied": "Copied!"
},
"user-overview": {
"sso": "SSO"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions admin/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@
}
},
"copied": "Copié !"
},
"user-overview": {
"sso": "SSO"
}
}
},
Expand Down
Loading