Skip to content

Commit 3fd94f4

Browse files
committed
Fixes #581
1 parent ee736c8 commit 3fd94f4

File tree

4 files changed

+35
-17
lines changed

4 files changed

+35
-17
lines changed

client/src/__tests__/utils/UserRole.test.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
const applicationUsagesForManageId = manageId => {
1313
return [{application: {manageId: manageId}}];
1414
}
15+
1516
describe('UserRole', () => {
1617
it("Test isUserAllowed", () => {
1718
let user = {userRoles: [{authority: AUTHORITIES.GUEST}]}
@@ -36,16 +37,12 @@ describe('UserRole', () => {
3637

3738
it("Allowed authorities for invitation - manager", () => {
3839
const researchUserRole = {authority: AUTHORITIES.MANAGER, role: {id: "1", manageId: "2"}};
39-
const wikiRole = {id: "2", manageId: "2"};
4040
const mailUserRole = {authority: AUTHORITIES.INVITER, role: {id: "3", manageId: "9"}};
4141
const user = {userRoles: [researchUserRole, mailUserRole]}
4242

4343
let authorities = allowedAuthoritiesForInvitation(user, []);
4444
expect(authorities).toEqual([AUTHORITIES.INVITER, AUTHORITIES.GUEST]);
4545

46-
authorities = allowedAuthoritiesForInvitation(user, [wikiRole]);
47-
expect(authorities).toEqual([]);
48-
4946
authorities = allowedAuthoritiesForInvitation(user, [mailUserRole.role]);
5047
expect(authorities).toEqual([AUTHORITIES.GUEST]);
5148

client/src/pages/InvitationForm.jsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,20 @@ export const InvitationForm = () => {
201201
setSelectedRoles([])
202202
setInvitation({...invitation, enforceEmailEquality: false, eduIDOnly: false})
203203
} else {
204+
const allowedAuthorities = allowedAuthoritiesForInvitation(user, selectedOptions);
205+
let intendedAuthority = invitation.intendedAuthority;
206+
//If the chosen authority is no longer allowed, then change it
207+
if (!allowedAuthorities.includes(invitation.intendedAuthority)) {
208+
intendedAuthority = allowedAuthorities[0];
209+
}
204210
const newSelectedOptions = Array.isArray(selectedOptions) ? [...selectedOptions] : [selectedOptions];
205211
setSelectedRoles(newSelectedOptions);
206212
const enforceEmailEquality = newSelectedOptions.some(role => role.enforceEmailEquality);
207213
const eduIDOnly = newSelectedOptions.some(role => role.eduIDOnly);
214+
208215
setInvitation({
209216
...invitation,
217+
intendedAuthority: intendedAuthority,
210218
enforceEmailEquality: enforceEmailEquality,
211219
eduIDOnly: eduIDOnly,
212220
roleExpiryDate: defaultRoleExpiryDate(newSelectedOptions)
@@ -247,14 +255,14 @@ export const InvitationForm = () => {
247255
pinnedEmails={[]}
248256
removeMail={removeMail}
249257
required={true}
250-
maxEmails={null} //TODO is there a internal placeholder identifier? then one
251-
maxEmailsMessage={"TODO : localize Not allowed to add more then one email"}
258+
maxEmails={null} //TODO is there a internal placeholder identifier? then one.
259+
// See https://github.com/OpenConext/OpenConext-Invite/issues/540
260+
maxEmailsMessage={"TODO : localize Not allowed to add more then one email with external identifier"}
252261
error={!initial && isEmpty(invitation.invites)}/>
253262

254263
{(!initial && isEmpty(invitation.invites)) &&
255264
<ErrorIndicator msg={I18n.t("invitations.requiredEmail")}/>}
256-
257-
{authorityOptions.length > 1 &&
265+
{(authorityOptions.length > 1 || (!isInviter && authorityOptions.length === 1)) &&
258266
<SelectField
259267
value={authorityOptions.find(option => option.value === invitation.intendedAuthority)
260268
|| authorityOptions[authorityOptions.length - 1]}

client/src/utils/UserRole.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,32 @@ export const allowedAuthoritiesForInvitation = (user, selectedRoles) => {
170170
if (user.superUser) {
171171
//The superuser has no organization guid, but is allowed to add one
172172
return Object.keys(AUTHORITIES);
173-
174173
}
175174
//Return only the AUTHORITIES where the user has the correct authority per selectedRole
175+
if (user.institutionAdmin && !isEmpty(user.applications)) {
176+
const nonInstitutionalRoles = selectedRoles.filter(role => user.organizationGUID !== role.organizationGUID);
177+
if (nonInstitutionalRoles.length === 0) {
178+
return Object.keys(AUTHORITIES)
179+
.filter(authority => authority !== AUTHORITIES.SUPER_USER);
180+
} else {
181+
//If the user is an institution-admin but is also a regular inviter or manager of another non-institutional role, then filter the authorities
182+
const allowedAuthority = nonInstitutionalRoles
183+
.reduce((acc, userRole) => {
184+
if (acc === null || AUTHORITIES_HIERARCHY[userRole.authority] > AUTHORITIES_HIERARCHY[acc]) {
185+
return userRole.authority;
186+
}
187+
return acc;
188+
}, null) || AUTHORITIES.INVITER;
189+
return Object.keys(AUTHORITIES)
190+
.filter(auth => AUTHORITIES_HIERARCHY[auth] > AUTHORITIES_HIERARCHY[allowedAuthority]);
191+
}
192+
}
176193
const userRolesForSelectedRoles = selectedRoles
177194
.map(role => role.isUserRole ? role.role : role)
178195
.filter(role => (!isEmpty(user.organizationGUID) && user.organizationGUID === role.organizationGUID) ||
179196
user.userRoles.some(userRole => userRole.role.id === role.id))
180197
.filter(userRole => !isEmpty(userRole));
181-
//If the user is an institutionAdmin but is also a regular inviter or manager of this role, then filter the authorities
182-
if (user.institutionAdmin && !isEmpty(user.applications) && userRolesForSelectedRoles.length === 0) {
183-
return Object.keys(AUTHORITIES)
184-
.filter(authority => authority !== AUTHORITIES.SUPER_USER);
185-
}
198+
186199
if (!isUserAllowed(AUTHORITIES.INVITER, user)) {
187200
return [];
188201
}
@@ -193,11 +206,11 @@ export const allowedAuthoritiesForInvitation = (user, selectedRoles) => {
193206
}
194207
const leastImportantAuthority = userRolesForSelectedRoles
195208
.reduce((acc, userRole) => {
196-
if (AUTHORITIES_HIERARCHY[userRole.authority] < AUTHORITIES_HIERARCHY[acc]) {
209+
if (acc === null || AUTHORITIES_HIERARCHY[userRole.authority] > AUTHORITIES_HIERARCHY[acc]) {
197210
return userRole.authority;
198211
}
199212
return acc;
200-
}, AUTHORITIES.GUEST);
213+
}, null) || AUTHORITIES.INVITER;
201214
return Object.keys(AUTHORITIES)
202215
.filter(auth => AUTHORITIES_HIERARCHY[auth] > AUTHORITIES_HIERARCHY[leastImportantAuthority]);
203216

server/src/main/java/invite/security/UserPermissions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static void assertValidInvitation(User user, Authority intendedAuthority,
7171
throw new UserRestrictionException();
7272
}
7373
Set<UserRole> userRoles = user.getUserRoles();
74-
//Institution admin needs to own all roles
74+
//Institution admin needs to own all roles or be a member of the role for at least the authority of invitationo
7575
if (user.isInstitutionAdmin() && roles.stream()
7676
.allMatch(role -> user.getOrganizationGUID().equals(role.getOrganizationGUID()))) {
7777
return;

0 commit comments

Comments
 (0)