From 18dce531704352f9ca29488e983cf3a55f82cf7f Mon Sep 17 00:00:00 2001 From: anhefti Date: Thu, 22 Apr 2021 08:49:52 +0200 Subject: [PATCH] SEBSERV-135 - gui implementation --- .../ch/ethz/seb/sebserver/gbl/api/API.java | 1 + ...tificateData.java => CertificateInfo.java} | 25 ++-- .../gui/content/CertificateList.java | 123 ++++++++++++++++++ .../gui/content/action/ActionCategory.java | 3 +- .../gui/content/action/ActionDefinition.java | 14 ++ .../gui/content/activity/ActivitiesPane.java | 12 ++ .../content/activity/ActivityDefinition.java | 1 + .../activity/PageStateDefinitionImpl.java | 6 +- .../api/seb/cert/AddCertificate.java | 40 ++++++ .../api/seb/cert/GetCertificate.java | 40 ++++++ .../api/seb/cert/GetCertificateNames.java | 42 ++++++ .../api/seb/cert/GetCertificatePage.java | 41 ++++++ .../api/seb/cert/RemoveCertificate.java | 39 ++++++ .../servicelayer/dao/CertificateDAO.java | 20 ++- .../dao/impl/CertificateDAOImpl.java | 4 +- .../sebconfig/CertificateService.java | 28 ++-- .../impl/CertificateServiceImpl.java | 37 ++++-- .../weblayer/api/CertificateController.java | 41 +++--- src/main/resources/messages.properties | 15 +++ 19 files changed, 456 insertions(+), 76 deletions(-) rename src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/{CertificateData.java => CertificateInfo.java} (85%) create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/content/CertificateList.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/AddCertificate.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificate.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificateNames.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificatePage.java create mode 100644 src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/RemoveCertificate.java diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java index c3a63afc..f64e4e6e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java @@ -202,5 +202,6 @@ public final class API { public static final String CERTIFICATE_ALIAS = "alias"; public static final String CERTIFICATE_FILE_TYPE = "fileType"; public static final String CERTIFICATE_PASSWORD_ATTR_NAME = "certPassword"; + public static final String CERTIFICATE_ALIAS_VAR_PATH_SEGMENT = "/{" + CERTIFICATE_ALIAS + "}"; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateData.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateInfo.java similarity index 85% rename from src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateData.java rename to src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateInfo.java index 09b03b8f..1949ac50 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/sebconfig/CertificateInfo.java @@ -20,17 +20,17 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Entity; @JsonIgnoreProperties(ignoreUnknown = true) -public class CertificateData implements Entity { +public class CertificateInfo implements Entity { public static enum CertificateType { UNKNOWN, - SSL_TLS, - CA, - IDENTITY + DIGITAL_SIGNATURE, + DATA_ENCIPHERMENT, + KEY_CERT_SIGN } public static enum CertificateFileType { - PEM("pem", "crt"), + PEM("pem", "crt", "cer"), PKCS12("p12", "pfx"); private String[] extentions; @@ -61,22 +61,17 @@ public class CertificateData implements Entity { @JsonProperty(ATTR_CERT_TYPE) public final EnumSet types; - @JsonProperty(ATTR_CERT_BASE_64) - public final String certBase64; - @JsonCreator - public CertificateData( + public CertificateInfo( @JsonProperty(ATTR_ALIAS) final String alias, @JsonProperty(ATTR_ALIAS) final DateTime validityFrom, @JsonProperty(ATTR_ALIAS) final DateTime validityTo, - @JsonProperty(ATTR_CERT_TYPE) final EnumSet types, - @JsonProperty(ATTR_CERT_BASE_64) final String certBase64) { + @JsonProperty(ATTR_CERT_TYPE) final EnumSet types) { this.alias = alias; this.validityFrom = validityFrom; this.validityTo = validityTo; this.types = types; - this.certBase64 = certBase64; } public String getAlias() { @@ -95,10 +90,6 @@ public class CertificateData implements Entity { return this.types; } - public String getCertBase64() { - return this.certBase64; - } - @Override public String getModelId() { return this.alias; @@ -130,7 +121,7 @@ public class CertificateData implements Entity { return false; if (getClass() != obj.getClass()) return false; - final CertificateData other = (CertificateData) obj; + final CertificateInfo other = (CertificateInfo) obj; if (this.alias == null) { if (other.alias != null) return false; diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/CertificateList.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/CertificateList.java new file mode 100644 index 00000000..7631a505 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/CertificateList.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.content; + +import org.eclipse.swt.widgets.Composite; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; +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.page.PageContext; +import ch.ethz.seb.sebserver.gui.service.page.PageService; +import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert.GetCertificatePage; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; +import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; +import ch.ethz.seb.sebserver.gui.table.EntityTable; +import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; + +@Lazy +@Component +@GuiProfile +public class CertificateList implements TemplateComposer { + + private static final LocTextKey EMPTY_LIST_TEXT_KEY = + new LocTextKey("sebserver.certificate.list.empty"); + private static final LocTextKey TITLE_TEXT_KEY = + new LocTextKey("sebserver.certificate.list.title"); + private static final LocTextKey ALIAS_TEXT_KEY = + new LocTextKey("sebserver.certificate.list.column.alias"); + private static final LocTextKey VALID_FROM_KEY = + new LocTextKey("sebserver.certificate.list.column.validFrom"); + private static final LocTextKey VALID_TO_KEY = + new LocTextKey("sebserver.certificate.list.column.validTo"); + private static final LocTextKey TYPE_TEXT_KEY = + new LocTextKey("sebserver.certificate.list.column.type"); + + private final TableFilterAttribute aliasFilter = new TableFilterAttribute( + CriteriaType.TEXT, + CertificateInfo.FILTER_ATTR_ALIAS); + + private final PageService pageService; + private final RestService restService; + private final CurrentUser currentUser; + private final int pageSize; + + protected CertificateList( + final PageService pageService, + @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { + + this.pageService = pageService; + this.restService = pageService.getRestService(); + this.currentUser = pageService.getCurrentUser(); + this.pageSize = pageSize; + } + + @Override + public void compose(final PageContext pageContext) { + final Composite content = this.pageService + .getWidgetFactory() + .defaultPageLayout( + pageContext.getParent(), + TITLE_TEXT_KEY); + + // table + final EntityTable table = + this.pageService.entityTableBuilder(this.restService.getRestCall(GetCertificatePage.class)) + .withEmptyMessage(EMPTY_LIST_TEXT_KEY) + .withPaging(this.pageSize) + + .withColumn(new ColumnDefinition<>( + CertificateInfo.ATTR_ALIAS, + ALIAS_TEXT_KEY, + CertificateInfo::getAlias) + .sortable() + .withFilter(this.aliasFilter)) + + .withColumn(new ColumnDefinition<>( + CertificateInfo.ATTR_VALIDITY_FROM, + VALID_FROM_KEY, + CertificateInfo::getValidityFrom) + .sortable()) + + .withColumn(new ColumnDefinition<>( + CertificateInfo.ATTR_VALIDITY_TO, + VALID_TO_KEY, + CertificateInfo::getValidityTo) + .sortable()) + + .withColumn(new ColumnDefinition<>( + CertificateInfo.ATTR_CERT_TYPE, + TYPE_TEXT_KEY, + this::getTypeInfo)) + + .withSelectionListener(this.pageService.getSelectionPublisher( + pageContext, + ActionDefinition.SEB_CERTIFICATE_REMOVE)) + + .compose(pageContext.copyOf(content)); + } + + private String getTypeInfo(final CertificateInfo certificateInfo) { + final I18nSupport i18nSupport = this.pageService.getI18nSupport(); + //i18nSupport.getText("") + + // TODO + + return ""; + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java index 0fbf8a1d..6ed4c968 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionCategory.java @@ -25,7 +25,8 @@ public enum ActionCategory { SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1), SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1), RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1), - EXAM_MONITORING_NOTIFICATION_LIST(new LocTextKey("sebserver.monitoring.exam.connection.notificationlist.actions"), + EXAM_MONITORING_NOTIFICATION_LIST(new LocTextKey( + "sebserver.monitoring.exam.connection.notificationlist.actions"), 1), CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1), LOGS_USER_ACTIVITY_LIST(new LocTextKey("sebserver.userlogs.list.actions"), 1), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index 6db29a23..759b47e1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -612,6 +612,20 @@ public enum ActionDefinition { PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_VIEW, ActionCategory.FORM), + SEB_CERTIFICATE_LIST( + new LocTextKey("sebserver.certificate.action.list"), + PageStateDefinitionImpl.SEB_CERTIFICATE_LIST), + SEB_CERTIFICATE_IMPORT( + new LocTextKey("sebserver.certificate.action.import"), + ImageIcon.IMPORT, + PageStateDefinitionImpl.SEB_CERTIFICATE_LIST, + ActionCategory.FORM), + SEB_CERTIFICATE_REMOVE( + new LocTextKey("sebserver.certificate.action.remove"), + ImageIcon.DELETE, + PageStateDefinitionImpl.SEB_CERTIFICATE_LIST, + ActionCategory.FORM), + RUNNING_EXAM_VIEW_LIST( new LocTextKey("sebserver.monitoring.action.list"), PageStateDefinitionImpl.MONITORING_RUNNING_EXAM_LIST), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java index 8547959f..5895b022 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java @@ -229,6 +229,18 @@ public class ActivitiesPane implements TemplateComposer { .create()); } + // Certificate management + if (!isSupporterOnly) { + final TreeItem examConfigTemplate = this.widgetFactory.treeItemLocalized( + sebConfigs, + ActivityDefinition.SEB_CERTIFICATE_MANAGEMENT.displayName); + injectActivitySelection( + examConfigTemplate, + actionBuilder + .newAction(ActionDefinition.SEB_CERTIFICATE_LIST) + .create()); + } + sebConfigs.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java index 602591a7..0e2eb8a6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivityDefinition.java @@ -24,6 +24,7 @@ public enum ActivityDefinition implements Activity { SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.list.title")), SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")), SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")), + SEB_CERTIFICATE_MANAGEMENT(new LocTextKey("sebserver.certificate.action.list")), MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")), MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")), SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs")); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java index 191fa0cc..c0844ca3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/PageStateDefinitionImpl.java @@ -8,6 +8,7 @@ package ch.ethz.seb.sebserver.gui.content.activity; +import ch.ethz.seb.sebserver.gui.content.CertificateList; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm; import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList; @@ -25,8 +26,8 @@ import ch.ethz.seb.sebserver.gui.content.QuizLookupList; import ch.ethz.seb.sebserver.gui.content.SEBClientConfigForm; import ch.ethz.seb.sebserver.gui.content.SEBClientConfigList; import ch.ethz.seb.sebserver.gui.content.SEBClientEvents; -import ch.ethz.seb.sebserver.gui.content.SEBExamConfigList; import ch.ethz.seb.sebserver.gui.content.SEBExamConfigForm; +import ch.ethz.seb.sebserver.gui.content.SEBExamConfigList; import ch.ethz.seb.sebserver.gui.content.SEBSettingsForm; import ch.ethz.seb.sebserver.gui.content.UserAccountChangePasswordForm; import ch.ethz.seb.sebserver.gui.content.UserAccountForm; @@ -80,6 +81,9 @@ public enum PageStateDefinitionImpl implements PageStateDefinition { ConfigTemplateAttributeForm.class, ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE), + SEB_CERTIFICATE_LIST(Type.LIST_VIEW, CertificateList.class, + ActivityDefinition.SEB_CERTIFICATE_MANAGEMENT), + MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS), MONITORING_CLIENT_CONNECTION(Type.FORM_VIEW, MonitoringClientConnection.class, ActivityDefinition.MONITORING_EXAMS), diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/AddCertificate.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/AddCertificate.java new file mode 100644 index 00000000..eebf336f --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/AddCertificate.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class AddCertificate extends RestCall { + + public AddCertificate() { + super(new TypeKey<>( + CallType.UNDEFINED, + EntityType.CERTIFICATE, + new TypeReference() { + }), + HttpMethod.POST, + MediaType.APPLICATION_OCTET_STREAM, + API.CERTIFICATE_ENDPOINT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificate.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificate.java new file mode 100644 index 00000000..cdc614d1 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificate.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetCertificate extends RestCall { + + public GetCertificate() { + super(new TypeKey<>( + CallType.GET_SINGLE, + EntityType.CERTIFICATE, + new TypeReference() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CERTIFICATE_ENDPOINT + API.CERTIFICATE_ALIAS_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificateNames.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificateNames.java new file mode 100644 index 00000000..923d2aff --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificateNames.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert; + +import java.util.List; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.EntityName; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetCertificateNames extends RestCall> { + + public GetCertificateNames() { + super(new TypeKey<>( + CallType.GET_NAMES, + EntityType.CERTIFICATE, + new TypeReference>() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CERTIFICATE_ENDPOINT + API.NAMES_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificatePage.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificatePage.java new file mode 100644 index 00000000..d22ab81b --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/GetCertificatePage.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class GetCertificatePage extends RestCall> { + + public GetCertificatePage() { + super(new TypeKey<>( + CallType.GET_PAGE, + EntityType.CERTIFICATE, + new TypeReference>() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CERTIFICATE_ENDPOINT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/RemoveCertificate.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/RemoveCertificate.java new file mode 100644 index 00000000..be0707a5 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/seb/cert/RemoveCertificate.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.cert; + +import org.springframework.context.annotation.Lazy; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.core.type.TypeReference; + +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.EntityType; +import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; + +@Lazy +@Component +@GuiProfile +public class RemoveCertificate extends RestCall { + + public RemoveCertificate() { + super(new TypeKey<>( + CallType.GET_SINGLE, + EntityType.CERTIFICATE, + new TypeReference<>() { + }), + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + API.CERTIFICATE_ENDPOINT + API.CERTIFICATE_ALIAS_VAR_PATH_SEGMENT); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/CertificateDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/CertificateDAO.java index 01e2ceb2..c2b525dd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/CertificateDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/CertificateDAO.java @@ -10,14 +10,13 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.util.Base64; import java.util.EnumSet; import java.util.NoSuchElementException; import org.joda.time.DateTime; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData.CertificateType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; import ch.ethz.seb.sebserver.gbl.util.Result; import io.micrometer.core.instrument.util.StringUtils; @@ -27,22 +26,21 @@ public interface CertificateDAO { Result getCertificates(Long institutionId); - Result addCertificate(Long institutionId, String alias, Certificate certificate); + Result addCertificate(Long institutionId, String alias, Certificate certificate); Result removeCertificate(Long institutionId, String alias); - static Result getDataFromCertificate(final Certificates certificates, final String alias) { + static Result getDataFromCertificate(final Certificates certificates, final String alias) { return Result.tryCatch(() -> { final X509Certificate certificate = (X509Certificate) certificates.keyStore.engineGetCertificate(alias); if (certificate != null) { final X509Certificate cert = certificate; - return new CertificateData( + return new CertificateInfo( extractAlias(cert, alias), new DateTime(cert.getNotBefore()), new DateTime(cert.getNotAfter()), - getTypes(cert), - Base64.getEncoder().encodeToString(cert.getEncoded())); + getTypes(cert)); } else { throw new NoSuchElementException("X509Certificate with alias: " + alias); @@ -75,17 +73,17 @@ public interface CertificateDAO { // digitalSignature if (keyUsage[0]) { - result.add(CertificateType.SSL_TLS); + result.add(CertificateType.DIGITAL_SIGNATURE); } // dataEncipherment if (keyUsage[3]) { - result.add(CertificateType.IDENTITY); + result.add(CertificateType.DATA_ENCIPHERMENT); } // keyCertSign if (keyUsage[5]) { - result.add(CertificateType.CA); + result.add(CertificateType.KEY_CERT_SIGN); } if (result.isEmpty()) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/CertificateDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/CertificateDAOImpl.java index 1cb9bd82..4a106341 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/CertificateDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/CertificateDAOImpl.java @@ -26,7 +26,7 @@ import org.springframework.transaction.annotation.Transactional; import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.EntityType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Cryptor; @@ -68,7 +68,7 @@ public class CertificateDAOImpl implements CertificateDAO { @Override @Transactional - public Result addCertificate( + public Result addCertificate( final Long institutionId, final String alias, final Certificate certificate) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/CertificateService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/CertificateService.java index d29e296a..9a7ef13e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/CertificateService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/CertificateService.java @@ -14,22 +14,22 @@ import java.util.function.Predicate; import org.apache.commons.lang3.StringUtils; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData.CertificateFileType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData.CertificateType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateFileType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; public interface CertificateService { - Result getCertificateData(Long institutionId, String alias); + Result getCertificateInfo(Long institutionId, String alias); - Result> getCertificateData(Long institutionId, FilterMap filterMap); + Result> getCertificateInfo(Long institutionId, FilterMap filterMap); Result getCertificates(Long institutionId); - Result addCertificate( + Result addCertificate( Long institutionId, CertificateFileType certificateFileType, String alias, @@ -37,19 +37,21 @@ public interface CertificateService { Result removeCertificate(Long institutionId, String alias); - Result> toCertificateData(Certificates certificates); + Result> toCertificateInfo(Certificates certificates); - default Predicate createFilter(final FilterMap filterMap) { - final String aliasFilter = filterMap.getString(CertificateData.FILTER_ATTR_ALIAS); + Result getBase64Encoded(Long institutionId, String alias); + + default Predicate createFilter(final FilterMap filterMap) { + final String aliasFilter = filterMap.getString(CertificateInfo.FILTER_ATTR_ALIAS); final CertificateType typeFilter = filterMap.getEnum( - CertificateData.FILTER_ATTR_TYPE, + CertificateInfo.FILTER_ATTR_TYPE, CertificateType.class); - return certificateData -> { + return certificateInfo -> { if (StringUtils.isNotBlank(aliasFilter) && - !certificateData.alias.contains(aliasFilter)) { + !certificateInfo.alias.contains(aliasFilter)) { return false; } - if (typeFilter != null && !certificateData.types.contains(typeFilter)) { + if (typeFilter != null && !certificateInfo.types.contains(typeFilter)) { return false; } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateServiceImpl.java index a4daa27f..1b350650 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateServiceImpl.java @@ -9,8 +9,11 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl; import java.io.InputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.Base64; import java.util.Collection; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -18,8 +21,8 @@ import java.util.stream.Collectors; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData.CertificateFileType; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateFileType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; @@ -39,7 +42,7 @@ public class CertificateServiceImpl implements CertificateService { } @Override - public Result getCertificateData(final Long institutionId, final String alias) { + public Result getCertificateInfo(final Long institutionId, final String alias) { return this.certificateDAO .getCertificates(institutionId) @@ -47,7 +50,7 @@ public class CertificateServiceImpl implements CertificateService { } @Override - public Result> getCertificateData( + public Result> getCertificateInfo( final Long institutionId, final FilterMap filterMap) { @@ -64,7 +67,7 @@ public class CertificateServiceImpl implements CertificateService { } @Override - public Result addCertificate( + public Result addCertificate( final Long institutionId, final CertificateFileType certificateFileType, final String alias, @@ -83,13 +86,29 @@ public class CertificateServiceImpl implements CertificateService { } @Override - public Result> toCertificateData(final Certificates certificates) { + public Result> toCertificateInfo(final Certificates certificates) { return Result.tryCatch(() -> getDataFromCertificates(certificates)); } - private Collection getDataFromCertificates( + @Override + public Result getBase64Encoded(final Long institutionId, final String alias) { + return this.certificateDAO + .getCertificates(institutionId) + .map(certs -> certs.keyStore.engineGetCertificate(alias)) + .map(this::getBase64Encoded); + } + + private String getBase64Encoded(final Certificate cert) { + try { + return Base64.getEncoder().encodeToString(cert.getEncoded()); + } catch (final CertificateEncodingException e) { + throw new RuntimeException(); + } + } + + private Collection getDataFromCertificates( final Certificates certificates, - final Predicate predicate) { + final Predicate predicate) { return certificates.aliases .stream() @@ -99,7 +118,7 @@ public class CertificateServiceImpl implements CertificateService { .collect(Collectors.toList()); } - private Collection getDataFromCertificates(final Certificates certificates) { + private Collection getDataFromCertificates(final Certificates certificates) { return getDataFromCertificates(certificates, data -> true); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/CertificateController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/CertificateController.java index bd97d5ab..f80d66a4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/CertificateController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/CertificateController.java @@ -39,9 +39,8 @@ import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityName; import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateData.CertificateFileType; -import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo; +import ch.ethz.seb.sebserver.gbl.model.sebconfig.CertificateInfo.CertificateFileType; import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; @@ -117,7 +116,7 @@ public class CertificateController { method = RequestMethod.GET, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Page getPage( + public Page getPage( @RequestParam( name = API.PARAM_INSTITUTION_ID, required = true, @@ -131,8 +130,8 @@ public class CertificateController { checkReadPrivilege(institutionId); final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString()); - final Collection certificates = this.certificateService - .getCertificateData(institutionId, filterMap) + final Collection certificates = this.certificateService + .getCertificateInfo(institutionId, filterMap) .getOrThrow(); return this.paginationService.buildPageFromList( @@ -160,7 +159,7 @@ public class CertificateController { checkReadPrivilege(institutionId); return this.certificateService - .getCertificateData( + .getCertificateInfo( institutionId, new FilterMap(allRequestParams, request.getQueryString())) .getOrThrow() @@ -170,19 +169,19 @@ public class CertificateController { } @RequestMapping( - path = API.MODEL_ID_VAR_PATH_SEGMENT, + path = API.CERTIFICATE_ALIAS_VAR_PATH_SEGMENT, method = RequestMethod.GET, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public CertificateData getBy( + public CertificateInfo getAlias( @RequestParam( name = API.PARAM_INSTITUTION_ID, required = true, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, - @PathVariable final String modelId) { + @PathVariable final String alias) { return this.certificateService - .getCertificateData(institutionId, modelId) + .getCertificateInfo(institutionId, alias) .getOrThrow(); } @@ -190,7 +189,7 @@ public class CertificateController { method = RequestMethod.POST, consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Certificates loadCertificate( + public CertificateInfo loadCertificate( @RequestParam( name = API.PARAM_INSTITUTION_ID, required = true, @@ -212,8 +211,7 @@ public class CertificateController { inputStream = new BufferedInputStream(request.getInputStream()); return this.certificateService.addCertificate(institutionId, certificateFileType, alias, inputStream) - .map(certData -> this.userActivityLogDAO.log(UserLogActivityType.IMPORT, certData)) - .flatMap(certData -> this.certificateService.getCertificates(institutionId)) + .flatMap(certData -> this.userActivityLogDAO.log(UserLogActivityType.IMPORT, certData)) .getOrThrow(); } catch (final Exception e) { @@ -226,21 +224,20 @@ public class CertificateController { } @RequestMapping( + path = API.CERTIFICATE_ALIAS_VAR_PATH_SEGMENT, method = RequestMethod.DELETE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public Certificates deleteCertificate( + public void deleteCertificate( @RequestParam( name = API.PARAM_INSTITUTION_ID, required = true, defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId, - @RequestHeader( - name = API.CERTIFICATE_ALIAS, - required = true) final String alias) { + @PathVariable final String alias) { this.checkWritePrivilege(institutionId); - return this.certificateService.removeCertificate(institutionId, alias) + this.certificateService.removeCertificate(institutionId, alias) .getOrThrow(); } @@ -258,15 +255,15 @@ public class CertificateController { institutionId); } - private static Function, List> pageSort(final String sort) { + private static Function, List> pageSort(final String sort) { return certificates -> { - final List list = certificates.stream().collect(Collectors.toList()); + final List list = certificates.stream().collect(Collectors.toList()); if (StringUtils.isBlank(sort)) { return list; } final String sortBy = PageSortOrder.decode(sort); - if (sortBy.equals(CertificateData.FILTER_ATTR_ALIAS)) { + if (sortBy.equals(CertificateInfo.FILTER_ATTR_ALIAS)) { list.sort(Comparator.comparing(cert -> cert.alias)); } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index a6c46b4a..466b9b94 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -1533,6 +1533,21 @@ sebserver.configtemplate.attr.action.setdefault=Set Default Values sebserver.configtemplate.attr.action.template=View Configuration Template +sebserver.certificate.action.list=Certificates +sebserver.certificate.action.import=Import Certificate +sebserver.certificate.action.remove=Remove Selected Certificates + +sebserver.certificate.list.title=Certificates +sebserver.certificate.list.column.alias=Alias +sebserver.certificate.list.column.validFrom=Valid From +sebserver.certificate.list.column.validTo=Valid To +sebserver.certificate.list.column.type=Types +sebserver.certificate.list.column.type.UNKNOWN=Unknown +sebserver.certificate.list.column.type.DIGITAL_SIGNATURE=TLS/SSL +sebserver.certificate.list.column.type.DATA_ENCIPHERMENT=Identity +sebserver.certificate.list.column.type.KEY_CERT_SIGN=CA + + ################################ # Monitoring ################################