Custom Tenant configuration. (#395)
* Tenant configuration configurable. Signed-off-by: kaizimmerm <kai.zimmermann@bosch-si.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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<? extends TenantConfigurationValidator> 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<? extends TenantConfigurationValidator> 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 <T> Class<T> getDataType() {
|
||||
return (Class<T>) 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<TenantConfigurationKey> 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.");
|
||||
}
|
||||
}
|
||||
@@ -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<String, TenantConfigurationKey> configuration = new HashMap<>();
|
||||
|
||||
/**
|
||||
* @return full map of all configured tenant properties
|
||||
*/
|
||||
public Map<String, TenantConfigurationKey> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return full list of {@link TenantConfigurationKey}s
|
||||
*/
|
||||
public Collection<TenantConfigurationKey> 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<? extends TenantConfigurationValidator> 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 <T> Class<T> getDataType() {
|
||||
return (Class<T>) 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<? extends TenantConfigurationValidator> getValidator() {
|
||||
return validator;
|
||||
}
|
||||
|
||||
public void setValidator(final Class<? extends TenantConfigurationValidator> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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("");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<String, MgmtSystemTenantConfigurationValue> toResponse(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantConfigurationProperties tenantConfigurationProperties) {
|
||||
|
||||
final Map<String, MgmtSystemTenantConfigurationValue> 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()))));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<ResourceSupport> getSystem() {
|
||||
@@ -53,7 +60,9 @@ public class MgmtSystemResource implements MgmtSystemRestApi {
|
||||
*/
|
||||
@Override
|
||||
public ResponseEntity<Map<String, MgmtSystemTenantConfigurationValue>> 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<Void> 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<MgmtSystemTenantConfigurationValue> 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<? extends Serializable> updatedValue = tenantConfigurationManagement
|
||||
.addOrUpdateConfiguration(configKey, configurationValueRest.getValue());
|
||||
.addOrUpdateConfiguration(keyName, configurationValueRest.getValue());
|
||||
return new ResponseEntity<>(MgmtSystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,3 +51,11 @@ MYSQL.spring.datasource.password=
|
||||
# SP Controller configuration
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -643,5 +643,4 @@ public interface TargetManagement {
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_UPDATE_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_CONTROLLER)
|
||||
Target updateTarget(TargetUpdate update);
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
<T extends Serializable> TenantConfigurationValue<T> addOrUpdateConfiguration(
|
||||
TenantConfigurationKey configurationKey, T value);
|
||||
<T extends Serializable> TenantConfigurationValue<T> 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)
|
||||
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey);
|
||||
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName);
|
||||
|
||||
/**
|
||||
* Retrieves a configuration value from the e.g. tenant overwritten
|
||||
@@ -99,7 +98,7 @@ public interface TenantConfigurationManagement {
|
||||
*
|
||||
* @param <T>
|
||||
* 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)
|
||||
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(TenantConfigurationKey configurationKey,
|
||||
<T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(String configurationKeyName,
|
||||
Class<T> propertyType);
|
||||
|
||||
/**
|
||||
@@ -125,7 +124,7 @@ public interface TenantConfigurationManagement {
|
||||
*
|
||||
* @param <T>
|
||||
* 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> T getGlobalConfigurationValue(TenantConfigurationKey configurationKey, Class<T> propertyType);
|
||||
<T> T getGlobalConfigurationValue(String configurationKeyName, Class<T> propertyType);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -94,6 +95,8 @@ public class EventType {
|
||||
TYPES.put(21, SoftwareModuleCreatedEvent.class);
|
||||
TYPES.put(22, SoftwareModuleDeletedEvent.class);
|
||||
TYPES.put(23, SoftwareModuleUpdatedEvent.class);
|
||||
|
||||
TYPES.put(24, TargetPollEvent.class);
|
||||
}
|
||||
|
||||
private int value;
|
||||
|
||||
@@ -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.<br>
|
||||
* Calculates non-persistent timestamps , e.g. the point a time a target is
|
||||
* declared as overdue.<br>
|
||||
* 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(
|
||||
final TenantConfigurationKey configurationKey, final Class<T> propertyType) {
|
||||
@Cacheable(value = "tenantConfiguration", key = "#configurationKeyName")
|
||||
public <T extends Serializable> TenantConfigurationValue<T> getConfigurationValue(final String configurationKeyName,
|
||||
final Class<T> 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 <T> void validateTenantConfigurationDataType(final TenantConfigurationKey configurationKey,
|
||||
final Class<T> 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.<T> 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 <T extends Serializable> TenantConfigurationValue<T> 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> T getGlobalConfigurationValue(final TenantConfigurationKey configurationKey,
|
||||
final Class<T> propertyType) {
|
||||
public <T> T getGlobalConfigurationValue(final String configurationKeyName, final Class<T> 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 <T extends Serializable> TenantConfigurationValue<T> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Action> findActionsByRolloutAndStatus(final Rollout rollout, final Action.Status actionStatus) {
|
||||
return actionRepository.findByRolloutAndStatus((JpaRollout) rollout, actionStatus);
|
||||
|
||||
@@ -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<String> defaultConfigValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(configKey, String.class);
|
||||
final TenantConfigurationValue<String> 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<String> 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<String, Void> keynames = new HashMap<String, Void>();
|
||||
final Map<String, Void> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String> TEST_POLLING_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String>builder().value("00:05:00").build();
|
||||
.<String> builder().value("00:05:00").build();
|
||||
private static final TenantConfigurationValue<String> TEST_POLLING_OVERDUE_TIME_INTERVAL = TenantConfigurationValue
|
||||
.<String>builder().value("00:07:37").build();
|
||||
.<String> 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.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String> 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.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String> 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.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String> 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.<String>greaterThanOrEqualTo(any(Expression.class), any(String.class)))
|
||||
when(criteriaBuilderMock.<String> 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.<String>lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder)))
|
||||
when(criteriaBuilderMock.<String> 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.<String>lessThanOrEqualTo(any(Expression.class), eq(overduePropPlaceholder)))
|
||||
when(criteriaBuilderMock.<String> 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() {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -39,3 +36,47 @@ flyway.sqlMigrationSuffix=${spring.jpa.database}.sql
|
||||
# DDI configuration
|
||||
hawkbit.controller.pollingTime=00:01:00
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String> knownHashes = splitMultiHashBySemicolon(authorityNameConfigurationValue);
|
||||
final List<String> 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<String> knownHashes = splitMultiHashBySemicolon(knownIssuerHashes);
|
||||
final List<String> 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<String> splitMultiHashBySemicolon(String knownIssuerHashes) {
|
||||
private static List<String> splitMultiHashBySemicolon(final String knownIssuerHashes) {
|
||||
return Arrays.asList(knownIssuerHashes.split(";"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -27,6 +27,8 @@ public abstract class AbstractTextFieldBuilder<E extends AbstractTextField> {
|
||||
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<E extends AbstractTextField> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param readOnly
|
||||
* the readOnly to set
|
||||
* @return the builder
|
||||
*/
|
||||
public AbstractTextFieldBuilder<E> readOnly(final boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enabled
|
||||
* the enabled to set
|
||||
* @return the builder
|
||||
*/
|
||||
public AbstractTextFieldBuilder<E> enabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prompt
|
||||
* the prompt to set
|
||||
@@ -119,6 +141,8 @@ public abstract class AbstractTextFieldBuilder<E extends AbstractTextField> {
|
||||
|
||||
textComponent.setRequired(required);
|
||||
textComponent.setImmediate(immediate);
|
||||
textComponent.setReadOnly(readOnly);
|
||||
textComponent.setEnabled(enabled);
|
||||
|
||||
if (StringUtils.isNotEmpty(caption)) {
|
||||
textComponent.setCaption(caption);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -25,7 +25,7 @@ public abstract class BaseConfigurationView extends CustomComponent implements C
|
||||
private final List<ConfigurationItemChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
protected void notifyConfigurationChanged() {
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationHasChanged());
|
||||
configurationChangeListeners.forEach(ConfigurationItemChangeListener::configurationHasChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,4 +25,12 @@ public interface ConfigurationGroup extends Component, ConfigurationItem {
|
||||
* called to rollback any configuration changes.
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if view can be shown (e.g. sufficient
|
||||
* permissions).
|
||||
*/
|
||||
default boolean show() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<ConfigurationGroup> configurationViews = Lists.newArrayListWithExpectedSize(3);
|
||||
|
||||
@Autowired(required = false)
|
||||
private Collection<ConfigurationGroup> 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");
|
||||
|
||||
@@ -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<ConfigurationItemChangeListener> 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<Boolean> 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
margin-left: 1px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
//Version displayed at bottom of menu *
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
}
|
||||
|
||||
.margin-top-style {
|
||||
margin-top: 10px;
|
||||
margin-top: 10px !important;
|
||||
}
|
||||
|
||||
//confimation dialogue popup - Content margin adjustment
|
||||
|
||||
Reference in New Issue
Block a user