SEBSERV-135 improved identity handling and error messages

This commit is contained in:
anhefti 2021-06-28 17:33:24 +02:00
parent 730ec7dfc8
commit d76f1f5ca9
16 changed files with 77 additions and 52 deletions

View file

@ -203,7 +203,7 @@ public class APIMessage implements Serializable {
return ErrorMessage.FIELD_VALIDATION.of(fieldName, args);
}
public static String toHTML(final String errorMessage, final List<APIMessage> messages) {
public static String toHTML(final String errorMessage, final Collection<APIMessage> messages) {
final StringBuilder builder = new StringBuilder();
builder.append("<b>Failure:</b>").append("<br/><br/>").append(errorMessage).append("<br/><br/>");
builder.append("<b>Detail Messages:</b><br/><br/>");
@ -220,7 +220,7 @@ public class APIMessage implements Serializable {
* within an Exception and throw. The Exception will be caught a the
* APIExceptionHandler endpoint. The APIMessage will be extracted
* and send as response. */
public static class APIMessageException extends RuntimeException {
public static class APIMessageException extends RuntimeException implements APIMessageError {
private static final long serialVersionUID = 1453431210820677296L;
@ -246,6 +246,7 @@ public class APIMessage implements Serializable {
this.apiMessages = Arrays.asList(errorMessage.of(detail, attributes));
}
@Override
public Collection<APIMessage> getAPIMessages() {
return this.apiMessages;
}
@ -283,11 +284,11 @@ public class APIMessage implements Serializable {
}
public static boolean checkError(final Exception error, final ErrorMessage errorMessage) {
if (!(error instanceof APIMessageException)) {
if (!(error instanceof APIMessageError)) {
return false;
}
final APIMessageException _error = (APIMessageException) error;
final APIMessageError _error = (APIMessageError) error;
return _error.getAPIMessages()
.stream()
.filter(msg -> errorMessage.messageCode.equals(msg.messageCode))

View file

@ -8,14 +8,14 @@
package ch.ethz.seb.sebserver.gbl.api;
import java.util.List;
import java.util.Collection;
/** Defines an API message error holder that supplies a List of APIMessage if error happened */
public interface APIMessageError {
/** Get a List of APIMessage errors if error happened
*
* @return a List of APIMessage errors if error happened or empty list of not*/
List<APIMessage> getErrorMessages();
* @return a List of APIMessage errors if error happened or empty list of not */
Collection<APIMessage> getAPIMessages();
}

View file

@ -203,10 +203,16 @@ public final class SEBClientConfig implements GrantEntity, Activatable {
this.configPurpose = configPurpose;
this.sebServerPingTime = sebServerPingTime;
this.vdiType = vdiType;
this.vdiExecutable = vdiExecutable != null ? vdiExecutable : vdiType.defaultExecutable;
this.vdiPath = vdiPath != null ? vdiPath : vdiType.defaultPath;
this.vdiArguments = vdiArguments != null ? vdiArguments : vdiType.defaultArguments;
this.vdiType = vdiType != null ? vdiType : VDIType.NO;
this.vdiExecutable = vdiExecutable != null
? vdiExecutable
: vdiType != null ? vdiType.defaultExecutable : null;
this.vdiPath = vdiPath != null
? vdiPath
: vdiType != null ? vdiType.defaultPath : null;
this.vdiArguments = vdiArguments != null
? vdiArguments
: vdiType != null ? vdiType.defaultArguments : null;
this.fallback = fallback;
this.fallbackStartURL = fallbackStartURL;

View file

@ -176,7 +176,7 @@ public class CertificateImportPopup {
final Exception error = result.getError();
if (error instanceof RestCallError) {
((RestCallError) error)
.getErrorMessages()
.getAPIMessages()
.stream()
.findFirst()
.ifPresent(message -> {

View file

@ -75,6 +75,8 @@ public class CertificateList implements TemplateComposer {
new LocTextKey("sebserver.certificate.action.import-config.confirm");
static final LocTextKey FORM_ACTION_MESSAGE_IN_USE_TEXT_KEY =
new LocTextKey("sebserver.certificate.action.remove.in-use");
static final LocTextKey FORM_ACTION_MESSAGE_REMOVE_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.certificate.action.remove.confirm");
private final TableFilterAttribute aliasFilter = new TableFilterAttribute(
CriteriaType.TEXT,
@ -155,6 +157,7 @@ public class CertificateList implements TemplateComposer {
.publishIf(() -> grantCheck.iw())
.newAction(ActionDefinition.SEB_CERTIFICATE_REMOVE)
.withConfirm(() -> FORM_ACTION_MESSAGE_REMOVE_CONFIRM_TEXT_KEY)
.withSelect(
table::getSelection,
this::removeCertificate,

View file

@ -16,6 +16,7 @@ import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -332,14 +333,16 @@ public class SEBClientConfigForm implements TemplateComposer {
// VDI
.withDefaultSpanInput(2)
.addField(FormBuilder.singleSelection(
SEBClientConfig.ATTR_VDI_TYPE,
VDI_TYPE_TEXT_KEY,
clientConfig.vdiType != null
? clientConfig.vdiType.name()
: SEBClientConfig.VDIType.NO.name(),
() -> this.pageService.getResourceService().vdiTypeResources())
.mandatory(!isReadonly))
.addFieldIf(
() -> false, // TODO skipped for version 1.2 --> 1.3 or 1.4
() -> FormBuilder.singleSelection(
SEBClientConfig.ATTR_VDI_TYPE,
VDI_TYPE_TEXT_KEY,
clientConfig.vdiType != null
? clientConfig.vdiType.name()
: SEBClientConfig.VDIType.NO.name(),
() -> this.pageService.getResourceService().vdiTypeResources())
.mandatory(!isReadonly))
.withDefaultSpanEmptyCell(3);
// VDI Attributes
@ -472,10 +475,18 @@ public class SEBClientConfigForm implements TemplateComposer {
};
if (!isReadonly) {
formHandleAnchor.formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_FALLBACK)
.addListener(SWT.Selection, selectionListener);
formHandleAnchor.formHandle.getForm().getFieldInput(SEBClientConfig.ATTR_VDI_TYPE)
.addListener(SWT.Selection, selectionListener);
final Control fallbackInput = formHandleAnchor.formHandle
.getForm()
.getFieldInput(SEBClientConfig.ATTR_FALLBACK);
if (fallbackInput != null) {
fallbackInput.addListener(SWT.Selection, selectionListener);
}
final Control vdiInput = formHandleAnchor.formHandle
.getForm()
.getFieldInput(SEBClientConfig.ATTR_VDI_TYPE);
if (vdiInput != null) {
vdiInput.addListener(SWT.Selection, selectionListener);
}
}
formContent.layout();

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.content;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;
@ -210,7 +211,7 @@ public class SEBExamConfigImportPopup {
final Exception error = configuration.getError();
if (error instanceof RestCallError) {
((RestCallError) error)
.getErrorMessages()
.getAPIMessages()
.stream()
.findFirst()
.ifPresent(message -> {
@ -393,8 +394,8 @@ public class SEBExamConfigImportPopup {
private static void notifyErrorOnSave(final Exception error, final PageContext context) {
if (error instanceof APIMessageError) {
try {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final APIMessage apiMessage = errorMessages.get(0);
final Collection<APIMessage> errorMessages = ((APIMessageError) error).getAPIMessages();
final APIMessage apiMessage = errorMessages.iterator().next();
if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) {
context.publishPageMessage(new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION));
} else {

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
@ -324,8 +325,8 @@ public class SEBSettingsForm implements TemplateComposer {
public void notifyErrorOnSave(final Exception error, final PageContext context) {
if (error instanceof APIMessageError) {
try {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final APIMessage apiMessage = errorMessages.get(0);
final Collection<APIMessage> errorMessages = ((APIMessageError) error).getAPIMessages();
final APIMessage apiMessage = errorMessages.iterator().next();
if (APIMessage.ErrorMessage.INTEGRITY_VALIDATION.isOf(apiMessage)) {
throw new PageMessageException(MESSAGE_SAVE_INTEGRITY_VIOLATION);
} else {

View file

@ -144,13 +144,13 @@ public class FormHandle<T extends Entity> {
if (error instanceof RestCallError) {
final List<APIMessage> fieldValidationErrors = ((RestCallError) error)
.getErrorMessages()
.getAPIMessages()
.stream()
.filter(APIMessage.ErrorMessage.FIELD_VALIDATION::isOf)
.collect(Collectors.toList());
final List<APIMessage> noneFieldValidationErrors = ((RestCallError) error)
.getErrorMessages()
.getAPIMessages()
.stream()
.filter(message -> !APIMessage.ErrorMessage.FIELD_VALIDATION.isOf(message))
.collect(Collectors.toList());

View file

@ -390,7 +390,7 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
private String verifyErrorMessage(final Exception error) {
if (error instanceof RestCallError) {
final List<APIMessage> errorMessages = ((RestCallError) error).getErrorMessages();
final List<APIMessage> errorMessages = ((RestCallError) error).getAPIMessages();
if (errorMessages.isEmpty()) {
return "";
}

View file

@ -9,6 +9,7 @@
package ch.ethz.seb.sebserver.gui.service.page.impl;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -332,7 +333,7 @@ public class PageContextImpl implements PageContext {
: error.getMessage();
if (error instanceof APIMessageError) {
final List<APIMessage> errorMessages = ((APIMessageError) error).getErrorMessages();
final Collection<APIMessage> errorMessages = ((APIMessageError) error).getAPIMessages();
final MessageBox messageBox = new Message(
getShell(),
this.i18nSupport.getText("sebserver.error.unexpected"),

View file

@ -38,7 +38,7 @@ public class RestCallError extends RuntimeException implements APIMessageError {
}
@Override
public List<APIMessage> getErrorMessages() {
public List<APIMessage> getAPIMessages() {
return this.errors;
}

View file

@ -223,12 +223,7 @@ public class CertificateDAOImpl implements CertificateDAO {
// dataEncipherment
if (keyUsage[2] || keyUsage[3]) {
final String alias = certificates.keyStore.engineGetCertificateAlias(cert);
if (this.cryptor.getPrivateKey(certificates.keyStore, alias).hasValue()) {
result.add(CertificateType.DATA_ENCIPHERMENT_PRIVATE_KEY);
} else {
result.add(CertificateType.DATA_ENCIPHERMENT);
}
result.add(CertificateType.DATA_ENCIPHERMENT);
}
// keyCertSign
@ -240,6 +235,11 @@ public class CertificateDAOImpl implements CertificateDAO {
result.add(CertificateType.UNKNOWN);
}
final String alias = certificates.keyStore.engineGetCertificateAlias(cert);
if (this.cryptor.getPrivateKey(certificates.keyStore, alias).hasValue()) {
result.add(CertificateType.DATA_ENCIPHERMENT_PRIVATE_KEY);
}
return result;
}

View file

@ -85,7 +85,7 @@ public abstract class AbstractCertificateCryptor {
final String algorithm = cert.getPublicKey().getAlgorithm();
final Cipher encryptCipher = Cipher.getInstance(algorithm);
encryptCipher.init(Cipher.ENCRYPT_MODE, cert);
encryptCipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
return encryptCipher.doFinal(data, 0, length);
}
@ -99,7 +99,7 @@ public abstract class AbstractCertificateCryptor {
final String algorithm = cert.getPublicKey().getAlgorithm();
final Cipher encryptCipher = Cipher.getInstance(algorithm);
encryptCipher.init(Cipher.DECRYPT_MODE, cert);
encryptCipher.init(Cipher.DECRYPT_MODE, cert.getPublicKey());
return encryptCipher.doFinal(encryptedData, 0, length);
}

View file

@ -1607,6 +1607,7 @@ sebserver.certificate.action.import.missing-password=The certificate file needs
sebserver.certificate.action.import-config.confirm=Certificate(s) successfully imported
sebserver.certificate.message.error.file=Unsupported file type
sebserver.certificate.action.import-file-select.no=Please select a valid file
sebserver.certificate.action.remove.confirm=Are you sure you want delete the selected Certificate(s)?
sebserver.certificate.action.remove.in-use=This certificate is in use and cannot be removed.

View file

@ -381,7 +381,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
RestCallError error = (RestCallError) call.getError();
assertEquals(
"[APIMessage [messageCode=1001, systemMessage=FORBIDDEN, details=No edit right grant for user: TestInstAdmin, attributes=[]]]",
String.valueOf(error.getErrorMessages()));
String.valueOf(error.getAPIMessages()));
// change password
final Result<UserInfo> passwordChange = restService
@ -400,7 +400,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
error = (RestCallError) instNames.getError();
assertEquals(
"UNAUTHORIZED",
String.valueOf(error.getErrorMessages().get(0).getSystemMessage()));
String.valueOf(error.getAPIMessages().get(0).getSystemMessage()));
// login again with the new password and check roles
restService = createRestServiceForUser(
@ -2339,7 +2339,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("Forbidden error message expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1001", apiMessage.messageCode);
assertEquals("FORBIDDEN", apiMessage.systemMessage);
}
@ -2395,7 +2395,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2408,7 +2408,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2419,7 +2419,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2430,7 +2430,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2441,7 +2441,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2452,7 +2452,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}
@ -2463,7 +2463,7 @@ public class UseCasesIntegrationTest extends GuiIntegrationTest {
.getOrThrow();
fail("no resource found exception expected here");
} catch (final RestCallError e) {
final APIMessage apiMessage = e.getErrorMessages().get(0);
final APIMessage apiMessage = e.getAPIMessages().get(0);
assertEquals("1002", apiMessage.getMessageCode());
assertEquals("resource not found", apiMessage.getSystemMessage());
}