diff --git a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties index 935618296..f5b6a392a 100644 --- a/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties +++ b/hawkbit-autoconfigure/src/main/resources/hawkbitdefaults.properties @@ -7,6 +7,7 @@ # http://www.eclipse.org/legal/epl-v10.html # + # Displayed basic auth realm security.basic.realm=HawkBit @@ -82,3 +83,45 @@ hawkbit.artifact.url.protocols.md5sum-http.port=${hawkbit.artifact.url.protocols hawkbit.artifact.url.protocols.md5sum-http.supports=DDI hawkbit.artifact.url.protocols.md5sum-http.ref=${hawkbit.artifact.url.protocols.download-http.ref}.MD5SUM +# DDI and download security +hawkbit.server.ddi.security.authentication.header.enabled=false +hawkbit.server.ddi.security.authentication.header.authority= +hawkbit.server.ddi.security.authentication.targettoken.enabled=false +hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false +hawkbit.server.download.anonymous.enabled=false +hawkbit.server.ddi.security.authentication.gatewaytoken.key= + +# Default tenant configuration properties +hawkbit.server.tenant.configuration.authentication-header-enabled.keyName=authentication.header.enabled +hawkbit.server.tenant.configuration.authentication-header-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.header.enabled} +hawkbit.server.tenant.configuration.authentication-header-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-header-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-header-authority.keyName=authentication.header.authority +hawkbit.server.tenant.configuration.authentication-header-authority.defaultValue=${hawkbit.server.ddi.security.authentication.header.authority} + +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.keyName=authentication.targettoken.enabled +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.targettoken.enabled} +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.keyName=authentication.gatewaytoken.enabled +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.gatewaytoken.enabled} +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-gatewaytoken-key.keyName=authentication.gatewaytoken.key +hawkbit.server.tenant.configuration.authentication-gatewaytoken-key.defaultValue=${hawkbit.server.ddi.security.authentication.gatewaytoken.key} + +hawkbit.server.tenant.configuration.polling-time.keyName=pollingTime +hawkbit.server.tenant.configuration.polling-time.defaultValue=${hawkbit.controller.pollingTime} +hawkbit.server.tenant.configuration.polling-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.polling-overdue-time.keyName=pollingOverdueTime +hawkbit.server.tenant.configuration.polling-overdue-time.defaultValue=${hawkbit.controller.pollingOverdueTime} +hawkbit.server.tenant.configuration.polling-overdue-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.anonymous-download-enabled.keyName=anonymous.download.enabled +hawkbit.server.tenant.configuration.anonymous-download-enabled.defaultValue=${hawkbit.server.download.anonymous.enabled} +hawkbit.server.tenant.configuration.anonymous-download-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.anonymous-download-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java index 472b2bfdd..b5bbdd616 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/ControllerPollProperties.java @@ -10,9 +10,7 @@ package org.eclipse.hawkbit; import java.io.Serializable; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.EnvironmentAware; /** * Defines global configuration for the controllers/clients on the provisioning @@ -20,8 +18,7 @@ import org.springframework.context.EnvironmentAware; * * * Note: many of the controller related properties can be overridden on tenant - * level. As a result they are not defined here but in - * {@link TenantConfigurationKey} and injected using {@link EnvironmentAware}. + * level. * */ @ConfigurationProperties(prefix = "hawkbit.controller") @@ -29,8 +26,8 @@ public class ControllerPollProperties implements Serializable { private static final long serialVersionUID = 1L; /** - * Maximum polling time that can be configured by a tenant in HH:MM:SS - * notation. + * Maximum polling time that can be configured system wide and by tenant in + * HH:MM:SS notation. */ private String maxPollingTime = "23:59:59"; @@ -40,6 +37,34 @@ public class ControllerPollProperties implements Serializable { */ private String minPollingTime = "00:00:30"; + /** + * Controller polling time that can be configured system wide and by tenant + * in HH:MM:SS notation. + */ + private String pollingTime = "00:05:00"; + + /** + * Controller polling overdue time that can be configured system wide and by + * tenant in HH:MM:SS notation. + */ + private String pollingOverdueTime = "00:05:00"; + + public String getPollingTime() { + return pollingTime; + } + + public void setPollingTime(final String pollingTime) { + this.pollingTime = pollingTime; + } + + public String getPollingOverdueTime() { + return pollingOverdueTime; + } + + public void setPollingOverdueTime(final String pollingOverdueTime) { + this.pollingOverdueTime = pollingOverdueTime; + } + public String getMaxPollingTime() { return maxPollingTime; } diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/HawkbitServerProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/HawkbitServerProperties.java index 878965102..ac2f6c506 100644 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/HawkbitServerProperties.java +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/HawkbitServerProperties.java @@ -22,12 +22,52 @@ public class HawkbitServerProperties { */ private String url = "http://localhost:8080"; + private final Anonymous anonymous = new Anonymous(); + private final Build build = new Build(); + public Anonymous getAnonymous() { + return anonymous; + } + public Build getBuild() { return build; } + /** + * Properties for anonymous API access by Devices/Controllers. + * + */ + public static class Anonymous { + private final Download download = new Download(); + + public Download getDownload() { + return download; + } + + /** + * Properties for artifact download under anonymous API access by + * Devices/Controllers. + * + */ + public static class Download { + + /** + * Unauthenticated artifact download possible if true. + */ + private boolean enabled; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + } + } + /** * Build information of the hawkBit instance. Influenced by maven. * diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java deleted file mode 100644 index d5995da59..000000000 --- a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationKey.java +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2015 Bosch Software Innovations GmbH and others. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - */ -package org.eclipse.hawkbit.tenancy.configuration; - -import java.util.Arrays; -import java.util.Optional; - -import org.eclipse.hawkbit.ControllerPollProperties; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationStringValidator; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidator; -import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; -import org.springframework.context.ApplicationContext; - -/** - * An enum which defines the tenant specific configurations which can be - * configured for each tenant separately. The non overridable properties are - * configured in {@link ControllerPollProperties} instead. - * - */ -public enum TenantConfigurationKey { - - /** - * boolean value {@code true} {@code false}. - */ - AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled", "hawkbit.server.ddi.security.authentication.header.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), - /** - * - */ - AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME("authentication.header.authority", "hawkbit.server.ddi.security.authentication.header.authority", String.class, Boolean.FALSE.toString(), TenantConfigurationStringValidator.class), - /** - * boolean value {@code true} {@code false}. - */ - AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED("authentication.targettoken.enabled", "hawkbit.server.ddi.security.authentication.targettoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), - - /** - * boolean value {@code true} {@code false}. - */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED("authentication.gatewaytoken.enabled", "hawkbit.server.ddi.security.authentication.gatewaytoken.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class), - /** - * string value which holds the name of the security token key. - */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME("authentication.gatewaytoken.name", "hawkbit.server.ddi.security.authentication.gatewaytoken.name", String.class, null, TenantConfigurationStringValidator.class), - - /** - * string value which holds the actual security-key of the gateway security - * token. - */ - AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY("authentication.gatewaytoken.key", "hawkbit.server.ddi.security.authentication.gatewaytoken.key", String.class, null, TenantConfigurationStringValidator.class), - - /** - * string value which holds the polling time interval in the format HH:mm:ss - */ - POLLING_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, TenantConfigurationPollingDurationValidator.class), - - /** - * string value which holds the polling time interval in the format HH:mm:ss - */ - POLLING_OVERDUE_TIME_INTERVAL("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, TenantConfigurationPollingDurationValidator.class), - - /** - * boolean value {@code true} {@code false}. - */ - ANONYMOUS_DOWNLOAD_MODE_ENABLED("anonymous.download.enabled", "hawkbit.server.download.anonymous.enabled", Boolean.class, Boolean.FALSE.toString(), TenantConfigurationBooleanValidator.class); - - private final String keyName; - private final String defaultKeyName; - private final Class dataType; - private final String defaultValue; - private final Class validator; - - /** - * - * @param key - * the property key name - * @param defaultKeyName - * the allowed values for this specific key - * @param dataType - * the class of the property - * @param defaultValue - * value which should be returned, in case there is no value in - * the database - * @param validator - * Validator which validates, that property is of correct format - */ - TenantConfigurationKey(final String key, final String defaultKeyName, final Class dataType, - final String defaultValue, final Class validator) { - this.keyName = key; - this.dataType = dataType; - this.defaultKeyName = defaultKeyName; - this.defaultValue = defaultValue; - this.validator = validator; - } - - /** - * @return the keyName - */ - public String getKeyName() { - return keyName; - } - - /** - * @return the defaultKeyName - */ - public String getDefaultKeyName() { - return defaultKeyName; - } - - /** - * @return the defaultValue - */ - public String getDefaultValue() { - return defaultValue; - } - - /** - * - * @return the data type of the tenant configuration value. (e.g. - * Integer.class, String.class) - */ - @SuppressWarnings("unchecked") - public Class getDataType() { - return (Class) dataType; - } - - /** - * validates if a object matches the allowed data format of the - * corresponding key - * - * @param context - * application context - * @param value - * which will be validated - * @throws TenantConfigurationValidatorException - * is thrown, when object is invalid - */ - public void validate(final ApplicationContext context, final Object value) { - final TenantConfigurationValidator createdBean = context.getAutowireCapableBeanFactory().createBean(validator); - try { - createdBean.validate(value); - } finally { - context.getAutowireCapableBeanFactory().destroyBean(createdBean); - } - } - - /** - * @param keyName - * name of the TenantConfigurationKey - * @return the TenantConfigurationKey with the name keyName - */ - public static TenantConfigurationKey fromKeyName(final String keyName) { - - final Optional optKey = Arrays.stream(TenantConfigurationKey.values()) - .filter(conf -> conf.getKeyName().equals(keyName)).findFirst(); - - if (optKey.isPresent()) { - return optKey.get(); - } - throw new InvalidTenantConfigurationKeyException("The given configuration key name does not exist."); - } -} diff --git a/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java new file mode 100644 index 000000000..8a23e2b2d --- /dev/null +++ b/hawkbit-core/src/main/java/org/eclipse/hawkbit/tenancy/configuration/TenantConfigurationProperties.java @@ -0,0 +1,169 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.tenancy.configuration; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.hawkbit.ControllerPollProperties; +import org.eclipse.hawkbit.HawkbitServerProperties.Anonymous.Download; +import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationStringValidator; +import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidator; +import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.ApplicationContext; + +/** + * Properties for tenant configuration default values. + * + */ +@ConfigurationProperties("hawkbit.server.tenant") +public class TenantConfigurationProperties { + + private final Map configuration = new HashMap<>(); + + /** + * @return full map of all configured tenant properties + */ + public Map getConfiguration() { + return configuration; + } + + /** + * @return full list of {@link TenantConfigurationKey}s + */ + public Collection getConfigurationKeys() { + return configuration.values(); + } + + /** + * @param keyName + * name of the TenantConfigurationKey + * @return the TenantConfigurationKey with the name keyName + */ + public TenantConfigurationKey fromKeyName(final String keyName) { + return configuration.values().stream().filter(conf -> conf.getKeyName().equals(keyName)).findFirst() + .orElseThrow(() -> new InvalidTenantConfigurationKeyException( + "The given configuration key " + keyName + " does not exist.")); + } + + /** + * Tenant specific configurations which can be configured for each tenant + * separately by means of override of the system defaults. + * + */ + public static class TenantConfigurationKey { + /** + * Header based authentication enabled. + */ + public static final String AUTHENTICATION_MODE_HEADER_ENABLED = "authentication.header.enabled"; + + /** + * Header based authentication authority name. + */ + public static final String AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME = "authentication.header.authority"; + /** + * Target token based authentication enabled. + */ + public static final String AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED = "authentication.targettoken.enabled"; + + /** + * Gateway token based authentication enabled. + */ + public static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED = "authentication.gatewaytoken.enabled"; + + /** + * Gateway token value. + */ + public static final String AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY = "authentication.gatewaytoken.key"; + + /** + * See system default in + * {@link ControllerPollProperties#getPollingTime()}. + */ + public static final String POLLING_TIME_INTERVAL = "pollingTime"; + + /** + * See system default in + * {@link ControllerPollProperties#getPollingOverdueTime()}. + */ + public static final String POLLING_OVERDUE_TIME_INTERVAL = "pollingOverdueTime"; + + /** + * See system default {@link Download#isEnabled()}. + */ + public static final String ANONYMOUS_DOWNLOAD_MODE_ENABLED = "anonymous.download.enabled"; + + private String keyName; + private String defaultValue = ""; + private Class dataType = String.class; + private Class validator = TenantConfigurationStringValidator.class; + + public String getKeyName() { + return keyName; + } + + public void setKeyName(final String keyName) { + this.keyName = keyName; + } + + /** + * + * @return the data type of the tenant configuration value. (e.g. + * Integer.class, String.class) + */ + @SuppressWarnings("unchecked") + public Class getDataType() { + return (Class) dataType; + } + + public void setDataType(final Class dataType) { + this.dataType = dataType; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(final String defaultValue) { + this.defaultValue = defaultValue; + } + + public Class getValidator() { + return validator; + } + + public void setValidator(final Class validator) { + this.validator = validator; + } + + /** + * validates if a object matches the allowed data format of the + * corresponding key + * + * @param context + * application context + * @param value + * which will be validated + * @throws TenantConfigurationValidatorException + * is thrown, when object is invalid + */ + public void validate(final ApplicationContext context, final Object value) { + final TenantConfigurationValidator createdBean = context.getAutowireCapableBeanFactory() + .createBean(validator); + try { + createdBean.validate(value); + } finally { + context.getAutowireCapableBeanFactory().destroyBean(createdBean); + } + } + + } +} diff --git a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java index c9ffe730e..26bb256c4 100644 --- a/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java +++ b/hawkbit-ddi-resource/src/test/java/org/eclipse/hawkbit/ddi/rest/resource/DdiRootControllerTest.java @@ -26,6 +26,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import org.eclipse.hawkbit.im.authentication.SpPermission; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.DistributionSetCreatedEvent; @@ -43,7 +44,7 @@ import org.eclipse.hawkbit.repository.test.util.WithUser; import org.eclipse.hawkbit.rest.util.JsonBuilder; import org.eclipse.hawkbit.rest.util.MockMvcResultPrinter; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.util.IpUtil; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -68,7 +69,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = { CONTROLLER_ROLE, SYSTEM_ROLE }, autoCreateTenant = false) @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetDeletedEvent.class, count = 1) }) + @Expect(type = TargetDeletedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) }) public void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception { mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print()) @@ -92,7 +93,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @WithUser(principal = "knownPrincipal", authorities = { SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET, SpPermission.CREATE_TARGET }, allSpPermissions = false) @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 1) }) + @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) }) public void targetPollDoesNotModifyAuditData() throws Exception { // create target first with "knownPrincipal" user and audit data final String knownTargetControllerId = "target1"; @@ -128,7 +129,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test @Description("Ensures that the system creates a new target in plug and play manner, i.e. target is authenticated but does not exist yet.") - @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) }) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 1) }) public void rootRsPlugAndPlay() throws Exception { final long current = System.currentTimeMillis(); @@ -155,7 +157,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test @Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.") @WithUser(principal = "knownpricipal", allSpPermissions = false) - @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) }) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 1) }) public void pollWithModifiedGloablPollingTime() throws Exception { securityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> { tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL, @@ -174,6 +177,13 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test @Description("Ensures that etag check results in not modified response if provided etag by client is identical to entity in repository.") + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 7), + @Expect(type = TargetAssignDistributionSetEvent.class, count = 2), + @Expect(type = TargetUpdatedEvent.class, count = 3), @Expect(type = ActionUpdatedEvent.class, count = 1), + @Expect(type = DistributionSetCreatedEvent.class, count = 2), + @Expect(type = ActionCreatedEvent.class, count = 2), + @Expect(type = SoftwareModuleCreatedEvent.class, count = 6) }) public void rootRsNotModified() throws Exception { final String etag = mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant())) .andDo(MockMvcResultPrinter.print()).andExpect(status().isOk()) @@ -239,7 +249,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Description("Ensures that the target state machine of a precomissioned target switches from " + "UNKNOWN to REGISTERED when the target polls for the first time.") @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 1) }) + @Expect(type = TargetUpdatedEvent.class, count = 1), @Expect(type = TargetPollEvent.class, count = 1) }) public void rootRsPrecommissioned() throws Exception { final Target target = testdataFactory.createTarget("4711"); @@ -263,7 +273,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test @Description("Ensures that the source IP address of the polling target is correctly stored in repository") - @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) }) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 1) }) public void rootRsPlugAndPlayIpAddress() throws Exception { // test final String knownControllerId1 = "0815"; @@ -278,7 +289,8 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Test @Description("Ensures that the source IP address of the polling target is not stored in repository if disabled") - @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1) }) + @ExpectEvents({ @Expect(type = TargetCreatedEvent.class, count = 1), + @Expect(type = TargetPollEvent.class, count = 1) }) public void rootRsIpAddressNotStoredIfDisabled() throws Exception { securityProperties.getClients().setTrackRemoteIp(false); @@ -300,7 +312,7 @@ public class DdiRootControllerTest extends AbstractDDiApiIntegrationTest { @Expect(type = DistributionSetCreatedEvent.class, count = 1), @Expect(type = TargetAssignDistributionSetEvent.class, count = 1), @Expect(type = ActionCreatedEvent.class, count = 1), @Expect(type = ActionUpdatedEvent.class, count = 1), - @Expect(type = TargetUpdatedEvent.class, count = 2), + @Expect(type = TargetUpdatedEvent.class, count = 2), @Expect(type = TargetPollEvent.class, count = 3), @Expect(type = SoftwareModuleCreatedEvent.class, count = 3) }) public void tryToFinishAnUpdateProcessAfterItHasBeenFinished() throws Exception { final DistributionSet ds = testdataFactory.createDistributionSet(""); diff --git a/hawkbit-ddi-resource/src/test/resources/application-test.properties b/hawkbit-ddi-resource/src/test/resources/application-test.properties index f4d7832c4..a1f984dfb 100644 --- a/hawkbit-ddi-resource/src/test/resources/application-test.properties +++ b/hawkbit-ddi-resource/src/test/resources/application-test.properties @@ -37,6 +37,15 @@ flyway.sqlMigrationSuffix=${spring.jpa.database}.sql hawkbit.controller.pollingTime=00:01:00 hawkbit.controller.pollingOverdueTime=00:01:00 +hawkbit.server.tenant.configuration.polling-time.keyName=pollingTime +hawkbit.server.tenant.configuration.polling-time.defaultValue=${hawkbit.controller.pollingTime} +hawkbit.server.tenant.configuration.polling-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.polling-overdue-time.keyName=pollingOverdueTime +hawkbit.server.tenant.configuration.polling-overdue-time.defaultValue=${hawkbit.controller.pollingOverdueTime} +hawkbit.server.tenant.configuration.polling-overdue-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + + hawkbit.artifact.url.protocols[0].rel=download hawkbit.artifact.url.protocols[0].protocol=http hawkbit.artifact.url.protocols[0].supports=DMF,DDI diff --git a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java index 1997f9928..6a22fa0ab 100644 --- a/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java +++ b/hawkbit-dmf-amqp/src/main/java/org/eclipse/hawkbit/amqp/AmqpMessageDispatcherService.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.stream.Collectors; import org.eclipse.hawkbit.api.ApiType; +import org.eclipse.hawkbit.api.ArtifactUrl; import org.eclipse.hawkbit.api.ArtifactUrlHandler; import org.eclipse.hawkbit.api.URLPlaceholder; import org.eclipse.hawkbit.api.URLPlaceholder.SoftwareData; @@ -216,7 +217,7 @@ public class AmqpMessageDispatcherService extends BaseAmqpService { new SoftwareData(localArtifact.getSoftwareModule().getId(), localArtifact.getFilename(), localArtifact.getId(), localArtifact.getSha1Hash())), ApiType.DMF) - .stream().collect(Collectors.toMap(e -> e.getProtocol(), e -> e.getRef()))); + .stream().collect(Collectors.toMap(ArtifactUrl::getProtocol, ArtifactUrl::getRef))); artifact.setFilename(localArtifact.getFilename()); artifact.setHashes(new ArtifactHash(localArtifact.getSha1Hash(), localArtifact.getMd5Hash())); diff --git a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java index 64ca8590a..d6fb164f9 100644 --- a/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java +++ b/hawkbit-dmf-amqp/src/test/java/org/eclipse/hawkbit/amqp/AmqpControllerAuthenticationTest.java @@ -44,7 +44,7 @@ import org.eclipse.hawkbit.security.DdiSecurityProperties.Authentication.Anonymo import org.eclipse.hawkbit.security.DdiSecurityProperties.Rp; import org.eclipse.hawkbit.security.SecurityContextTenantAware; import org.eclipse.hawkbit.security.SystemSecurityContext; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java index d0c8dfcc5..b85baee6d 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemMapper.java @@ -11,13 +11,14 @@ package org.eclipse.hawkbit.mgmt.rest.resource; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; -import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationValue; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; /** * A mapper which maps repository model to RESTful model representation and @@ -32,19 +33,17 @@ public final class MgmtSystemMapper { /** * @param tenantConfigurationManagement * instance of TenantConfigurationManagement + * @param tenantConfigurationProperties + * to get defined keys * @return a map of all existing configuration values */ public static Map toResponse( - final TenantConfigurationManagement tenantConfigurationManagement) { + final TenantConfigurationManagement tenantConfigurationManagement, + final TenantConfigurationProperties tenantConfigurationProperties) { - final Map configurationMap = new HashMap<>(); - - for (final TenantConfigurationKey key : TenantConfigurationKey.values()) { - configurationMap.put(key.getKeyName(), - toResponse(key.getKeyName(), tenantConfigurationManagement.getConfigurationValue(key))); - } - - return configurationMap; + return tenantConfigurationProperties.getConfigurationKeys().stream() + .collect(Collectors.toMap(TenantConfigurationKey::getKeyName, key -> toResponse(key.getKeyName(), + tenantConfigurationManagement.getConfigurationValue(key.getKeyName())))); } /** diff --git a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java index 8678edd2a..f77d4582e 100644 --- a/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java +++ b/hawkbit-mgmt-resource/src/main/java/org/eclipse/hawkbit/mgmt/rest/resource/MgmtSystemResource.java @@ -19,7 +19,7 @@ import org.eclipse.hawkbit.mgmt.json.model.system.MgmtSystemTenantConfigurationV import org.eclipse.hawkbit.mgmt.rest.api.MgmtSystemRestApi; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -38,8 +38,15 @@ public class MgmtSystemResource implements MgmtSystemRestApi { private static final Logger LOG = LoggerFactory.getLogger(MgmtSystemResource.class); + private final TenantConfigurationManagement tenantConfigurationManagement; + private final TenantConfigurationProperties tenantConfigurationProperties; + @Autowired - private TenantConfigurationManagement tenantConfigurationManagement; + MgmtSystemResource(final TenantConfigurationManagement tenantConfigurationManagement, + final TenantConfigurationProperties tenantConfigurationProperties) { + this.tenantConfigurationManagement = tenantConfigurationManagement; + this.tenantConfigurationProperties = tenantConfigurationProperties; + } @Override public ResponseEntity getSystem() { @@ -53,7 +60,9 @@ public class MgmtSystemResource implements MgmtSystemRestApi { */ @Override public ResponseEntity> getSystemConfiguration() { - return new ResponseEntity<>(MgmtSystemMapper.toResponse(tenantConfigurationManagement), HttpStatus.OK); + return new ResponseEntity<>( + MgmtSystemMapper.toResponse(tenantConfigurationManagement, tenantConfigurationProperties), + HttpStatus.OK); } /** @@ -69,9 +78,7 @@ public class MgmtSystemResource implements MgmtSystemRestApi { @Override public ResponseEntity deleteConfigurationValue(@PathVariable("keyName") final String keyName) { - final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); - - tenantConfigurationManagement.deleteConfiguration(configKey); + tenantConfigurationManagement.deleteConfiguration(keyName); LOG.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK); return new ResponseEntity<>(HttpStatus.NO_CONTENT); @@ -91,11 +98,10 @@ public class MgmtSystemResource implements MgmtSystemRestApi { public ResponseEntity getConfigurationValue( @PathVariable("keyName") final String keyName) { - final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); - LOG.debug("{} config value getted, return status {}", keyName, HttpStatus.OK); - return new ResponseEntity<>(MgmtSystemMapper.toResponse(configKey.getKeyName(), - tenantConfigurationManagement.getConfigurationValue(configKey)), HttpStatus.OK); + return new ResponseEntity<>( + MgmtSystemMapper.toResponse(keyName, tenantConfigurationManagement.getConfigurationValue(keyName)), + HttpStatus.OK); } /** @@ -115,10 +121,8 @@ public class MgmtSystemResource implements MgmtSystemRestApi { @PathVariable("keyName") final String keyName, @RequestBody final MgmtSystemTenantConfigurationValueRequest configurationValueRest) { - final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName); - final TenantConfigurationValue updatedValue = tenantConfigurationManagement - .addOrUpdateConfiguration(configKey, configurationValueRest.getValue()); + .addOrUpdateConfiguration(keyName, configurationValueRest.getValue()); return new ResponseEntity<>(MgmtSystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK); } diff --git a/hawkbit-mgmt-resource/src/test/resources/application-test.properties b/hawkbit-mgmt-resource/src/test/resources/application-test.properties index c03a084d7..a091717bd 100644 --- a/hawkbit-mgmt-resource/src/test/resources/application-test.properties +++ b/hawkbit-mgmt-resource/src/test/resources/application-test.properties @@ -50,4 +50,12 @@ MYSQL.spring.datasource.password= # SP Controller configuration hawkbit.controller.pollingTime=00:01:00 -hawkbit.controller.pollingOverdueTime=00:01:00 \ No newline at end of file +hawkbit.controller.pollingOverdueTime=00:01:00 + +hawkbit.server.tenant.configuration.polling-time.keyName=pollingTime +hawkbit.server.tenant.configuration.polling-time.defaultValue=${hawkbit.controller.pollingTime} +hawkbit.server.tenant.configuration.polling-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.polling-overdue-time.keyName=pollingOverdueTime +hawkbit.server.tenant.configuration.polling-overdue-time.defaultValue=${hawkbit.controller.pollingOverdueTime} +hawkbit.server.tenant.configuration.polling-overdue-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java index 9136e43d0..752164b45 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/ControllerManagement.java @@ -29,7 +29,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.hibernate.validator.constraints.NotEmpty; import org.springframework.security.access.prepost.PreAuthorize; diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java index 84092a7d4..6befca853 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TargetManagement.java @@ -643,5 +643,4 @@ public interface TargetManagement { @PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR + SpringEvalExpressions.IS_CONTROLLER) Target updateTarget(TargetUpdate update); - } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java index 6b57d277b..7dc73d971 100644 --- a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/TenantConfigurationManagement.java @@ -13,7 +13,7 @@ import java.io.Serializable; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.repository.model.TenantConfiguration; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; import org.springframework.core.convert.ConversionFailedException; import org.springframework.core.env.Environment; @@ -29,7 +29,7 @@ public interface TenantConfigurationManagement { * Adds or updates a specific configuration for a specific tenant. * * - * @param configurationKey + * @param configurationKeyName * the key of the configuration * @param value * the configuration value which will be written into the @@ -42,8 +42,7 @@ public interface TenantConfigurationManagement { * if the property cannot be converted to the given */ @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - TenantConfigurationValue addOrUpdateConfiguration( - TenantConfigurationKey configurationKey, T value); + TenantConfigurationValue addOrUpdateConfiguration(String configurationKeyName, T value); /** * Build the tenant configuration by the given key @@ -69,14 +68,14 @@ public interface TenantConfigurationManagement { * the configuration key to be deleted */ @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - void deleteConfiguration(TenantConfigurationKey configurationKey); + void deleteConfiguration(String configurationKey); /** * Retrieves a configuration value from the e.g. tenant overwritten * configuration values or in case the tenant does not a have a specific * configuration the global default value hold in the {@link Environment}. * - * @param configurationKey + * @param configurationKeyName * the key of the configuration * @return the converted configuration value either from the tenant specific * configuration stored or from the fall back default values or @@ -90,7 +89,7 @@ public interface TenantConfigurationManagement { * {@code propertyType} */ @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - TenantConfigurationValue getConfigurationValue(TenantConfigurationKey configurationKey); + TenantConfigurationValue getConfigurationValue(String configurationKeyName); /** * Retrieves a configuration value from the e.g. tenant overwritten @@ -99,7 +98,7 @@ public interface TenantConfigurationManagement { * * @param * the type of the configuration value - * @param configurationKey + * @param configurationKeyName * the key of the configuration * @param propertyType * the type of the configuration value, e.g. {@code String.class} @@ -116,7 +115,7 @@ public interface TenantConfigurationManagement { * {@code propertyType} */ @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - TenantConfigurationValue getConfigurationValue(TenantConfigurationKey configurationKey, + TenantConfigurationValue getConfigurationValue(String configurationKeyName, Class propertyType); /** @@ -125,7 +124,7 @@ public interface TenantConfigurationManagement { * * @param * the type of the configuration value - * @param configurationKey + * @param configurationKeyName * the key of the configuration * @param propertyType * the type of the configuration value, e.g. {@code String.class} @@ -140,5 +139,5 @@ public interface TenantConfigurationManagement { * {@code propertyType} */ @PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION) - T getGlobalConfigurationValue(TenantConfigurationKey configurationKey, Class propertyType); + T getGlobalConfigurationValue(String configurationKeyName, Class propertyType); } diff --git a/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TargetPollEvent.java b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TargetPollEvent.java new file mode 100644 index 000000000..99f7daf93 --- /dev/null +++ b/hawkbit-repository/hawkbit-repository-api/src/main/java/org/eclipse/hawkbit/repository/event/remote/TargetPollEvent.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015 Bosch Software Innovations GmbH and others. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package org.eclipse.hawkbit.repository.event.remote; + +import org.eclipse.hawkbit.repository.model.Target; + +/** + * Event is send in case a target polls either through DDI or DMF. + */ +public class TargetPollEvent extends RemoteTenantAwareEvent { + + private static final long serialVersionUID = 1L; + private String controllerId; + private String targetAdress; + + /** + * Default constructor. + */ + public TargetPollEvent() { + // for serialization libs like jackson + } + + public TargetPollEvent(final Target target, final String applicationId) { + super(target.getControllerId(), target.getTenant(), applicationId); + this.controllerId = target.getControllerId(); + this.targetAdress = target.getTargetInfo().getAddress().toString(); + } + + public String getControllerId() { + return controllerId; + } + + public String getTargetAdress() { + return targetAdress; + } +} diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java index f18a4122f..13342020b 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/event/EventType.java @@ -18,6 +18,7 @@ import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent; import org.eclipse.hawkbit.repository.event.remote.SoftwareModuleDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.TargetAssignDistributionSetEvent; import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent; +import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; import org.eclipse.hawkbit.repository.event.remote.TargetTagDeletedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionCreatedEvent; import org.eclipse.hawkbit.repository.event.remote.entity.ActionUpdatedEvent; @@ -90,10 +91,12 @@ public class EventType { // download TYPES.put(20, DownloadProgressEvent.class); - + TYPES.put(21, SoftwareModuleCreatedEvent.class); TYPES.put(22, SoftwareModuleDeletedEvent.class); TYPES.put(23, SoftwareModuleUpdatedEvent.class); + + TYPES.put(24, TargetPollEvent.class); } private int value; diff --git a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/TimestampCalculator.java b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/TimestampCalculator.java index ea51c0c5e..2614b117a 100644 --- a/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/TimestampCalculator.java +++ b/hawkbit-repository/hawkbit-repository-core/src/main/java/org/eclipse/hawkbit/repository/TimestampCalculator.java @@ -13,11 +13,11 @@ import java.time.Instant; import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; /** - * Calculates non-persistent timestamps , e.g. the point a time a - * target is declared as overdue.
+ * Calculates non-persistent timestamps , e.g. the point a time a target is + * declared as overdue.
* Therefore tenant specific configuration may be considered. * */ @@ -43,11 +43,11 @@ public final class TimestampCalculator { - getDurationForKey(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL).toMillis(); } - private static Duration getDurationForKey(TenantConfigurationKey key) { + private static Duration getDurationForKey(final String key) { return DurationHelper.formattedStringToDuration(getRawStringForKey(key)); } - private static String getRawStringForKey(TenantConfigurationKey key) { + private static String getRawStringForKey(final String key) { return getTenantConfigurationManagement().getConfigurationValue(key, String.class).getValue(); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java index 104544c7b..2ad7ef23c 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaControllerManagement.java @@ -26,6 +26,7 @@ import org.eclipse.hawkbit.repository.TargetManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.builder.ActionStatusCreate; import org.eclipse.hawkbit.repository.event.remote.DownloadProgressEvent; +import org.eclipse.hawkbit.repository.event.remote.TargetPollEvent; import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent; import org.eclipse.hawkbit.repository.exception.EntityNotFoundException; import org.eclipse.hawkbit.repository.exception.ToManyAttributeEntriesException; @@ -49,11 +50,10 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; -import org.eclipse.hawkbit.repository.model.TenantConfiguration; import org.eclipse.hawkbit.security.HawkbitSecurityProperties; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -127,14 +127,8 @@ public class JpaControllerManagement implements ControllerManagement { @Override public String getPollingTime() { - final TenantConfigurationKey configurationKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; - final Class propertyType = String.class; - JpaTenantConfigurationManagement.validateTenantConfigurationDataType(configurationKey, propertyType); - final TenantConfiguration tenantConfiguration = tenantConfigurationRepository - .findByKey(configurationKey.getKeyName()); - return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement - .buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration).getValue()); + .getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue()); } @Override @@ -203,10 +197,15 @@ public class JpaControllerManagement implements ControllerManagement { final JpaTarget target = targetRepository.findOne(spec); if (target == null) { - return targetManagement.createTarget(entityFactory.target().create().controllerId(controllerId) - .description("Plug and Play target: " + controllerId).name(controllerId) + final Target result = targetManagement.createTarget(entityFactory.target().create() + .controllerId(controllerId).description("Plug and Play target: " + controllerId).name(controllerId) .status(TargetUpdateStatus.REGISTERED).lastTargetQuery(System.currentTimeMillis()) .address(Optional.ofNullable(address).map(URI::toString).orElse(null))); + + afterCommit.afterCommit( + () -> eventPublisher.publishEvent(new TargetPollEvent(result, applicationContext.getId()))); + + return result; } return updateLastTargetQuery(target.getTargetInfo(), address).getTarget(); @@ -224,9 +223,6 @@ public class JpaControllerManagement implements ControllerManagement { if (lastTargetQuery != null) { mtargetInfo.setLastTargetQuery(lastTargetQuery); } - if (address != null) { - mtargetInfo.setAddress(address.toString()); - } if (mtargetInfo.getUpdateStatus() == TargetUpdateStatus.UNKNOWN) { mtargetInfo.setUpdateStatus(TargetUpdateStatus.REGISTERED); @@ -234,6 +230,12 @@ public class JpaControllerManagement implements ControllerManagement { .publishEvent(new TargetUpdatedEvent(mtargetInfo.getTarget(), applicationContext.getId()))); } + if (address != null) { + mtargetInfo.setAddress(address.toString()); + afterCommit.afterCommit(() -> eventPublisher + .publishEvent(new TargetPollEvent(mtargetInfo.getTarget(), applicationContext.getId()))); + } + return targetInfoRepository.save(mtargetInfo); } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java index 2b62e660c..e24bd3506 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/JpaTenantConfigurationManagement.java @@ -14,16 +14,15 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.jpa.model.JpaTenantConfiguration; import org.eclipse.hawkbit.repository.model.TenantConfiguration; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ApplicationContext; -import org.springframework.context.EnvironmentAware; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.env.Environment; import org.springframework.data.jpa.repository.Modifying; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @@ -34,22 +33,26 @@ import org.springframework.validation.annotation.Validated; */ @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) @Validated -public class JpaTenantConfigurationManagement implements EnvironmentAware, TenantConfigurationManagement { +public class JpaTenantConfigurationManagement implements TenantConfigurationManagement { @Autowired private TenantConfigurationRepository tenantConfigurationRepository; + @Autowired + private TenantConfigurationProperties tenantConfigurationProperties; + @Autowired private ApplicationContext applicationContext; private static final ConfigurableConversionService conversionService = new DefaultConversionService(); - private Environment environment; - @Override - @Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") - public TenantConfigurationValue getConfigurationValue( - final TenantConfigurationKey configurationKey, final Class propertyType) { + @Cacheable(value = "tenantConfiguration", key = "#configurationKeyName") + public TenantConfigurationValue getConfigurationValue(final String configurationKeyName, + final Class propertyType) { + + final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName); + validateTenantConfigurationDataType(configurationKey, propertyType); final TenantConfiguration tenantConfiguration = tenantConfigurationRepository @@ -69,6 +72,7 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan */ static void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey, final Class propertyType) { + if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { throw new TenantConfigurationValidatorException( String.format("Cannot parse the database value of type %s into the type %s.", @@ -87,46 +91,44 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan .lastModifiedBy(tenantConfiguration.getLastModifiedBy()) .value(conversionService.convert(tenantConfiguration.getValue(), propertyType)).build(); - } else if (configurationKey.getDefaultKeyName() != null) { + } else if (configurationKey.getDefaultValue() != null) { return TenantConfigurationValue. builder().global(true).createdBy(null).createdAt(null) .lastModifiedAt(null).lastModifiedBy(null) - .value(getGlobalConfigurationValue(configurationKey, propertyType)).build(); + .value(getGlobalConfigurationValue(configurationKey.getKeyName(), propertyType)).build(); } return null; } @Override public TenantConfigurationValue getConfigurationValue( - final TenantConfigurationKey configurationKey) { - return getConfigurationValue(configurationKey, configurationKey.getDataType()); + final String configurationKeyName) { + final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName); + + return getConfigurationValue(configurationKeyName, configurationKey.getDataType()); } @Override - public T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey, - final Class propertyType) { + public T getGlobalConfigurationValue(final String configurationKeyName, final Class propertyType) { - if (!configurationKey.getDataType().isAssignableFrom(propertyType)) { - throw new TenantConfigurationValidatorException( - String.format("Cannot parse the database value of type %s into the type %s.", - configurationKey.getDataType(), propertyType)); + final TenantConfigurationKey key = tenantConfigurationProperties.fromKeyName(configurationKeyName); + + if (!key.getDataType().isAssignableFrom(propertyType)) { + throw new TenantConfigurationValidatorException(String.format( + "Cannot parse the database value of type %s into the type %s.", key.getDataType(), propertyType)); } - final T valueInProperties = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType); - - if (valueInProperties == null) { - return conversionService.convert(configurationKey.getDefaultValue(), propertyType); - } - - return valueInProperties; + return conversionService.convert(key.getDefaultValue(), propertyType); } @Override - @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") + @CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName") @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying public TenantConfigurationValue addOrUpdateConfiguration( - final TenantConfigurationKey configurationKey, final T value) { + final String configurationKeyName, final T value) { + + final TenantConfigurationKey configurationKey = tenantConfigurationProperties.fromKeyName(configurationKeyName); if (!configurationKey.getDataType().isAssignableFrom(value.getClass())) { throw new TenantConfigurationValidatorException(String.format( @@ -159,15 +161,10 @@ public class JpaTenantConfigurationManagement implements EnvironmentAware, Tenan } @Override - @CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()") + @CacheEvict(value = "tenantConfiguration", key = "#configurationKeyName") @Transactional(isolation = Isolation.READ_UNCOMMITTED) @Modifying - public void deleteConfiguration(final TenantConfigurationKey configurationKey) { - tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName()); - } - - @Override - public void setEnvironment(final Environment environment) { - this.environment = environment; + public void deleteConfiguration(final String configurationKeyName) { + tenantConfigurationRepository.deleteByKey(configurationKeyName); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java index 3411f08d5..869801947 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/RepositoryApplicationConfiguration.java @@ -64,6 +64,7 @@ import org.eclipse.hawkbit.repository.rsql.RsqlValidationOracle; import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration; @@ -94,7 +95,8 @@ import com.google.common.collect.Maps; @EnableAspectJAutoProxy @Configuration @ComponentScan -@EnableConfigurationProperties({ RepositoryProperties.class, ControllerPollProperties.class, RolloutProperties.class }) +@EnableConfigurationProperties({ RepositoryProperties.class, ControllerPollProperties.class, RolloutProperties.class, + TenantConfigurationProperties.class }) @EnableScheduling @EntityScan("org.eclipse.hawkbit.repository.jpa.model") public class RepositoryApplicationConfiguration extends JpaBaseConfiguration { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java index fe87b951b..e4a07b78d 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/main/java/org/eclipse/hawkbit/repository/jpa/model/JpaTargetInfo.java @@ -48,7 +48,7 @@ import org.eclipse.hawkbit.repository.model.TargetInfo; import org.eclipse.hawkbit.repository.model.TargetUpdateStatus; import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.persistence.annotations.CascadeOnDelete; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java index 686af157f..3f3f79b06 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/AbstractJpaIntegrationTest.java @@ -18,6 +18,7 @@ import org.eclipse.hawkbit.repository.jpa.model.JpaRollout; import org.eclipse.hawkbit.repository.model.Action; import org.eclipse.hawkbit.repository.model.Rollout; import org.eclipse.hawkbit.repository.test.util.AbstractIntegrationTest; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.transaction.annotation.Isolation; @@ -78,6 +79,9 @@ public abstract class AbstractJpaIntegrationTest extends AbstractIntegrationTest @Autowired protected TenantAwareCacheManager cacheManager; + @Autowired + protected TenantConfigurationProperties tenantConfigurationProperties; + @Transactional(readOnly = true, isolation = Isolation.READ_UNCOMMITTED) public List findActionsByRolloutAndStatus(final Rollout rollout, final Action.Status actionStatus) { return actionRepository.findByRolloutAndStatus((JpaRollout) rollout, actionStatus); diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java index 14f387ad1..ea79e77ca 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/TenantConfigurationManagementTest.java @@ -9,17 +9,17 @@ package org.eclipse.hawkbit.repository.jpa; import static org.fest.assertions.api.Assertions.assertThat; -import static org.junit.Assert.fail; +import static org.fest.assertions.api.Assertions.fail; import java.io.Serializable; import java.time.Duration; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.InvalidTenantConfigurationKeyException; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationValidatorException; import org.junit.Assert; import org.junit.Test; @@ -35,13 +35,13 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Tests that tenant specific configuration can be persisted and in case the tenant does not have specific configuration the default from environment is used instead.") public void storeTenantSpecificConfigurationAsString() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME; - final String envPropertyDefault = environment.getProperty(configKey.getDefaultKeyName()); + final String envPropertyDefault = environment + .getProperty("hawkbit.server.ddi.security.authentication.gatewaytoken.key"); assertThat(envPropertyDefault).isNotNull(); // get the configuration from the system management - final TenantConfigurationValue defaultConfigValue = tenantConfigurationManagement - .getConfigurationValue(configKey, String.class); + final TenantConfigurationValue defaultConfigValue = tenantConfigurationManagement.getConfigurationValue( + TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class); assertThat(defaultConfigValue.isGlobal()).isEqualTo(true); assertThat(defaultConfigValue.getValue()).isEqualTo(envPropertyDefault); @@ -49,11 +49,13 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes // update the tenant specific configuration final String newConfigurationValue = "thisIsAnotherTokenName"; assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue.getValue()); - tenantConfigurationManagement.addOrUpdateConfiguration(configKey, newConfigurationValue); + tenantConfigurationManagement.addOrUpdateConfiguration( + TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, newConfigurationValue); // verify that new configuration value is used final TenantConfigurationValue updatedConfigurationValue = tenantConfigurationManagement - .getConfigurationValue(configKey, String.class); + .getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, + String.class); assertThat(updatedConfigurationValue.isGlobal()).isEqualTo(false); assertThat(updatedConfigurationValue.getValue()).isEqualTo(newConfigurationValue); @@ -63,7 +65,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Tests that the tenant specific configuration can be updated") public void updateTenantSpecifcConfiguration() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY; final String value1 = "firstValue"; final String value2 = "secondValue"; @@ -81,7 +83,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Tests that the configuration value can be converted from String to Integer automatically") public void storeAndUpdateTenantSpecificConfigurationAsBoolean() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED; final Boolean value1 = true; tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1); assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue()) @@ -95,7 +97,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Tests that the get configuration throws exception in case the value cannot be automatically converted from String to Boolean") public void wrongTenantConfigurationValueTypeThrowsException() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED; final String value1 = "thisIsNotABoolean"; // add value as String @@ -110,13 +112,13 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Tests that a deletion of a tenant specific configuration deletes it from the database.") public void deleteConfigurationReturnNullConfiguration() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY; // gateway token does not have default value so no configuration value - // is should be available + // should be available final String defaultConfigValue = tenantConfigurationManagement.getConfigurationValue(configKey, String.class) .getValue(); - assertThat(defaultConfigValue).isNull(); + assertThat(defaultConfigValue).isEmpty(); // update the tenant specific configuration final String newConfigurationValue = "thisIsAnotherValueForPolling"; @@ -131,14 +133,14 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes // delete the tenant specific configuration tenantConfigurationManagement.deleteConfiguration(configKey); // ensure that now gateway token is set again, because is deleted and - // must be null now - assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue()).isNull(); + // must be empty now + assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue()).isEmpty(); } @Test @Description("Test that an Exception is thrown, when an integer is stored but a string expected.") public void storesIntegerWhenStringIsExpected() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY; final Integer wrongDataype = 123; try { tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype); @@ -151,7 +153,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Test that an Exception is thrown, when an integer is stored but a boolean expected.") public void storesIntegerWhenBooleanIsExpected() { - final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED; + final String configKey = TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED; final Integer wrongDataype = 123; try { tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype); @@ -164,7 +166,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Test that an Exception is thrown, when an integer is stored as PollingTime.") public void storesIntegerWhenPollingIntervalIsExpected() { - final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; final Integer wrongDataype = 123; try { tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype); @@ -177,7 +179,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Test that an Exception is thrown, when an invalid formatted string is stored as PollingTime.") public void storesWrongFormattedStringAsPollingInterval() { - final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; final String wrongFormatted = "wrongFormatted"; try { tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongFormatted); @@ -190,7 +192,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Test that an Exception is thrown, when an invalid formatted string is stored as PollingTime.") public void storesTooSmallDurationAsPollingInterval() { - final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; final String tooSmallDuration = DurationHelper .durationToFormattedString(DurationHelper.getDurationByTimeValues(0, 0, 1)); @@ -205,7 +207,7 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Stores a correct formatted PollignTime and reads it again.") public void storesCorrectDurationAsPollingInterval() { - final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; final Duration duration = DurationHelper.getDurationByTimeValues(1, 2, 0); assertThat(duration).isEqualTo(Duration.ofHours(1).plusMinutes(2)); @@ -233,9 +235,9 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Verifies that every TenenatConfiguraationKeyName exists only once") public void verifyThatAllKeysAreDifferent() { - final Map keynames = new HashMap(); + final Map keynames = new HashMap<>(); - Arrays.stream(TenantConfigurationKey.values()).forEach(key -> { + tenantConfigurationProperties.getConfigurationKeys().forEach(key -> { if (keynames.containsKey(key.getKeyName())) { throw new IllegalStateException("The key names are not unique"); @@ -248,9 +250,20 @@ public class TenantConfigurationManagementTest extends AbstractJpaIntegrationTes @Test @Description("Get TenantConfigurationKeyByName") public void getTenantConfigurationKeyByName() { - final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; + final String configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL; - assertThat(TenantConfigurationKey.fromKeyName(configKey.getKeyName())).isEqualTo(configKey); + assertThat(tenantConfigurationProperties.fromKeyName(configKey).getKeyName()).isEqualTo(configKey); } + @Test + @Description("Tenant configuration which is not declared throws exception") + public void storeTenantConfigurationWhichIsNotDeclaredThrowsException() { + final String configKeyWhichDoesNotExists = "configKeyWhichDoesNotExists"; + try { + tenantConfigurationManagement.addOrUpdateConfiguration(configKeyWhichDoesNotExists, "value"); + fail("Expected InvalidTenantConfigurationKeyException for tenant configuration key which is not declared"); + } catch (final InvalidTenantConfigurationKeyException e) { + // expected exception + } + } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java index 90c8d9b33..3fcc258a1 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/RSQLUtilityTest.java @@ -40,7 +40,7 @@ import org.eclipse.hawkbit.repository.model.SoftwareModule; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyReplacer; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -61,7 +61,7 @@ import ru.yandex.qatools.allure.annotations.Stories; public class RSQLUtilityTest { @Spy - private VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(); + private final VirtualPropertyResolver macroResolver = new VirtualPropertyResolver(); @Mock private TenantConfigurationManagement confMgmt; @@ -78,9 +78,9 @@ public class RSQLUtilityTest { private Attribute attribute; private static final TenantConfigurationValue TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue - .builder().value("00:05:00").build(); + . builder().value("00:05:00").build(); private static final TenantConfigurationValue TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue - .builder().value("00:07:37").build(); + . builder().value("00:07:37").build(); @Test public void wrongRsqlSyntaxThrowSyntaxException() { @@ -111,8 +111,7 @@ public class RSQLUtilityTest { String wrongRSQL = TargetFields.ATTRIBUTE + "==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } @@ -120,8 +119,7 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ATTRIBUTE + ".unkwon.wrong==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } @@ -141,8 +139,7 @@ public class RSQLUtilityTest { String wrongRSQL = TargetFields.ASSIGNEDDS + "==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } @@ -150,8 +147,7 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } @@ -159,8 +155,7 @@ public class RSQLUtilityTest { wrongRSQL = TargetFields.ASSIGNEDDS + ".unknownField.ToMuch==abc"; try { RSQLUtility.parse(wrongRSQL, TargetFields.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); fail("Missing expected RSQLParameterSyntaxException because of wrong RSQL syntax"); } catch (final RSQLParameterUnsupportedFieldException e) { } @@ -174,7 +169,7 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("version")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); // test @@ -192,7 +187,7 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); @@ -213,7 +208,7 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); when(criteriaBuilderMock.upper(eq(pathOfString(baseSoftwareModuleRootMock)))) .thenReturn(pathOfString(baseSoftwareModuleRootMock)); @@ -234,7 +229,7 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("name")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) SoftwareModule.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.greaterThanOrEqualTo(any(Expression.class), any(String.class))) + when(criteriaBuilderMock. greaterThanOrEqualTo(any(Expression.class), any(String.class))) .thenReturn(mock(Predicate.class)); // test RSQLUtility.parse(correctRsql, SoftwareModuleFields.class, null).toPredicate(baseSoftwareModuleRootMock, @@ -255,8 +250,7 @@ public class RSQLUtilityTest { // test RSQLUtility.parse(correctRsql, TestFieldEnum.class, null).toPredicate(baseSoftwareModuleRootMock, - criteriaQueryMock, - criteriaBuilderMock); + criteriaQueryMock, criteriaBuilderMock); // verfication verify(criteriaBuilderMock, times(1)).and(any(Predicate.class)); @@ -291,16 +285,17 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) + when(criteriaBuilderMock. lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) .thenReturn(mock(Predicate.class)); // test - RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) - .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); + RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()).toPredicate(baseSoftwareModuleRootMock, + criteriaQueryMock, criteriaBuilderMock); // verification verify(macroResolver).lookup(overdueProp); - // the macro is already replaced when passed to #lessThanOrEqualTo -> the method is never invoked with the + // the macro is already replaced when passed to #lessThanOrEqualTo -> + // the method is never invoked with the // placeholder: verify(criteriaBuilderMock, never()).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); @@ -316,16 +311,17 @@ public class RSQLUtilityTest { when(baseSoftwareModuleRootMock.get("testfield")).thenReturn(baseSoftwareModuleRootMock); when(baseSoftwareModuleRootMock.getJavaType()).thenReturn((Class) String.class); when(criteriaBuilderMock.equal(any(Root.class), anyString())).thenReturn(mock(Predicate.class)); - when(criteriaBuilderMock.lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) + when(criteriaBuilderMock. lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder))) .thenReturn(mock(Predicate.class)); // test - Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) + final Predicate result = RSQLUtility.parse(correctRsql, TestFieldEnum.class, setupMacroLookup()) .toPredicate(baseSoftwareModuleRootMock, criteriaQueryMock, criteriaBuilderMock); // verification verify(macroResolver).lookup(overdueProp); - // the macro is unknown and hence never replaced -> #lessThanOrEqualTo is invoked with the placeholder: + // the macro is unknown and hence never replaced -> #lessThanOrEqualTo + // is invoked with the placeholder: verify(criteriaBuilderMock).lessThanOrEqualTo(eq(pathOfString(baseSoftwareModuleRootMock)), eq(overduePropPlaceholder)); } @@ -353,7 +349,9 @@ public class RSQLUtilityTest { /* * (non-Javadoc) * - * @see org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider# getFieldName() + * @see + * org.eclipse.hawkbit.server.rest.resource.model.FieldNameProvider# + * getFieldName() */ @Override public String getFieldName() { diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java index 349b7e3ea..fdb840fcc 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/java/org/eclipse/hawkbit/repository/jpa/rsql/VirtualPropertyResolverTest.java @@ -21,7 +21,7 @@ import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.TimestampCalculator; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.repository.rsql.VirtualPropertyResolver; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,7 +41,7 @@ import ru.yandex.qatools.allure.annotations.Stories; public class VirtualPropertyResolverTest { @Spy - private VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(); + private final VirtualPropertyResolver resolverUnderTest = new VirtualPropertyResolver(); @Mock private TenantConfigurationManagement confMgmt; @@ -59,66 +59,65 @@ public class VirtualPropertyResolverTest { public void before() { nowTestTime = Instant.now().toEpochMilli(); when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class)) - .thenReturn(TEST_POLLING_TIME_INTERVAL); + .thenReturn(TEST_POLLING_TIME_INTERVAL); when(confMgmt.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)) - .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); + .thenReturn(TEST_POLLING_OVERDUE_TIME_INTERVAL); mockStatic(TimestampCalculator.class); when(TimestampCalculator.getTenantConfigurationManagement()).thenReturn(confMgmt); - substitutor = new StrSubstitutor(resolverUnderTest, - StrSubstitutor.DEFAULT_PREFIX, + substitutor = new StrSubstitutor(resolverUnderTest, StrSubstitutor.DEFAULT_PREFIX, StrSubstitutor.DEFAULT_SUFFIX, StrSubstitutor.DEFAULT_ESCAPE); - } + } @Test @Description("Tests resolution of NOW_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.") public void resolveNowTimestampPlaceholder() { - String placeholder = "${NOW_TS}"; - String testString = "lhs=lt=" + placeholder; + final String placeholder = "${NOW_TS}"; + final String testString = "lhs=lt=" + placeholder; - String resolvedPlaceholders = substitutor.replace(testString); + final String resolvedPlaceholders = substitutor.replace(testString); assertThat("NOW_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @Description("Tests resolution of OVERDUE_TS by using a StrSubstitutor configured with the VirtualPropertyResolver.") public void resolveOverdueTimestampPlaceholder() { - String placeholder = "${OVERDUE_TS}"; - String testString = "lhs=lt=" + placeholder; + final String placeholder = "${OVERDUE_TS}"; + final String testString = "lhs=lt=" + placeholder; - String resolvedPlaceholders = substitutor.replace(testString); + final String resolvedPlaceholders = substitutor.replace(testString); assertThat("OVERDUE_TS has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @Description("Tests case insensititity of VirtualPropertyResolver.") public void resolveOverdueTimestampPlaceholderLowerCase() { - String placeholder = "${overdue_ts}"; - String testString = "lhs=lt=" + placeholder; + final String placeholder = "${overdue_ts}"; + final String testString = "lhs=lt=" + placeholder; - String resolvedPlaceholders = substitutor.replace(testString); + final String resolvedPlaceholders = substitutor.replace(testString); assertThat("overdue_ts has to be resolved!", resolvedPlaceholders, not(containsString(placeholder))); } @Test @Description("Tests VirtualPropertyResolver with a placeholder unknown to VirtualPropertyResolver.") public void handleUnknownPlaceholder() { - String placeholder = "${unknown}"; - String testString = "lhs=lt=" + placeholder; + final String placeholder = "${unknown}"; + final String testString = "lhs=lt=" + placeholder; - String resolvedPlaceholders = substitutor.replace(testString); + final String resolvedPlaceholders = substitutor.replace(testString); assertThat("unknown should not be resolved!", resolvedPlaceholders, containsString(placeholder)); } @Test @Description("Tests escape mechanism for placeholders (syntax is $${SOME_PLACEHOLDER}).") public void handleEscapedPlaceholder() { - String placeholder = "${OVERDUE_TS}"; - String escaptedPlaceholder = StrSubstitutor.DEFAULT_ESCAPE + placeholder; - String testString = "lhs=lt=" + escaptedPlaceholder; + final String placeholder = "${OVERDUE_TS}"; + final String escaptedPlaceholder = StrSubstitutor.DEFAULT_ESCAPE + placeholder; + final String testString = "lhs=lt=" + escaptedPlaceholder; - String resolvedPlaceholders = substitutor.replace(testString); + final String resolvedPlaceholders = substitutor.replace(testString); assertThat("Escaped OVERDUE_TS should not be resolved!", resolvedPlaceholders, containsString(placeholder)); } } diff --git a/hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties b/hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties index 185131ffb..115f14118 100644 --- a/hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties +++ b/hawkbit-repository/hawkbit-repository-jpa/src/test/resources/application-test.properties @@ -13,9 +13,6 @@ logging.level.org.eclipse.persistence=ERROR spring.data.mongodb.uri=mongodb://localhost/spArtifactRepository${random.value} spring.data.mongodb.port=28017 -hawkbit.server.ddi.security.authentication.header.enabled=true -hawkbit.server.ddi.security.authentication.gatewaytoken.name=TestToken - multipart.max-file-size=5MB hawkbit.server.security.dos.maxStatusEntriesPerAction=100 @@ -38,4 +35,48 @@ flyway.sqlMigrationSuffix=${spring.jpa.database}.sql # DDI configuration hawkbit.controller.pollingTime=00:01:00 -hawkbit.controller.pollingOverdueTime=00:01:00 \ No newline at end of file +hawkbit.controller.pollingOverdueTime=00:01:00 + +# DDI and download security +hawkbit.server.ddi.security.authentication.header.authority= +hawkbit.server.ddi.security.authentication.targettoken.enabled=false +hawkbit.server.ddi.security.authentication.gatewaytoken.enabled=false +hawkbit.server.download.anonymous.enabled=false +hawkbit.server.ddi.security.authentication.header.enabled=true +hawkbit.server.ddi.security.authentication.gatewaytoken.name=TestToken +hawkbit.server.ddi.security.authentication.gatewaytoken.key= + +# Default tenant configuration properties +hawkbit.server.tenant.configuration.authentication-header-enabled.keyName=authentication.header.enabled +hawkbit.server.tenant.configuration.authentication-header-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.header.enabled} +hawkbit.server.tenant.configuration.authentication-header-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-header-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-header-authority.keyName=authentication.header.authority +hawkbit.server.tenant.configuration.authentication-header-authority.defaultValue=${hawkbit.server.ddi.security.authentication.header.authority} + +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.keyName=authentication.targettoken.enabled +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.targettoken.enabled} +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-targettoken-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.keyName=authentication.gatewaytoken.enabled +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.defaultValue=${hawkbit.server.ddi.security.authentication.gatewaytoken.enabled} +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.authentication-gatewaytoken-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator + +hawkbit.server.tenant.configuration.authentication-gatewaytoken-key.keyName=authentication.gatewaytoken.key +hawkbit.server.tenant.configuration.authentication-gatewaytoken-key.defaultValue=${hawkbit.server.ddi.security.authentication.gatewaytoken.key} + +hawkbit.server.tenant.configuration.polling-time.keyName=pollingTime +hawkbit.server.tenant.configuration.polling-time.defaultValue=${hawkbit.controller.pollingTime} +hawkbit.server.tenant.configuration.polling-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.polling-overdue-time.keyName=pollingOverdueTime +hawkbit.server.tenant.configuration.polling-overdue-time.defaultValue=${hawkbit.controller.pollingOverdueTime} +hawkbit.server.tenant.configuration.polling-overdue-time.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationPollingDurationValidator + +hawkbit.server.tenant.configuration.anonymous-download-enabled.keyName=anonymous.download.enabled +hawkbit.server.tenant.configuration.anonymous-download-enabled.defaultValue=${hawkbit.server.download.anonymous.enabled} +hawkbit.server.tenant.configuration.anonymous-download-enabled.dataType=java.lang.Boolean +hawkbit.server.tenant.configuration.anonymous-download-enabled.validator=org.eclipse.hawkbit.tenancy.configuration.validator.TenantConfigurationBooleanValidator diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java index 24e75a1c1..5b455152c 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/TestConfiguration.java @@ -37,6 +37,7 @@ import org.eclipse.hawkbit.security.SecurityTokenGenerator; import org.eclipse.hawkbit.security.SpringSecurityAuditorAware; import org.eclipse.hawkbit.security.SystemSecurityContext; import org.eclipse.hawkbit.tenancy.TenantAware; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -67,7 +68,7 @@ import org.springframework.util.AntPathMatcher; @EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.PROXY, proxyTargetClass = false, securedEnabled = true) @EnableConfigurationProperties({ HawkbitServerProperties.class, DdiSecurityProperties.class, ArtifactUrlHandlerProperties.class, ArtifactFilesystemProperties.class, HawkbitSecurityProperties.class, - ControllerPollProperties.class }) + ControllerPollProperties.class, TenantConfigurationProperties.class }) @Profile("test") @EnableAutoConfiguration public class TestConfiguration implements AsyncConfigurer { diff --git a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java index 5ac51ecb4..854277829 100644 --- a/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java +++ b/hawkbit-repository/hawkbit-repository-test/src/main/java/org/eclipse/hawkbit/repository/test/util/AbstractIntegrationTest.java @@ -102,7 +102,7 @@ import com.google.common.collect.Lists; // strange test failures. @DirtiesContext(classMode = ClassMode.AFTER_CLASS) public abstract class AbstractIntegrationTest implements EnvironmentAware { - private final static Logger LOG = LoggerFactory.getLogger(AbstractIntegrationTest.class); + private static final Logger LOG = LoggerFactory.getLogger(AbstractIntegrationTest.class); protected static final Pageable pageReq = new PageRequest(0, 400); diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java index 866ee16bc..376fe70b4 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/im/authentication/SpPermission.java @@ -228,11 +228,11 @@ public final class SpPermission { /* * Spring security eval expressions. */ - private static final String BRACKET_OPEN = "("; - private static final String BRACKET_CLOSE = ")"; - private static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'"; - private static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE; - private static final String HAS_AUTH_AND = " and "; + public static final String BRACKET_OPEN = "("; + public static final String BRACKET_CLOSE = ")"; + public static final String HAS_AUTH_PREFIX = "hasAuthority" + BRACKET_OPEN + "'"; + public static final String HAS_AUTH_SUFFIX = "'" + BRACKET_CLOSE; + public static final String HAS_AUTH_AND = " and "; /** * The role which contains in the spring security context in case an diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/AbstractControllerAuthenticationFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/AbstractControllerAuthenticationFilter.java index 56baf3bfc..54ccfdbba 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/AbstractControllerAuthenticationFilter.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/AbstractControllerAuthenticationFilter.java @@ -11,7 +11,6 @@ package org.eclipse.hawkbit.security; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +38,7 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe this.configurationKeyTenantRunner = new SecurityConfigurationKeyTenantRunner(); } - protected abstract TenantConfigurationKey getTenantConfigurationKey(); + protected abstract String getTenantConfigurationKey(); @Override public boolean isEnable(final TenantSecurityToken secruityToken) { diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticateSecurityTokenFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticateSecurityTokenFilter.java index b953453ea..1ef75d48d 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticateSecurityTokenFilter.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticateSecurityTokenFilter.java @@ -15,7 +15,7 @@ import org.eclipse.hawkbit.repository.ControllerManagement; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.Target; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -106,7 +106,7 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro } @Override - protected TenantConfigurationKey getTenantConfigurationKey() { + protected String getTenantConfigurationKey() { return TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED; } } diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java index b4457bfcf..e3651a508 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedAnonymousDownload.java @@ -14,7 +14,7 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -58,7 +58,7 @@ public class ControllerPreAuthenticatedAnonymousDownload extends AbstractControl } @Override - protected TenantConfigurationKey getTenantConfigurationKey() { + protected String getTenantConfigurationKey() { return TenantConfigurationKey.ANONYMOUS_DOWNLOAD_MODE_ENABLED; } diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java index 7d1bd7b0f..87da5753b 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedGatewaySecurityTokenFilter.java @@ -11,7 +11,7 @@ package org.eclipse.hawkbit.security; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +78,7 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra } @Override - protected TenantConfigurationKey getTenantConfigurationKey() { + protected String getTenantConfigurationKey() { return TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED; } diff --git a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilter.java b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilter.java index fae0b53ad..4c044a103 100644 --- a/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilter.java +++ b/hawkbit-security-integration/src/main/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilter.java @@ -15,7 +15,7 @@ import java.util.stream.Collectors; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.tenancy.TenantAware; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,10 +108,11 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont controllerId = secruityToken.getHeader(caCommonNameHeader); } - List knownHashes = splitMultiHashBySemicolon(authorityNameConfigurationValue); + final List knownHashes = splitMultiHashBySemicolon(authorityNameConfigurationValue); final String cntlId = controllerId; - return knownHashes.stream().map(hashItem -> new HeaderAuthentication(cntlId, hashItem)).collect(Collectors.toSet()); + return knownHashes.stream().map(hashItem -> new HeaderAuthentication(cntlId, hashItem)) + .collect(Collectors.toSet()); } /** @@ -122,7 +123,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont */ private String getIssuerHashHeader(final TenantSecurityToken secruityToken, final String knownIssuerHashes) { // there may be several knownIssuerHashes configured for the tenant - List knownHashes = splitMultiHashBySemicolon(knownIssuerHashes); + final List knownHashes = splitMultiHashBySemicolon(knownIssuerHashes); // iterate over the headers until we get a null header. int iHeader = 1; @@ -143,7 +144,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont } @Override - protected TenantConfigurationKey getTenantConfigurationKey() { + protected String getTenantConfigurationKey() { return TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED; } @@ -155,7 +156,7 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont } } - private static List splitMultiHashBySemicolon(String knownIssuerHashes) { + private static List splitMultiHashBySemicolon(final String knownIssuerHashes) { return Arrays.asList(knownIssuerHashes.split(";")); } } diff --git a/hawkbit-security-integration/src/test/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilterTest.java b/hawkbit-security-integration/src/test/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilterTest.java index bfa13f71a..d21d4e63a 100644 --- a/hawkbit-security-integration/src/test/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilterTest.java +++ b/hawkbit-security-integration/src/test/java/org/eclipse/hawkbit/security/ControllerPreAuthenticatedSecurityHeaderFilterTest.java @@ -19,7 +19,7 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken; import org.eclipse.hawkbit.dmf.json.model.TenantSecurityToken.FileResource; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java index 01e9760a6..09c914d44 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/SpPermissionChecker.java @@ -13,20 +13,18 @@ import java.io.Serializable; import org.eclipse.hawkbit.im.authentication.PermissionService; import org.eclipse.hawkbit.im.authentication.SpPermission; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; /** * Bean which contains all SP permissions. * */ -@Service public class SpPermissionChecker implements Serializable { private static final long serialVersionUID = 2757865286212875704L; - private transient PermissionService permissionService; + protected transient PermissionService permissionService; @Autowired - SpPermissionChecker(final PermissionService permissionService) { + protected SpPermissionChecker(final PermissionService permissionService) { this.permissionService = permissionService; } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java index aeafd22bc..ee8574432 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/UserDetailsFormatter.java @@ -170,7 +170,7 @@ public final class UserDetailsFormatter { return Optional.ofNullable(userPrincipal.getEmail()); } - private static UserDetails getCurrentUser() { + public static UserDetails getCurrentUser() { final SecurityContext context = (SecurityContext) VaadinService.getCurrentRequest().getWrappedSession() .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); return (UserDetails) context.getAuthentication().getPrincipal(); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java index 591983650..4db408352 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/common/builder/AbstractTextFieldBuilder.java @@ -27,6 +27,8 @@ public abstract class AbstractTextFieldBuilder { private String id; private boolean immediate; private boolean required; + private boolean readOnly; + private boolean enabled = true; private int maxLengthAllowed; /** @@ -69,6 +71,26 @@ public abstract class AbstractTextFieldBuilder { return this; } + /** + * @param readOnly + * the readOnly to set + * @return the builder + */ + public AbstractTextFieldBuilder readOnly(final boolean readOnly) { + this.readOnly = readOnly; + return this; + } + + /** + * @param enabled + * the enabled to set + * @return the builder + */ + public AbstractTextFieldBuilder enabled(final boolean enabled) { + this.enabled = enabled; + return this; + } + /** * @param prompt * the prompt to set @@ -119,6 +141,8 @@ public abstract class AbstractTextFieldBuilder { textComponent.setRequired(required); textComponent.setImmediate(immediate); + textComponent.setReadOnly(readOnly); + textComponent.setEnabled(enabled); if (StringUtils.isNotEmpty(caption)) { textComponent.setCaption(caption); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUICheckBox.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUICheckBox.java index f75a03cd7..c4f093a39 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUICheckBox.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUICheckBox.java @@ -20,7 +20,12 @@ public class SPUICheckBox extends CheckBox { SPUICheckBox(final String caption, final String style, final String styleName, final boolean required, final String data) { - decorate(caption, style, styleName, required, data); + decorate(null, caption, style, styleName, required, data); + } + + SPUICheckBox(final String id, final String caption, final String style, final String styleName, + final boolean required, final String data) { + decorate(id, caption, style, styleName, required, data); } /** @@ -37,24 +42,27 @@ public class SPUICheckBox extends CheckBox { * @param promt * inputpromt of the CheckBox */ - private void decorate(final String caption, final String style, final String styleName, final boolean required, - final String data) { + private void decorate(final String id, final String caption, final String style, final String styleName, + final boolean required, final String data) { // Default settings setRequired(required); addStyleName(ValoTheme.CHECKBOX_SMALL); - if (null != caption) { + if (id != null) { + setId(id); + } + if (caption != null) { setCaption(caption); } // Add style - if (null != style) { + if (style != null) { setStyleName(style); } // Add style Name - if (null != styleName) { + if (styleName != null) { addStyleName(styleName); } // Set Data - if (null != data) { + if (data != null) { setData(data); } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUIComponentProvider.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUIComponentProvider.java index 7ed065ceb..ca133f16a 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUIComponentProvider.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/components/SPUIComponentProvider.java @@ -96,6 +96,28 @@ public final class SPUIComponentProvider { return new SPUICheckBox(caption, style, styleName, required, data); } + /** + * Get Label UI component. + * + * @param id + * id of the checkbox + * @param caption + * as caption + * @param style + * combo style to add + * @param styleName + * combo style to set + * @param required + * signifies if combo is mandatory + * @param data + * combo box data + * @return ComboBox + */ + public static CheckBox getCheckBox(final String id, final String caption, final String style, + final String styleName, final boolean required, final String data) { + return new SPUICheckBox(id, caption, style, styleName, required, data); + } + /** * Get Button - Factory Approach for decoration. * diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java index 266f95e45..de1fc1a80 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/menu/DashboardMenu.java @@ -125,7 +125,7 @@ public final class DashboardMenu extends CustomComponent { return dashboardMenuLayout; } - private VerticalLayout getMenuLayout() { + private static VerticalLayout getMenuLayout() { final VerticalLayout menuContent = new VerticalLayout(); menuContent.addStyleName(ValoTheme.MENU_PART); menuContent.addStyleName("sidebar"); @@ -197,7 +197,7 @@ public final class DashboardMenu extends CustomComponent { } - private Component buildUserMenu() { + private static Component buildUserMenu() { final MenuBar settings = new MenuBar(); settings.addStyleName("user-menu"); settings.setHtmlContentAllowed(true); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/BaseConfigurationView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/BaseConfigurationView.java index a68b095b4..f93a09130 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/BaseConfigurationView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/BaseConfigurationView.java @@ -25,7 +25,7 @@ public abstract class BaseConfigurationView extends CustomComponent implements C private final List configurationChangeListeners = new ArrayList<>(); protected void notifyConfigurationChanged() { - configurationChangeListeners.forEach(listener -> listener.configurationHasChanged()); + configurationChangeListeners.forEach(ConfigurationItemChangeListener::configurationHasChanged); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/ConfigurationGroup.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/ConfigurationGroup.java index 3ac3610f9..033d2a76e 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/ConfigurationGroup.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/ConfigurationGroup.java @@ -25,4 +25,12 @@ public interface ConfigurationGroup extends Component, ConfigurationItem { * called to rollback any configuration changes. */ void undo(); + + /** + * @return true if view can be shown (e.g. sufficient + * permissions). + */ + default boolean show() { + return true; + } } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/PollingConfigurationView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/PollingConfigurationView.java index bd70e78c9..2af11cf32 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/PollingConfigurationView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/PollingConfigurationView.java @@ -14,7 +14,7 @@ import org.eclipse.hawkbit.ControllerPollProperties; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.tenancy.configuration.DurationHelper; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.ui.tenantconfiguration.polling.DurationConfigField; import org.eclipse.hawkbit.ui.utils.I18N; import org.eclipse.hawkbit.ui.utils.UIComponentIdProvider; @@ -108,7 +108,7 @@ public class PollingConfigurationView extends BaseConfigurationView } } - private void saveDurationConfigurationValue(final TenantConfigurationKey key, final Duration duration) { + private void saveDurationConfigurationValue(final String key, final Duration duration) { if (duration == null) { tenantConfigurationManagement.deleteConfiguration(key); } else { diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java index e5dac50c4..05613ccec 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/TenantConfigurationDashboardView.java @@ -8,7 +8,9 @@ */ package org.eclipse.hawkbit.ui.tenantconfiguration; +import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; @@ -68,6 +70,9 @@ public class TenantConfigurationDashboardView extends CustomComponent implements private final List configurationViews = Lists.newArrayListWithExpectedSize(3); + @Autowired(required = false) + private Collection customConfigurationViews; + @Autowired TenantConfigurationDashboardView(final I18N i18n, final UiProperties uiProperties, final UINotification uINotification, final SystemManagement systemManagement, @@ -94,6 +99,10 @@ public class TenantConfigurationDashboardView extends CustomComponent implements configurationViews.add(defaultDistributionSetTypeLayout); configurationViews.add(authenticationConfigurationView); configurationViews.add(pollingConfigurationView); + if (customConfigurationViews != null) { + configurationViews.addAll( + customConfigurationViews.stream().filter(ConfigurationGroup::show).collect(Collectors.toList())); + } final Panel rootPanel = new Panel(); rootPanel.setStyleName("tenantconfig-root"); diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AbstractAuthenticationTenantConfigurationItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AbstractAuthenticationTenantConfigurationItem.java index 020b96893..3501b36d7 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AbstractAuthenticationTenantConfigurationItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AbstractAuthenticationTenantConfigurationItem.java @@ -12,7 +12,7 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.repository.model.TenantConfigurationValue; import org.eclipse.hawkbit.ui.common.builder.LabelBuilder; import org.eclipse.hawkbit.ui.utils.I18N; @@ -28,7 +28,7 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay private final I18N i18n; - private final TenantConfigurationKey configurationKey; + private final String configurationKey; private final transient TenantConfigurationManagement tenantConfigurationManagement; private final List configurationChangeListeners = new ArrayList<>(); @@ -40,7 +40,7 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay * the tenant configuration management to retrieve the * configuration value */ - public AbstractAuthenticationTenantConfigurationItem(final TenantConfigurationKey configurationKey, + public AbstractAuthenticationTenantConfigurationItem(final String configurationKey, final TenantConfigurationManagement tenantConfigurationManagement, final I18N i18n) { this.configurationKey = configurationKey; this.tenantConfigurationManagement = tenantConfigurationManagement; @@ -57,7 +57,10 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay @Override public boolean isConfigEnabled() { - return tenantConfigurationManagement.getConfigurationValue(configurationKey, Boolean.class).getValue(); + final TenantConfigurationValue enabled = tenantConfigurationManagement + .getConfigurationValue(configurationKey, Boolean.class); + + return enabled.getValue() && !enabled.isGlobal(); } /** @@ -70,12 +73,12 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay /** * @return the configurationKey */ - protected TenantConfigurationKey getConfigurationKey() { + protected String getConfigurationKey() { return configurationKey; } protected void notifyConfigurationChanged() { - configurationChangeListeners.forEach(listener -> listener.configurationHasChanged()); + configurationChangeListeners.forEach(ConfigurationItemChangeListener::configurationHasChanged); } @Override diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AnonymousDownloadAuthenticationConfigurationItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AnonymousDownloadAuthenticationConfigurationItem.java index 8d8e497cb..f3e8d76f5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AnonymousDownloadAuthenticationConfigurationItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/AnonymousDownloadAuthenticationConfigurationItem.java @@ -9,7 +9,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.ui.utils.I18N; /** diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/CertificateAuthenticationConfigurationItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/CertificateAuthenticationConfigurationItem.java index 4feffb602..6937143a5 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/CertificateAuthenticationConfigurationItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/CertificateAuthenticationConfigurationItem.java @@ -9,7 +9,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.ui.common.builder.LabelBuilder; import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder; import org.eclipse.hawkbit.ui.utils.I18N; diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/GatewaySecurityTokenAuthenticationConfigurationItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/GatewaySecurityTokenAuthenticationConfigurationItem.java index 3fca97f07..48cf132f4 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/GatewaySecurityTokenAuthenticationConfigurationItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/GatewaySecurityTokenAuthenticationConfigurationItem.java @@ -8,11 +8,11 @@ */ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication; +import org.apache.commons.lang3.StringUtils; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; import org.eclipse.hawkbit.security.SecurityTokenGenerator; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.ui.common.builder.LabelBuilder; -import org.eclipse.hawkbit.ui.common.builder.TextFieldBuilder; import org.eclipse.hawkbit.ui.components.SPUIComponentProvider; import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmall; import org.eclipse.hawkbit.ui.utils.I18N; @@ -21,7 +21,6 @@ import com.vaadin.server.FontAwesome; import com.vaadin.ui.Button; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; -import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.themes.ValoTheme; @@ -35,15 +34,11 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac private final transient SecurityTokenGenerator securityTokenGenerator; - private final TextField gatewayTokenNameTextField; - private final Label gatewayTokenkeyLabel; private boolean configurationEnabled; private boolean configurationEnabledChange; - private boolean keyNameChanged; - private boolean keyChanged; private final VerticalLayout detailLayout; @@ -61,10 +56,6 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac detailLayout = new VerticalLayout(); detailLayout.setImmediate(true); - gatewayTokenNameTextField = new TextFieldBuilder().immediate(true).buildTextComponent(); - // hide text field until we support multiple gateway tokens for a tenan - gatewayTokenNameTextField.setVisible(false); - gatewayTokenNameTextField.addTextChangeListener(event -> doKeyNameChanged()); final Button gatewaytokenBtn = SPUIComponentProvider.getButton("TODO-ID", "Regenerate Key", "", ValoTheme.BUTTON_TINY + " " + "redicon", true, null, SPUIButtonStyleSmall.class); @@ -80,24 +71,17 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac keyGenerationLayout.setSpacing(true); keyGenerationLayout.setImmediate(true); - keyGenerationLayout.addComponent(gatewayTokenNameTextField); keyGenerationLayout.addComponent(gatewayTokenkeyLabel); keyGenerationLayout.addComponent(gatewaytokenBtn); detailLayout.addComponent(keyGenerationLayout); if (isConfigEnabled()) { - gatewayTokenNameTextField.setValue(getSecurityTokenName()); gatewayTokenkeyLabel.setValue(getSecurityTokenKey()); setDetailVisible(true); } } - private void doKeyNameChanged() { - keyNameChanged = true; - notifyConfigurationChanged(); - } - private void setDetailVisible(final boolean visible) { if (visible) { addComponent(detailLayout); @@ -122,22 +106,13 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac configurationEnabled = true; setDetailVisible(true); String gatewayTokenKey = getSecurityTokenKey(); - String gatewayTokenName = getSecurityTokenName(); - if (gatewayTokenKey == null) { - gatewayTokenName = "GeneratedToken"; - keyNameChanged = true; + if (StringUtils.isEmpty(gatewayTokenKey)) { gatewayTokenKey = securityTokenGenerator.generateToken(); keyChanged = true; } - gatewayTokenNameTextField.setValue(gatewayTokenName); gatewayTokenkeyLabel.setValue(gatewayTokenKey); } - private String getSecurityTokenName() { - return getTenantConfigurationManagement().getConfigurationValue( - TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME, String.class).getValue(); - } - private String getSecurityTokenKey() { return getTenantConfigurationManagement().getConfigurationValue( TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue(); @@ -159,11 +134,6 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, configurationEnabled); } - if (keyNameChanged) { - getTenantConfigurationManagement().addOrUpdateConfiguration( - TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME, - gatewayTokenNameTextField.getValue()); - } if (keyChanged) { getTenantConfigurationManagement().addOrUpdateConfiguration( TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, @@ -174,9 +144,7 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac @Override public void undo() { configurationEnabledChange = false; - keyNameChanged = false; keyChanged = false; - gatewayTokenNameTextField.setValue(getSecurityTokenName()); gatewayTokenkeyLabel.setValue(getSecurityTokenKey()); } diff --git a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/TargetSecurityTokenAuthenticationConfigurationItem.java b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/TargetSecurityTokenAuthenticationConfigurationItem.java index 65a149ae5..97d06ec90 100644 --- a/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/TargetSecurityTokenAuthenticationConfigurationItem.java +++ b/hawkbit-ui/src/main/java/org/eclipse/hawkbit/ui/tenantconfiguration/authentication/TargetSecurityTokenAuthenticationConfigurationItem.java @@ -9,7 +9,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication; import org.eclipse.hawkbit.repository.TenantConfigurationManagement; -import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey; +import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey; import org.eclipse.hawkbit.ui.utils.I18N; /** diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss index 3f70e139e..ac6402910 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/others.scss @@ -64,6 +64,7 @@ margin-left: 1px; position: relative; z-index: 1; + font-size: 14px !important; } //Version displayed at bottom of menu * diff --git a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss index 742741d0e..ee912f72b 100644 --- a/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss +++ b/hawkbit-ui/src/main/resources/VAADIN/themes/hawkbit/customstyles/popup-window.scss @@ -135,7 +135,7 @@ } .margin-top-style { - margin-top: 10px; + margin-top: 10px !important; } //confimation dialogue popup - Content margin adjustment