SEBSERV-21 & SEBSERV-27 fixed role based User-Account access

This commit is contained in:
anhefti 2019-02-26 16:33:20 +01:00
parent cf636e974b
commit 8af5a4fc93
31 changed files with 450 additions and 102 deletions

View file

@ -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

View file

@ -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();

View file

@ -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;

View file

@ -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 + "]";
}
}

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -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));
;
}

View file

@ -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));

View file

@ -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)

View file

@ -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) {

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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());
}
}
}

View file

@ -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.
*

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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) {

View file

@ -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(

View file

@ -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));

View file

@ -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")));
}

View file

@ -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>

View file

@ -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

View 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

View file

@ -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

View file

@ -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();