SEBSERV-21 & SEBSERV-27 fixed role based User-Account access
This commit is contained in:
parent
cf636e974b
commit
8af5a4fc93
31 changed files with 450 additions and 102 deletions
|
@ -22,7 +22,7 @@ public class PasswordChange implements Entity {
|
|||
|
||||
public static final String ATTR_NAME_OLD_PASSWORD = "oldPassword";
|
||||
public static final String ATTR_NAME_NEW_PASSWORD = "newPassword";
|
||||
public static final String ATTR_NAME_RETYPED_NEW_PASSWORD = "retypedNewPassword";
|
||||
public static final String ATTR_NAME_CONFIRM_NEW_PASSWORD = "confirmNewPassword";
|
||||
|
||||
@NotNull
|
||||
@JsonProperty(USER.ATTR_UUID)
|
||||
|
@ -37,21 +37,21 @@ public class PasswordChange implements Entity {
|
|||
@JsonProperty(ATTR_NAME_NEW_PASSWORD)
|
||||
private final String newPassword;
|
||||
|
||||
@NotNull(message = "user:retypedNewPassword:notNull")
|
||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD)
|
||||
private final String retypedNewPassword;
|
||||
@NotNull(message = "user:confirmNewPassword:notNull")
|
||||
@JsonProperty(ATTR_NAME_CONFIRM_NEW_PASSWORD)
|
||||
private final String confirmNewPassword;
|
||||
|
||||
@JsonCreator
|
||||
public PasswordChange(
|
||||
@JsonProperty(USER.ATTR_UUID) final String userId,
|
||||
@JsonProperty(ATTR_NAME_OLD_PASSWORD) final String oldPassword,
|
||||
@JsonProperty(ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||
@JsonProperty(ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword) {
|
||||
@JsonProperty(ATTR_NAME_CONFIRM_NEW_PASSWORD) final String confirmNewPassword) {
|
||||
|
||||
this.userId = userId;
|
||||
this.oldPassword = oldPassword;
|
||||
this.newPassword = newPassword;
|
||||
this.retypedNewPassword = retypedNewPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
}
|
||||
|
||||
public String getOldPassword() {
|
||||
|
@ -62,12 +62,12 @@ public class PasswordChange implements Entity {
|
|||
return this.newPassword;
|
||||
}
|
||||
|
||||
public String getRetypedNewPassword() {
|
||||
return this.retypedNewPassword;
|
||||
public String getConfirmNewPassword() {
|
||||
return this.confirmNewPassword;
|
||||
}
|
||||
|
||||
public boolean newPasswordMatch() {
|
||||
return this.newPassword.equals(this.retypedNewPassword);
|
||||
return this.newPassword.equals(this.confirmNewPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -41,6 +42,8 @@ public interface UserAccount extends GrantEntity {
|
|||
|
||||
Set<String> getRoles();
|
||||
|
||||
EnumSet<UserRole> getUserRoles();
|
||||
|
||||
String getNewPassword();
|
||||
|
||||
String getRetypedNewPassword();
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
@ -182,6 +184,15 @@ public final class UserInfo implements UserAccount, Activatable, Serializable {
|
|||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
return EnumSet.copyOf(
|
||||
getRoles().stream()
|
||||
.map(r -> UserRole.valueOf(r))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public boolean hasRole(final UserRole userRole) {
|
||||
if (userRole == null) {
|
||||
return false;
|
||||
|
|
|
@ -9,8 +9,10 @@
|
|||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
@ -79,8 +81,8 @@ public final class UserMod implements UserAccount {
|
|||
private final String newPassword;
|
||||
|
||||
@NotNull(message = "user:retypedNewPassword:notNull")
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD)
|
||||
private final String retypedNewPassword;
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD)
|
||||
private final String confirmNewPassword;
|
||||
|
||||
@JsonCreator
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
|
@ -90,7 +92,7 @@ public final class UserMod implements UserAccount {
|
|||
@JsonProperty(USER.ATTR_NAME) final String name,
|
||||
@JsonProperty(USER.ATTR_USERNAME) final String username,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_NEW_PASSWORD) final String newPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD) final String retypedNewPassword,
|
||||
@JsonProperty(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD) final String confirmNewPassword,
|
||||
@JsonProperty(USER.ATTR_EMAIL) final String email,
|
||||
@JsonProperty(USER.ATTR_LANGUAGE) final Locale language,
|
||||
@JsonProperty(USER.ATTR_TIMEZONE) final DateTimeZone timeZone,
|
||||
|
@ -99,7 +101,7 @@ public final class UserMod implements UserAccount {
|
|||
this.uuid = uuid;
|
||||
this.institutionId = institutionId;
|
||||
this.newPassword = newPassword;
|
||||
this.retypedNewPassword = retypedNewPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
this.name = name;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
|
@ -110,11 +112,11 @@ public final class UserMod implements UserAccount {
|
|||
: Collections.emptySet();
|
||||
}
|
||||
|
||||
public UserMod(final UserInfo userInfo, final String newPassword, final String retypedNewPassword) {
|
||||
public UserMod(final UserInfo userInfo, final String newPassword, final String confirmNewPassword) {
|
||||
this.uuid = userInfo.uuid;
|
||||
this.institutionId = userInfo.institutionId;
|
||||
this.newPassword = newPassword;
|
||||
this.retypedNewPassword = retypedNewPassword;
|
||||
this.confirmNewPassword = confirmNewPassword;
|
||||
this.name = userInfo.name;
|
||||
this.username = userInfo.username;
|
||||
this.email = userInfo.email;
|
||||
|
@ -127,7 +129,7 @@ public final class UserMod implements UserAccount {
|
|||
this.uuid = modelId;
|
||||
this.institutionId = postAttrMapper.getLong(USER.ATTR_INSTITUTION_ID);
|
||||
this.newPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_NEW_PASSWORD);
|
||||
this.retypedNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD);
|
||||
this.confirmNewPassword = postAttrMapper.getString(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD);
|
||||
this.name = postAttrMapper.getString(USER.ATTR_NAME);
|
||||
this.username = postAttrMapper.getString(USER.ATTR_USERNAME);
|
||||
this.email = postAttrMapper.getString(USER.ATTR_EMAIL);
|
||||
|
@ -140,7 +142,7 @@ public final class UserMod implements UserAccount {
|
|||
this.uuid = modelId;
|
||||
this.institutionId = institutionId;
|
||||
this.newPassword = null;
|
||||
this.retypedNewPassword = null;
|
||||
this.confirmNewPassword = null;
|
||||
this.name = null;
|
||||
this.username = null;
|
||||
this.email = null;
|
||||
|
@ -204,9 +206,18 @@ public final class UserMod implements UserAccount {
|
|||
return this.roles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonIgnore
|
||||
public EnumSet<UserRole> getUserRoles() {
|
||||
return EnumSet.copyOf(
|
||||
getRoles().stream()
|
||||
.map(r -> UserRole.valueOf(r))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRetypedNewPassword() {
|
||||
return this.retypedNewPassword;
|
||||
return this.confirmNewPassword;
|
||||
}
|
||||
|
||||
public boolean passwordChangeRequest() {
|
||||
|
@ -214,7 +225,7 @@ public final class UserMod implements UserAccount {
|
|||
}
|
||||
|
||||
public boolean newPasswordMatch() {
|
||||
return passwordChangeRequest() && this.newPassword.equals(this.retypedNewPassword);
|
||||
return passwordChangeRequest() && this.newPassword.equals(this.confirmNewPassword);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -243,7 +254,7 @@ public final class UserMod implements UserAccount {
|
|||
+ this.username + ", email=" + this.email + ", language=" + this.language + ", timeZone="
|
||||
+ this.timeZone
|
||||
+ ", roles=" + this.roles
|
||||
+ ", newPassword=" + this.newPassword + ", retypedNewPassword=" + this.retypedNewPassword + "]";
|
||||
+ ", newPassword=" + this.newPassword + ", retypedNewPassword=" + this.confirmNewPassword + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gbl.model.user;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
||||
|
@ -32,4 +37,19 @@ public enum UserRole implements Entity {
|
|||
public String getName() {
|
||||
return name();
|
||||
}
|
||||
|
||||
public static List<UserRole> publicRolesForUser(final UserInfo user) {
|
||||
final EnumSet<UserRole> roles = user.getUserRoles();
|
||||
if (roles.contains(SEB_SERVER_ADMIN)) {
|
||||
return Arrays.asList(UserRole.values());
|
||||
} else if (roles.contains(INSTITUTIONAL_ADMIN)) {
|
||||
return Arrays.asList(INSTITUTIONAL_ADMIN, EXAM_ADMIN, EXAM_SUPPORTER);
|
||||
} else if (roles.contains(EXAM_ADMIN)) {
|
||||
return Arrays.asList(EXAM_ADMIN, EXAM_SUPPORTER);
|
||||
} else if (roles.contains(EXAM_SUPPORTER)) {
|
||||
return Arrays.asList(EXAM_SUPPORTER);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public class InstitutionForm implements TemplateComposer {
|
|||
|
||||
final boolean writeGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, institution);
|
||||
final boolean modifyGrant = this.currentUser.hasPrivilege(PrivilegeType.MODIFY, institution);
|
||||
final boolean userWriteGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.USER);
|
||||
final boolean userWriteGrant = this.currentUser.hasBasePrivilege(PrivilegeType.WRITE, EntityType.USER);
|
||||
final boolean isReadonly = pageContext.isReadonly();
|
||||
|
||||
// new PageContext with actual EntityKey
|
||||
|
|
|
@ -79,10 +79,10 @@ public class InstitutionList implements TemplateComposer {
|
|||
// propagate content actions to action-pane
|
||||
pageContext.createAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.readonly(false)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION))
|
||||
.publishIf(() -> this.currentUser.hasBasePrivilege(PrivilegeType.WRITE, EntityType.INSTITUTION))
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.USER))
|
||||
.publishIf(() -> this.currentUser.hasBasePrivilege(PrivilegeType.WRITE, EntityType.USER))
|
||||
.createAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(InstitutionActions::viewInstitutionFromList)
|
||||
|
@ -91,7 +91,7 @@ public class InstitutionList implements TemplateComposer {
|
|||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(InstitutionActions::editInstitutionFromList)
|
||||
.readonly(false)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION));
|
||||
.publishIf(() -> this.currentUser.hasBasePrivilege(PrivilegeType.MODIFY, EntityType.INSTITUTION));
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -83,15 +83,15 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
|
|||
entityKey.getModelId())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_OLD_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.old")
|
||||
"sebserver.useraccount.form.password.old")
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.new")
|
||||
"sebserver.useraccount.form.password.new")
|
||||
.asPasswordField())
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.institution.password.retyped")
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password.new.confirm")
|
||||
.asPasswordField()
|
||||
.withCondition(() -> entityKey != null))
|
||||
.buildFor(this.restService.getRestCall(ChangePassword.class));
|
||||
|
|
|
@ -39,6 +39,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageUtils;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccount;
|
||||
|
@ -71,12 +72,13 @@ public class UserAccountForm implements TemplateComposer {
|
|||
@Override
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final UserInfo currentUser = this.currentUser.get();
|
||||
final WidgetFactory widgetFactory = this.pageFormService.getWidgetFactory();
|
||||
final EntityKey entityKey = pageContext.getEntityKey();
|
||||
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
|
||||
final BooleanSupplier isNew = () -> entityKey == null;
|
||||
final BooleanSupplier isNotNew = () -> !isNew.getAsBoolean();
|
||||
final BooleanSupplier isSEBAdmin = () -> this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final BooleanSupplier isSEBAdmin = () -> currentUser.hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||
final boolean readonly = pageContext.isReadonly();
|
||||
// get data or create new. handle error if happen
|
||||
final UserAccount userAccount = isNew.getAsBoolean()
|
||||
|
@ -84,7 +86,7 @@ public class UserAccountForm implements TemplateComposer {
|
|||
UUID.randomUUID().toString(),
|
||||
(parentEntityKey != null)
|
||||
? Long.valueOf(parentEntityKey.modelId)
|
||||
: this.currentUser.get().institutionId)
|
||||
: currentUser.institutionId)
|
||||
: this.restService
|
||||
.getBuilder(GetUserAccount.class)
|
||||
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
|
||||
|
@ -99,6 +101,7 @@ public class UserAccountForm implements TemplateComposer {
|
|||
return;
|
||||
}
|
||||
|
||||
final boolean ownAccount = currentUser.uuid.equals(userAccount.getModelId());
|
||||
final boolean writeGrant = this.currentUser.hasPrivilege(PrivilegeType.WRITE, userAccount);
|
||||
final boolean modifyGrant = this.currentUser.hasPrivilege(PrivilegeType.MODIFY, userAccount);
|
||||
// modifying an UserAccount is not possible if the root institution is inactive
|
||||
|
@ -178,8 +181,8 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.asPasswordField()
|
||||
.withCondition(isNew))
|
||||
.addField(FormBuilder.text(
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password.retyped")
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"sebserver.useraccount.form.password.confirm")
|
||||
.asPasswordField()
|
||||
.withCondition(isNew))
|
||||
.buildFor((entityKey == null)
|
||||
|
@ -189,6 +192,7 @@ public class UserAccountForm implements TemplateComposer {
|
|||
// propagate content actions to action-pane
|
||||
|
||||
formContext.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.resetEntity()
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.publishIf(() -> writeGrant && readonly && istitutionActive)
|
||||
|
||||
|
@ -210,7 +214,14 @@ public class UserAccountForm implements TemplateComposer {
|
|||
.publishIf(() -> writeGrant && readonly && istitutionActive && !userAccount.isActive())
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_SAVE)
|
||||
.withExec(formHandle::postChanges)
|
||||
.withExec(action -> {
|
||||
final Action postChanges = formHandle.postChanges(action);
|
||||
if (ownAccount) {
|
||||
this.currentUser.refresh();
|
||||
pageContext.forwardToMainPage(pageContext);
|
||||
}
|
||||
return postChanges;
|
||||
})
|
||||
.publishIf(() -> !readonly)
|
||||
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
|
||||
|
|
|
@ -99,15 +99,15 @@ public class UserAccountList implements TemplateComposer {
|
|||
// propagate content actions to action-pane
|
||||
pageContext.createAction(ActionDefinition.USER_ACCOUNT_NEW)
|
||||
.withExec(UserAccountActions::newUserAccount)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.WRITE, EntityType.USER))
|
||||
.publishIf(() -> this.currentUser.hasInstitutionalPrivilege(PrivilegeType.WRITE, EntityType.USER))
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_VIEW)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(UserAccountActions::viewUserAccountFromList)
|
||||
.publish()
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM__LIST)
|
||||
.createAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
|
||||
.withSelectionSupplier(table::getSelection)
|
||||
.withExec(UserAccountActions::editUserAccountFromList)
|
||||
.publishIf(() -> this.currentUser.hasPrivilege(PrivilegeType.MODIFY, EntityType.USER));
|
||||
.publishIf(() -> this.currentUser.hasInstitutionalPrivilege(PrivilegeType.MODIFY, EntityType.USER));
|
||||
}
|
||||
|
||||
private String getLocaleDisplayText(final UserInfo userInfo) {
|
||||
|
|
|
@ -98,7 +98,7 @@ public enum ActionDefinition {
|
|||
UserAccountForm.class,
|
||||
USER_ACCOUNT_VIEW_LIST),
|
||||
|
||||
USER_ACCOUNT_MODIFY_FROM__LIST(
|
||||
USER_ACCOUNT_MODIFY_FROM_LIST(
|
||||
new LocTextKey("sebserver.useraccount.action.list.modify"),
|
||||
ImageIcon.EDIT,
|
||||
UserAccountForm.class,
|
||||
|
|
|
@ -97,8 +97,8 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
}
|
||||
|
||||
// User Account
|
||||
// if current user has base read privilege for User Account, show list
|
||||
if (this.currentUser.hasPrivilege(PrivilegeType.READ_ONLY, EntityType.USER)) {
|
||||
// if current user has base or institutional read privilege for User Account, show list
|
||||
if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ_ONLY, EntityType.USER)) {
|
||||
final TreeItem userAccounts = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
ActionDefinition.USER_ACCOUNT_VIEW_LIST.title);
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.swt.widgets.Label;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.MultiSelection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.Selection;
|
||||
import ch.ethz.seb.sebserver.gui.widget.SingleSelection;
|
||||
|
@ -104,24 +105,38 @@ public final class SelectionFieldBuilder extends FieldBuilder {
|
|||
this.itemsSupplier.get()
|
||||
.stream()
|
||||
.filter(tuple -> keys.contains(tuple._1))
|
||||
.map(tuple -> tuple._2)
|
||||
.forEach(v -> createMuliSelectionReadonlyLabel(composite, v));
|
||||
.map(tuple -> tuple._1)
|
||||
.forEach(v -> buildReadonlyLabel(composite, v, 0));
|
||||
}
|
||||
} else {
|
||||
builder.form.putField(
|
||||
this.name, lab,
|
||||
builder.valueLabel(
|
||||
builder.formParent,
|
||||
this.itemsSupplier.get().stream()
|
||||
.filter(tuple -> this.value.equals(tuple._1))
|
||||
.findFirst()
|
||||
.map(tuple -> tuple._2)
|
||||
.orElse(null),
|
||||
this.spanInput));
|
||||
this.name,
|
||||
lab,
|
||||
buildReadonlyLabel(builder.formParent, this.value, this.spanInput));
|
||||
builder.setFieldVisible(this.visible, this.name);
|
||||
}
|
||||
}
|
||||
|
||||
private Label buildReadonlyLabel(final Composite composite, final String valueKey, final int hspan) {
|
||||
final Label label = new Label(composite, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false, hspan, 1);
|
||||
gridData.verticalIndent = 0;
|
||||
gridData.horizontalIndent = 0;
|
||||
label.setLayoutData(gridData);
|
||||
label.setData(RWT.CUSTOM_VARIANT, CustomVariant.SELECTION_READONLY.key);
|
||||
|
||||
final Supplier<String> valueSupplier = () -> this.itemsSupplier.get().stream()
|
||||
.filter(tuple -> valueKey.equals(tuple._1))
|
||||
.findFirst()
|
||||
.map(tuple -> tuple._2)
|
||||
.orElse(Constants.EMPTY_NOTE);
|
||||
final Consumer<Label> updateFunction = l -> l.setText(valueSupplier.get());
|
||||
|
||||
label.setText(valueSupplier.get());
|
||||
label.setData(PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY, updateFunction);
|
||||
return label;
|
||||
}
|
||||
|
||||
private void createMuliSelectionReadonlyLabel(final Composite composite, final String value) {
|
||||
final Label label = new Label(composite, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.i18n;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -20,7 +18,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
|
||||
public interface I18nSupport {
|
||||
|
@ -96,15 +93,7 @@ public interface I18nSupport {
|
|||
return () -> getTimeZoneResources(this);
|
||||
}
|
||||
|
||||
default Supplier<List<Tuple<String>>> localizedUserRoleResources() {
|
||||
return localizedResourceSupplier(USER_ROLE_RESOURCES);
|
||||
}
|
||||
|
||||
final List<Tuple<String>> USER_ROLE_RESOURCES = Collections.unmodifiableList(
|
||||
Arrays.asList(UserRole.values())
|
||||
.stream()
|
||||
.map(ur -> new Tuple<>(ur.name(), "sebserver.useraccount.role." + ur.name()))
|
||||
.collect(Collectors.toList()));
|
||||
Supplier<List<Tuple<String>>> localizedUserRoleResources();
|
||||
|
||||
/** Get a list of language key/name tuples for all supported languages in the
|
||||
* language of the current users locale.
|
||||
|
|
|
@ -10,7 +10,10 @@ package ch.ethz.seb.sebserver.gui.service.i18n.impl;
|
|||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -23,6 +26,8 @@ import org.springframework.context.MessageSource;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||
|
@ -128,4 +133,13 @@ public class I18nSupportImpl implements I18nSupport {
|
|||
return this.messageSource.getMessage(key, args, def, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<List<Tuple<String>>> localizedUserRoleResources() {
|
||||
final List<Tuple<String>> roles = UserRole.publicRolesForUser(this.currentUser.get())
|
||||
.stream()
|
||||
.map(ur -> new Tuple<>(ur.name(), "sebserver.useraccount.role." + ur.name()))
|
||||
.collect(Collectors.toList());
|
||||
return localizedResourceSupplier(roles);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -74,7 +74,20 @@ public class CurrentUser {
|
|||
return null;
|
||||
}
|
||||
|
||||
public boolean hasPrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||
public boolean hasBasePrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||
return hasPrivilege(privilegeType, entityType, null, null);
|
||||
}
|
||||
|
||||
public boolean hasInstitutionalPrivilege(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||
final UserInfo userInfo = get();
|
||||
return hasPrivilege(privilegeType, entityType, userInfo.institutionId, null);
|
||||
}
|
||||
|
||||
public boolean hasPrivilege(
|
||||
final PrivilegeType privilegeType,
|
||||
final EntityType entityType,
|
||||
final Long institutionId,
|
||||
final String ownerId) {
|
||||
if (loadPrivileges()) {
|
||||
try {
|
||||
final UserInfo userInfo = get();
|
||||
|
@ -87,7 +100,8 @@ public class CurrentUser {
|
|||
userInfo.uuid,
|
||||
userInfo.institutionId,
|
||||
privilegeType,
|
||||
null, null))
|
||||
institutionId,
|
||||
ownerId))
|
||||
.findFirst()
|
||||
.isPresent();
|
||||
} catch (final Exception e) {
|
||||
|
@ -134,6 +148,10 @@ public class CurrentUser {
|
|||
return this.authContext != null && this.authContext.isLoggedIn();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
this.authContext.refreshUser();
|
||||
}
|
||||
|
||||
private void updateContext() {
|
||||
if (this.authContext == null || !this.authContext.isValid()) {
|
||||
this.authContext = this.authorizationContextHolder.getAuthorizationContext();
|
||||
|
|
|
@ -238,6 +238,19 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
return this.restTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshUser() {
|
||||
// delete the access-token (and refresh-token) on authentication server side
|
||||
this.restTemplate.delete(this.revokeTokenURI);
|
||||
// delete the access-token within the RestTemplate
|
||||
this.restTemplate.getOAuth2ClientContext().setAccessToken(null);
|
||||
// and request new access token
|
||||
this.restTemplate.getAccessToken();
|
||||
// and reset logged in user by getting actual one from webservice
|
||||
this.loggedInUser = null;
|
||||
getLoggedInUser();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<UserInfo> getLoggedInUser() {
|
||||
if (this.loggedInUser != null) {
|
||||
|
@ -283,5 +296,6 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
.getOrThrow().roles
|
||||
.contains(role.name());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,14 +24,14 @@ public interface SEBServerAuthorizationContext {
|
|||
boolean isValid();
|
||||
|
||||
/** Indicated whether a user is logged in within this authorization context or not.
|
||||
*
|
||||
*
|
||||
* @return whether a user is logged in within this authorization context or not */
|
||||
boolean isLoggedIn();
|
||||
|
||||
/** Requests a login with username and password on SEB Server webservice.
|
||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to exchange user/client credentials
|
||||
* with an access and refresh token.
|
||||
*
|
||||
*
|
||||
* @param username the username for login
|
||||
* @param password the password for login
|
||||
* @return */
|
||||
|
@ -40,21 +40,23 @@ public interface SEBServerAuthorizationContext {
|
|||
/** Requests a logout on SEB Server webservice if a user is currently logged in
|
||||
* This uses OAuth 2 and Springs OAuth2RestTemplate to make a revoke token request for the
|
||||
* currently logged in user and also invalidates this SEBServerAuthorizationContext
|
||||
*
|
||||
*
|
||||
* @return true if logout was successful */
|
||||
boolean logout();
|
||||
|
||||
/** Gets a Result of the UserInfo data of currently logged in user or of an error if no user is logged in
|
||||
* or there was an unexpected error while trying to get the user information.
|
||||
*
|
||||
*
|
||||
* @return Result of logged in user data or of an error on fail */
|
||||
Result<UserInfo> getLoggedInUser();
|
||||
|
||||
void refreshUser();
|
||||
|
||||
/** Returns true if a current logged in user has the specified role.
|
||||
*
|
||||
* @param role the UserRole to check
|
||||
* @return true if a current logged in user has the specified role */
|
||||
public boolean hasRole(UserRole role);
|
||||
boolean hasRole(UserRole role);
|
||||
|
||||
/** Get the underling RestTemplate to connect and communicate with the SEB Server webservice.
|
||||
*
|
||||
|
|
|
@ -48,6 +48,7 @@ public class MultiSelection extends Composite implements Selection {
|
|||
final String selectionValue = getSelectionValue();
|
||||
this.selected.clear();
|
||||
this.labels.clear();
|
||||
WidgetFactory.clearComposite(this);
|
||||
for (final Tuple<String> tuple : mapping) {
|
||||
final Label label = new Label(this, SWT.NONE);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, true);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer.authorization;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
|
@ -158,7 +159,7 @@ public interface AuthorizationService {
|
|||
|
||||
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny.
|
||||
*
|
||||
*
|
||||
* @param privilegeType the privilege type to check
|
||||
* @param entityType the type of the entity to check the given privilege type on */
|
||||
default void check(final PrivilegeType privilegeType, final EntityType entityType) {
|
||||
|
@ -167,7 +168,7 @@ public interface AuthorizationService {
|
|||
|
||||
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny.
|
||||
*
|
||||
*
|
||||
* @param privilegeType the privilege type to check
|
||||
* @param entityType the type of the entity to check the given privilege type on
|
||||
* @param institutionId the institution identifier for institutional privilege grant check */
|
||||
|
@ -183,7 +184,7 @@ public interface AuthorizationService {
|
|||
/** Check grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny or return the given grantEntity within a Result on successful grant.
|
||||
* This is useful to use with a Result based functional chain.
|
||||
*
|
||||
*
|
||||
* @param privilegeType the privilege type to check
|
||||
* @param entityType the type of the entity to check the given privilege type on
|
||||
* @param institutionId the institution identifier for institutional privilege grant check */
|
||||
|
@ -201,7 +202,7 @@ public interface AuthorizationService {
|
|||
/** Check read-only grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny or returns the given grantEntity within a Result on successful grant.
|
||||
* This is useful to use with a Result based functional chain.
|
||||
*
|
||||
*
|
||||
* @param entityType the type of the entity to check the given privilege type on
|
||||
* @param institutionId the institution identifier for institutional privilege grant check */
|
||||
default <E extends GrantEntity> Result<E> checkReadonly(final E grantEntity) {
|
||||
|
@ -211,7 +212,7 @@ public interface AuthorizationService {
|
|||
/** Check modify grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny or returns the given grantEntity within a Result on successful grant.
|
||||
* This is useful to use with a Result based functional chain.
|
||||
*
|
||||
*
|
||||
* @param entityType the type of the entity to check the given privilege type on
|
||||
* @param institutionId the institution identifier for institutional privilege grant check */
|
||||
default <E extends GrantEntity> Result<E> checkModify(final E grantEntity) {
|
||||
|
@ -221,11 +222,28 @@ public interface AuthorizationService {
|
|||
/** Check write grant by using corresponding hasGrant(XY) method and throws PermissionDeniedException
|
||||
* on deny or returns the given grantEntity within a Result on successful grant.
|
||||
* This is useful to use with a Result based functional chain.
|
||||
*
|
||||
*
|
||||
* @param entityType the type of the entity to check the given privilege type on
|
||||
* @param institutionId the institution identifier for institutional privilege grant check */
|
||||
default <E extends GrantEntity> Result<E> checkWrite(final E grantEntity) {
|
||||
return check(PrivilegeType.WRITE, grantEntity);
|
||||
}
|
||||
|
||||
default boolean hasRoleBasedUserAccountViewGrant(final UserInfo userAccount) {
|
||||
final EnumSet<UserRole> userRolesOfUserAccount = userAccount.getUserRoles();
|
||||
final SEBServerUser currentUser = getUserService().getCurrentUser();
|
||||
final EnumSet<UserRole> userRolesOfCurrentUser = currentUser.getUserRoles();
|
||||
if (userRolesOfCurrentUser.contains(UserRole.SEB_SERVER_ADMIN)) {
|
||||
return true;
|
||||
}
|
||||
if (userRolesOfCurrentUser.contains(UserRole.INSTITUTIONAL_ADMIN)) {
|
||||
return !userRolesOfUserAccount.contains(UserRole.SEB_SERVER_ADMIN);
|
||||
}
|
||||
if (currentUser.uuid().equals(userAccount.uuid)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
|
@ -20,6 +21,10 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.JodaTimeTypeResolver;
|
|||
|
||||
public class FilterMap extends POSTMapper {
|
||||
|
||||
public FilterMap() {
|
||||
super(new LinkedMultiValueMap<>());
|
||||
}
|
||||
|
||||
public FilterMap(final MultiValueMap<String, String> params) {
|
||||
super(params);
|
||||
}
|
||||
|
|
|
@ -60,15 +60,15 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
|||
|
||||
@Lazy
|
||||
@Component
|
||||
public class UserDaoImpl implements UserDAO {
|
||||
public class UserDAOImpl implements UserDAO {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(UserDaoImpl.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(UserDAOImpl.class);
|
||||
|
||||
private final UserRecordMapper userRecordMapper;
|
||||
private final RoleRecordMapper roleRecordMapper;
|
||||
private final PasswordEncoder userPasswordEncoder;
|
||||
|
||||
public UserDaoImpl(
|
||||
public UserDAOImpl(
|
||||
final UserRecordMapper userRecordMapper,
|
||||
final RoleRecordMapper roleRecordMapper,
|
||||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder userPasswordEncoder) {
|
|
@ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkAction;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ActivatableEntityDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||
|
||||
|
@ -55,6 +56,7 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
this.activatableEntityDAO = entityDAO;
|
||||
}
|
||||
|
||||
// TODO use also the getAll method
|
||||
@RequestMapping(
|
||||
path = API.ACTIVE_PATH_SEGMENT,
|
||||
method = RequestMethod.GET,
|
||||
|
@ -70,12 +72,17 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
|
||||
|
||||
checkReadPrivilege(institutionId);
|
||||
|
||||
final FilterMap filterMap = new FilterMap()
|
||||
.putIfAbsent(Entity.FILTER_ATTR_ACTIVE, "true")
|
||||
.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
|
||||
return this.paginationService.getPage(
|
||||
pageNumber,
|
||||
pageSize,
|
||||
sort,
|
||||
UserRecordDynamicSqlSupport.userRecord,
|
||||
() -> this.activatableEntityDAO.all(institutionId, true)).getOrThrow();
|
||||
() -> getAll(filterMap)).getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
|
@ -93,12 +100,17 @@ public abstract class ActivatableEntityController<T extends GrantEntity, M exten
|
|||
@RequestParam(name = Page.ATTR_SORT, required = false) final String sort) {
|
||||
|
||||
checkReadPrivilege(institutionId);
|
||||
|
||||
final FilterMap filterMap = new FilterMap()
|
||||
.putIfAbsent(Entity.FILTER_ATTR_ACTIVE, "false")
|
||||
.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
|
||||
return this.paginationService.getPage(
|
||||
pageNumber,
|
||||
pageSize,
|
||||
sort,
|
||||
UserRecordDynamicSqlSupport.userRecord,
|
||||
() -> this.activatableEntityDAO.all(institutionId, false)).getOrThrow();
|
||||
() -> getAll(filterMap)).getOrThrow();
|
||||
}
|
||||
|
||||
@RequestMapping(
|
||||
|
|
|
@ -104,7 +104,7 @@ public abstract class EntityController<T extends GrantEntity, M extends GrantEnt
|
|||
|
||||
final FilterMap filterMap = new FilterMap(allRequestParams);
|
||||
|
||||
// if current user has no read access for specified entity type within other institution then its own institution,
|
||||
// if current user has no read access for specified entity type within other institution
|
||||
// then the current users institutionId is put as a SQL filter criteria attribute to extends query performance
|
||||
if (!this.authorization.hasGrant(PrivilegeType.READ_ONLY, this.entityDAO.entityType())) {
|
||||
filterMap.putIfAbsent(API.PARAM_INSTITUTION_ID, String.valueOf(institutionId));
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.mybatis.dynamic.sql.SqlTable;
|
||||
|
@ -31,6 +36,7 @@ import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|||
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
||||
|
@ -38,6 +44,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.SEBServerUser;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO.ActivityType;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
||||
|
@ -97,15 +104,55 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
return new UserMod(null, postParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<Collection<UserInfo>> getAll(final FilterMap filterMap) {
|
||||
return super.getAll(filterMap)
|
||||
.map(result -> result
|
||||
.stream()
|
||||
.filter(this.authorization::hasRoleBasedUserAccountViewGrant)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<UserInfo> validForSave(final UserInfo userInfo) {
|
||||
return Result.tryCatch(() -> {
|
||||
final SEBServerUser currentUser = this.authorization.getUserService().getCurrentUser();
|
||||
final EnumSet<UserRole> rolesOfCurrentUser = currentUser.getUserRoles();
|
||||
final EnumSet<UserRole> userRolesOfAccount = userInfo.getUserRoles();
|
||||
|
||||
// check of institution of UserInfo is active. Otherwise save is not valid
|
||||
if (!this.beanValidationService.isActive(new EntityKey(userInfo.institutionId, EntityType.INSTITUTION))) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
"User within an inactive institution cannot be created nor modified");
|
||||
}
|
||||
|
||||
// check if the current User has the role based right to save the User Account
|
||||
// role based right in this context means that for example a Institutional Administrator that
|
||||
// has normally the right to edit a User Account of his own institution, don't has the right
|
||||
// to edit a User Account of his own institution with a higher role based rank, for example a
|
||||
// SEB Server Admin of the same Institution
|
||||
if (userRolesOfAccount.contains(UserRole.SEB_SERVER_ADMIN) &&
|
||||
!rolesOfCurrentUser.contains(UserRole.SEB_SERVER_ADMIN)) {
|
||||
|
||||
throw new IllegalAPIArgumentException(
|
||||
"The current user cannot edit a User-Account of heigher role pased rank: "
|
||||
+ UserRole.SEB_SERVER_ADMIN);
|
||||
}
|
||||
|
||||
// check if there are only public UserRole set for current User
|
||||
final List<UserRole> publicRolesFor = UserRole.publicRolesForUser(currentUser.getUserInfo());
|
||||
final UserRole nonePublicRole = userRolesOfAccount
|
||||
.stream()
|
||||
.filter(role -> !publicRolesFor.contains(role))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (nonePublicRole != null) {
|
||||
throw new IllegalAPIArgumentException(
|
||||
"The current user has not the privilege to create a User-Account with none public role: "
|
||||
+ nonePublicRole);
|
||||
}
|
||||
|
||||
return userInfo;
|
||||
});
|
||||
}
|
||||
|
@ -144,7 +191,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
|||
throw new APIMessageException(APIMessage.fieldValidationError(
|
||||
new FieldError(
|
||||
"passwordChange",
|
||||
PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD,
|
||||
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
|
||||
"user:retypedNewPassword:password.mismatch")));
|
||||
}
|
||||
|
||||
|
|
|
@ -21,13 +21,30 @@
|
|||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
<!-- <Logger name="ch.ethz.seb.sebserver" level="DEBUG" additivity="true" /> -->
|
||||
<!-- <Logger name="org.mybatis.generator" level="INFO" additivity="true" /> -->
|
||||
<!-- <Logger name="org.springframework.boot" level="INFO" additivity="true" /> -->
|
||||
<!-- <Logger name="org.springframework.security" level="DEBUG" additivity="true" /> -->
|
||||
<Logger name="ch.ethz.seb.sebserver" level="DEBUG" additivity="true" />
|
||||
<Logger name="org.mybatis.generator" level="INFO" additivity="true" />
|
||||
<Logger name="org.springframework.boot" level="INFO" additivity="true" />
|
||||
<Logger name="org.springframework.security" level="DEBUG" additivity="true" />
|
||||
|
||||
<!-- <Logger name="org.springframework.web" level="DEBUG" additivity="true" /> -->
|
||||
<!-- <Logger name="org.springframework.security.oauth2" level="DEBUG" additivity="true" /> -->
|
||||
<Logger name="org.springframework.web" level="DEBUG" additivity="true" />
|
||||
<Logger name="org.springframework.security.oauth2" level="DEBUG" additivity="true" />
|
||||
|
||||
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="test">
|
||||
|
||||
<root level="INFO" additivity="true">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
<Logger name="ch.ethz.seb.sebserver" level="DEBUG" additivity="true" />
|
||||
<Logger name="org.mybatis.generator" level="INFO" additivity="true" />
|
||||
<Logger name="org.springframework.boot" level="INFO" additivity="true" />
|
||||
<Logger name="org.springframework.security" level="DEBUG" additivity="true" />
|
||||
|
||||
<Logger name="org.springframework.web" level="DEBUG" additivity="true" />
|
||||
<Logger name="org.springframework.security.oauth2" level="DEBUG" additivity="true" />
|
||||
|
||||
|
||||
</springProfile>
|
||||
|
|
|
@ -20,8 +20,8 @@ sebserver.overall.action.filter.clear=Clear Filter Criteria
|
|||
sebserver.form.validation.error.title=Form Data Validation Failed
|
||||
sebserver.form.validation.error.message=There is missing or incorrect form data.
|
||||
sebserver.form.validation.fieldError.size=The size must be between {3} and {4}
|
||||
sebserver.form.validation.fieldError.name=Name is mandatory and must have a size between 3 and 255 character
|
||||
sebserver.form.validation.fieldError.urlSuffix=URL Suffix must have a size between 3 and 255 character
|
||||
sebserver.form.validation.fieldError.name=Name is mandatory and must have a size between {3} and {4} character
|
||||
sebserver.form.validation.fieldError.urlSuffix=URL Suffix must have a size between {3} and {4} character
|
||||
sebserver.form.validation.fieldError.notNull=This field is mandatory
|
||||
sebserver.form.validation.fieldError.username.notunique=This Username is already in use. Please choose another one.
|
||||
sebserver.form.validation.fieldError.password.wrong=Old password is wrong
|
||||
|
@ -128,12 +128,12 @@ sebserver.useraccount.form.language=Language
|
|||
sebserver.useraccount.form.timezone=Time Zone
|
||||
sebserver.useraccount.form.roles=User Roles
|
||||
sebserver.useraccount.form.password=Password
|
||||
sebserver.useraccount.form.password.retyped=Retyped Password
|
||||
sebserver.useraccount.form.password.confirm=Confirm Password
|
||||
|
||||
sebserver.useraccount.form.pwchange.title=Change Password : {0}
|
||||
sebserver.useraccount.form.institution.password.old=Old Password
|
||||
sebserver.useraccount.form.institution.password.new=New Password
|
||||
sebserver.useraccount.form.institution.password.retyped=Retyped New Password
|
||||
sebserver.useraccount.form.password.old=Old Password
|
||||
sebserver.useraccount.form.password.new=New Password
|
||||
sebserver.useraccount.form.password.new.confirm=Confirm New Password
|
||||
|
||||
|
||||
|
||||
|
|
140
src/main/resources/messages_de.properties
Normal file
140
src/main/resources/messages_de.properties
Normal file
|
@ -0,0 +1,140 @@
|
|||
################################
|
||||
# Overall
|
||||
################################
|
||||
|
||||
sebserver.overall.version=SEB Server Version : {0}
|
||||
sebserver.overall.imprint=Imprint
|
||||
sebserver.overall.about=About
|
||||
|
||||
sebserver.overall.message.leave.without.save=You are leaving this page without saved changes!\nThe unsaved changes will be lost.\Are you sure to leave the page?
|
||||
sebserver.overall.upload=Bitte Ausw\u00E4hlen
|
||||
sebserver.overall.action.modify.cancel=Abbrechen
|
||||
sebserver.overall.action.modify.cancel.confirm=Nicht gespeicherte Daten gehen verloren. Wirklich abbrechen?
|
||||
sebserver.overall.action.filter=Filtern
|
||||
sebserver.overall.action.filter.clear=Filter Zur\u00FCcksetzen
|
||||
|
||||
################################
|
||||
# Form validation and messages
|
||||
################################
|
||||
|
||||
sebserver.form.validation.error.title=Validierung
|
||||
sebserver.form.validation.error.message=Einige Daten fehlen oder sind nicht korrekt.
|
||||
sebserver.form.validation.fieldError.size=Der Text muss mindestens {3} und kann h\u00F6chstens {4} Zeichen beinhalten
|
||||
sebserver.form.validation.fieldError.name=Name is mandatory and must have a size between {3} and {4} character
|
||||
sebserver.form.validation.fieldError.urlSuffix=URL Suffix must have a size between {3} and {4} character
|
||||
sebserver.form.validation.fieldError.notNull=Dies ist ein Pflichtfeld
|
||||
sebserver.form.validation.fieldError.username.notunique=Dieser Username ist schon in Gebrauch. Bitte w\u00E4hlen Sie einen anderen.
|
||||
sebserver.form.validation.fieldError.password.wrong=Das (aktuelle) Passwort stimmt nicht
|
||||
sebserver.form.validation.fieldError.password.mismatch=Passwort, neues Passwort und Best\u00E4tigung stimmen nicht \u00FCberein
|
||||
sebserver.error.unexpected=Unerwarteter Fehler
|
||||
sebserver.page.message=Information
|
||||
sebserver.dialog.confirm.title=Best\u00E4tigung
|
||||
|
||||
sebserver.dialog.confirm.deactivation=Es gibt {0} weitere Objekte die zu diesem Objeckt geh\u00F6ren.<br/>Diese werden bei einer Deaktivierung ebenfalls deaktiviert.<br/><br/>Sollen alle deaktiviert weden?
|
||||
sebserver.dialog.confirm.deactivation.noDependencies=Soll dieses Object wirklich deaktiviert werden?
|
||||
|
||||
################################
|
||||
# Login Page
|
||||
################################
|
||||
|
||||
sebserver.login.username=Benutzer Name
|
||||
sebserver.login.pwd=Passwort
|
||||
sebserver.login.login=Anmelden
|
||||
sebserver.login.failed.title=Anmelden Fehlgeschlagen
|
||||
sebserver.login.failed.message=Zugang verweigert: Falscher Benutzer Name oder Passwort
|
||||
sebserver.logout=Abmelden
|
||||
sebserver.logout.success.message=Sie wurden erfolgreich abgemeldet
|
||||
sebserver.login.password.change=Information
|
||||
sebserver.login.password.change.success=Das Passwort wurde erfoglreich ge\u00E4ndert. Bitte melden Sie sich mit dem neuen Passwort an.
|
||||
|
||||
################################
|
||||
# Main Page
|
||||
################################
|
||||
|
||||
sebserver.logout=Abmelden
|
||||
sebserver.mainpage.maximize.tooltip=Maximieren
|
||||
sebserver.mainpage.minimize.tooltip=Minimieren
|
||||
sebserver.activitiespane.title=Aktivit\u00E4ten
|
||||
sebserver.actionpane.title=Aktionen
|
||||
|
||||
################################
|
||||
# Institution
|
||||
################################
|
||||
|
||||
sebserver.institution.list.title=Institutionen
|
||||
sebserver.institution.list.column.name=Name
|
||||
sebserver.institution.list.column.urlSuffix=URL Suffix
|
||||
sebserver.institution.list.column.active=Aktiv
|
||||
|
||||
sebserver.institution.action.list=Institution
|
||||
sebserver.institution.action.form=Institution
|
||||
sebserver.institution.action.new=Neue Institution
|
||||
sebserver.institution.action.list.view=Ausgew\u00E4hlte Ansehen
|
||||
sebserver.institution.action.modify=Institution Editieren
|
||||
sebserver.institution.action.list.modify=Ausgew\u00E4hlte Editieren
|
||||
sebserver.institution.action.save=Institution Speichern
|
||||
sebserver.institution.action.activate=Aktiv
|
||||
sebserver.institution.action.deactivate=Aktiv
|
||||
sebserver.institution.action.delete=Institution L\u00F6schen
|
||||
|
||||
|
||||
sebserver.institution.info.pleaseSelect=Bitte zuerst eine Instiiution aus der List ausw\u00E4hlen.
|
||||
sebserver.institution.form.title.new=Neue Institution
|
||||
sebserver.institution.form.title=Institution : {0}
|
||||
|
||||
sebserver.institution.form.name=Name
|
||||
sebserver.institution.form.urlSuffix=URL Suffix
|
||||
sebserver.institution.form.logoImage=Logo Bild
|
||||
|
||||
|
||||
################################
|
||||
# User Account
|
||||
################################
|
||||
|
||||
sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator
|
||||
sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institution Administrator
|
||||
sebserver.useraccount.role.EXAM_ADMIN=Examen Administrator
|
||||
sebserver.useraccount.role.EXAM_SUPPORTER=Examen Supporter
|
||||
|
||||
sebserver.useraccount.list.title=Benutzer Konto
|
||||
sebserver.useraccount.list.column.name=Name
|
||||
sebserver.useraccount.list.column.username=Benutzer Name
|
||||
sebserver.useraccount.list.column.email=E-Mail
|
||||
sebserver.useraccount.list.column.language=Sprache
|
||||
sebserver.useraccount.list.column.active=Aktiv
|
||||
|
||||
sebserver.useraccount.action.list=Benutzer Konto
|
||||
sebserver.useraccount.action.form=Benutzer Konto
|
||||
sebserver.useraccount.action.new=Neues Benutzer Konto
|
||||
sebserver.useraccount.action.view=Ausgew\u00E4hlter Ansehen
|
||||
sebserver.useraccount.action.list.modify=Ausgew\u00E4hlter Editieren
|
||||
sebserver.useraccount.action.modify=Editieren
|
||||
sebserver.useraccount.action.save=Benutzer Konto Speichern
|
||||
sebserver.useraccount.action.activate=Aktiv
|
||||
sebserver.useraccount.action.deactivate=Aktiv
|
||||
sebserver.useraccount.action.delete=Benutzer Konto L\u00F6schen
|
||||
sebserver.useraccount.action.change.password=Passwort Ändern
|
||||
sebserver.useraccount.action.change.password.save=Passwort Speichern
|
||||
|
||||
sebserver.useraccount.info.pleaseSelect=Bitte zuerst ein Benutzer Konto aus der List ausw\u00E4hlen.
|
||||
|
||||
sebserver.useraccount.form.title=Benutzer Konto : {0}
|
||||
sebserver.useraccount.form.title.new=Neues Benutzer Konto
|
||||
sebserver.useraccount.form.institution=Institution
|
||||
sebserver.useraccount.form.name=Name
|
||||
sebserver.useraccount.form.username=Benutzer Name
|
||||
sebserver.useraccount.form.mail=E-Mail
|
||||
sebserver.useraccount.form.language=Sprache
|
||||
sebserver.useraccount.form.timezone=Zeit Zone
|
||||
sebserver.useraccount.form.roles=Benutzer Rollen
|
||||
sebserver.useraccount.form.password=Passwort
|
||||
sebserver.useraccount.form.password.confirm=Passwort Best\u00E4tigen
|
||||
|
||||
sebserver.useraccount.form.pwchange.title=Passwort \u00C4ndern : {0}
|
||||
sebserver.useraccount.form.password.old=Altes Passwort
|
||||
sebserver.useraccount.form.password.new=Neues Passwort
|
||||
sebserver.useraccount.form.password.new.confirm=Neues Password Best\u00E4tigen
|
||||
|
||||
|
||||
|
||||
|
|
@ -386,11 +386,11 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
assertNotNull(institutions);
|
||||
assertEquals("[1]", getOrderedUUIDs(institutions.content));
|
||||
assertEquals("[1, 2]", getOrderedUUIDs(institutions.content));
|
||||
|
||||
// all inactive of the own institution
|
||||
institutions = this.jsonMapper.readValue(
|
||||
this.mockMvc.perform(get(this.endpoint + API.USER_ACCOUNT_ENDPOINT + "/inactive")
|
||||
this.mockMvc.perform(get(this.endpoint + API.INSTITUTION_ENDPOINT + "/inactive")
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
.header("Authorization", "Bearer " + sebAdminToken))
|
||||
.andExpect(status().isOk())
|
||||
|
@ -399,8 +399,8 @@ public class InstitutionAPITest extends AdministrationAPIIntegrationTester {
|
|||
});
|
||||
|
||||
assertNotNull(institutions);
|
||||
assertTrue(institutions.pageSize == 0);
|
||||
assertEquals("[]", getOrderedUUIDs(institutions.content));
|
||||
assertTrue(institutions.pageSize == 1);
|
||||
assertEquals("[3]", getOrderedUUIDs(institutions.content));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -452,7 +452,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID())
|
||||
.param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name())
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isOk())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<UserInfo>() {
|
||||
|
@ -653,7 +653,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.param(Domain.USER.ATTR_TIMEZONE, DateTimeZone.UTC.getID())
|
||||
.param(Domain.USER_ROLE.REFERENCE_NAME, UserRole.EXAM_ADMIN.name())
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andReturn().getResponse().getContentAsString(),
|
||||
new TypeReference<Collection<APIMessage>>() {
|
||||
|
@ -734,7 +734,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isForbidden())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
|
@ -761,7 +761,7 @@ public class UserAPITest extends AdministrationAPIIntegrationTester {
|
|||
.param(Domain.USER.ATTR_INSTITUTION_ID, "2")
|
||||
.param(Domain.USER.ATTR_NAME, "NewTestUser")
|
||||
.param(PasswordChange.ATTR_NAME_NEW_PASSWORD, "12345678")
|
||||
.param(PasswordChange.ATTR_NAME_RETYPED_NEW_PASSWORD, "12345678"))
|
||||
.param(PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD, "12345678"))
|
||||
.andExpect(status().isForbidden())
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
|
||||
|
|
Loading…
Reference in a new issue