Merge pull request #56 from bsinno/feature_MECS-86_tenant_specific_polling_configuration
Feature: tenant specific polling configuration Note: @fabnon is member of @michahirsch and my organisation
This commit is contained in:
1
examples/hawkbit-mgmt-api-client/.gitignore
vendored
1
examples/hawkbit-mgmt-api-client/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
/target/
|
||||
/bin/
|
||||
/.apt_generated/
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationTok
|
||||
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.rest.resource.RestConstants;
|
||||
import org.eclipse.hawkbit.security.ControllerTenantAwareAuthenticationDetailsSource;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
@@ -39,6 +40,7 @@ import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedGatewaySecurit
|
||||
import org.eclipse.hawkbit.security.HttpControllerPreAuthenticatedSecurityHeaderFilter;
|
||||
import org.eclipse.hawkbit.security.HttpDownloadAuthenticationFilter;
|
||||
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -111,33 +113,36 @@ public class SecurityManagedConfiguration {
|
||||
@Autowired
|
||||
private ControllerManagement controllerManagement;
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
@Autowired
|
||||
private DdiSecurityProperties ddiSecurityConfiguration;
|
||||
@Autowired
|
||||
private org.springframework.boot.autoconfigure.security.SecurityProperties springSecurityProperties;
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
@Override
|
||||
protected void configure(final HttpSecurity http) throws Exception {
|
||||
final ControllerTenantAwareAuthenticationDetailsSource authenticationDetailsSource = new ControllerTenantAwareAuthenticationDetailsSource();
|
||||
|
||||
final HttpControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new HttpControllerPreAuthenticatedSecurityHeaderFilter(
|
||||
ddiSecurityConfiguration.getRp().getCnHeader(), ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(),
|
||||
systemManagement, tenantAware);
|
||||
ddiSecurityConfiguration.getRp().getCnHeader(),
|
||||
ddiSecurityConfiguration.getRp().getSslIssuerHashHeader(), tenantConfigurationManagement,
|
||||
tenantAware, systemSecurityContext);
|
||||
securityHeaderFilter.setAuthenticationManager(authenticationManager());
|
||||
securityHeaderFilter.setCheckForPrincipalChanges(true);
|
||||
securityHeaderFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
|
||||
final HttpControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new HttpControllerPreAuthenticateSecurityTokenFilter(
|
||||
systemManagement, tenantAware, controllerManagement);
|
||||
tenantConfigurationManagement, tenantAware, controllerManagement, systemSecurityContext);
|
||||
securityTokenFilter.setAuthenticationManager(authenticationManager());
|
||||
securityTokenFilter.setCheckForPrincipalChanges(true);
|
||||
securityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
|
||||
final HttpControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
|
||||
systemManagement, tenantAware);
|
||||
tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
gatewaySecurityTokenFilter.setAuthenticationManager(authenticationManager());
|
||||
gatewaySecurityTokenFilter.setCheckForPrincipalChanges(true);
|
||||
gatewaySecurityTokenFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
|
||||
@@ -169,19 +174,10 @@ public class SecurityManagedConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.security.config.annotation.web.configuration.
|
||||
* WebSecurityConfigurerAdapter
|
||||
* #configure(org.springframework.security.config.annotation.
|
||||
* authentication.builders. AuthenticationManagerBuilder)
|
||||
*/
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(
|
||||
new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
|
||||
ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,8 +462,8 @@ public class SecurityManagedConfiguration {
|
||||
|
||||
@Override
|
||||
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.authenticationProvider(
|
||||
new PreAuthTokenSourceTrustAuthenticationProvider(ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||
auth.authenticationProvider(new PreAuthTokenSourceTrustAuthenticationProvider(
|
||||
ddiSecurityConfiguration.getRp().getTrustedIPs()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ hawkbit.threadpool.queuesize=20000
|
||||
# Defines the polling time for the controllers in HH:MM:SS notation
|
||||
hawkbit.controller.pollingTime=00:05:00
|
||||
hawkbit.controller.pollingOverdueTime=00:05:00
|
||||
hawkbit.controller.maxPollingTime=23:59:59
|
||||
hawkbit.controller.minPollingTime=00:00:30
|
||||
# Attention: if you want to use a maximumPollingTime greater 23:59:59 you have to update the DurationField in the configuration window
|
||||
|
||||
|
||||
# Configuration for RabbitMQ integration
|
||||
hawkbit.dmf.rabbitmq.deadLetterQueue=dmf_connector_deadletter
|
||||
|
||||
1
hawkbit-core/.gitignore
vendored
Normal file
1
hawkbit-core/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/.apt_generated/
|
||||
@@ -8,11 +8,19 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Defines the polling time for the controllers in HH:MM:SS notation.
|
||||
* Defines global configuration for the controllers/clients on the provisioning
|
||||
* targets/devices.
|
||||
*
|
||||
*
|
||||
* 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}.
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
@@ -20,31 +28,31 @@ import org.springframework.stereotype.Component;
|
||||
public class ControllerPollProperties {
|
||||
|
||||
/**
|
||||
* Recommended target polling time for DDI API. Final choice is up to the
|
||||
* target.
|
||||
* Maximum polling time that can be configured by a tenant in HH:MM:SS
|
||||
* notation.
|
||||
*/
|
||||
private String pollingTime = "00:05:00";
|
||||
private String maxPollingTime = "23:59:00";
|
||||
|
||||
/**
|
||||
* Assumed time frame where the target is considered overdue when no DDI
|
||||
* polling has been registered by the update server.
|
||||
* Minimum polling time that can be configured by a tenant in HH:MM:SS
|
||||
* notation.
|
||||
*/
|
||||
private String pollingOverdueTime = "00:05:00";
|
||||
private String minPollingTime = "00:00:30";
|
||||
|
||||
public String getPollingTime() {
|
||||
return pollingTime;
|
||||
public String getMaxPollingTime() {
|
||||
return maxPollingTime;
|
||||
}
|
||||
|
||||
public void setPollingTime(final String pollingTime) {
|
||||
this.pollingTime = pollingTime;
|
||||
public void setMaxPollingTime(final String maxPollingTime) {
|
||||
this.maxPollingTime = maxPollingTime;
|
||||
}
|
||||
|
||||
public String getPollingOverdueTime() {
|
||||
return pollingOverdueTime;
|
||||
public String getMinPollingTime() {
|
||||
return minPollingTime;
|
||||
}
|
||||
|
||||
public void setPollingOverdueTime(final String pollingOverdue) {
|
||||
this.pollingOverdueTime = pollingOverdue;
|
||||
public void setMinPollingTime(final String minPollingTime) {
|
||||
this.minPollingTime = minPollingTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ public enum SpServerError {
|
||||
*/
|
||||
SP_REST_SORT_PARAM_INVALID_DIRECTION("hawkbit.server.error.rest.param.invalidDirection",
|
||||
"The given sort parameter direction does not exist"),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -176,6 +177,16 @@ public enum SpServerError {
|
||||
SP_REPO_ENTITY_READ_ONLY("hawkbit.server.error.entityreadonly",
|
||||
"The given entity is read only and the change cannot be completed."),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
SP_CONFIGURATION_VALUE_INVALID("hawkbit.server.error.configValueInvalid",
|
||||
"The given configuration value is invalid."),
|
||||
/**
|
||||
*
|
||||
*/
|
||||
SP_CONFIGURATION_KEY_INVALID("hawkbit.server.error.configKeyInvalid", "The given configuration key is invalid."),
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -74,6 +74,9 @@ public abstract class SpServerRtException extends RuntimeException {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the SpServerError which is wrapped by this exception
|
||||
*/
|
||||
public SpServerError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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.time.Duration;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
|
||||
/**
|
||||
* This class is a helper for converting a duration into a string and for the
|
||||
* other way. The string is in the format expected in configuration and database
|
||||
* {@link #DURATION_FORMAT}.
|
||||
*
|
||||
*/
|
||||
public class DurationHelper {
|
||||
|
||||
/**
|
||||
* Format of the String expected in configuration file and in the database.
|
||||
*/
|
||||
public static final String DURATION_FORMAT = "HH:mm:ss";
|
||||
|
||||
/**
|
||||
* Converts a Duration into a formatted String
|
||||
*
|
||||
* @param duration
|
||||
* duration, which will be converted into a formatted String
|
||||
* @return String in the duration format, specified at
|
||||
* {@link #DURATION_FORMAT}
|
||||
*/
|
||||
public String durationToFormattedString(final Duration duration) {
|
||||
if (duration == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return LocalTime.ofNanoOfDay(duration.toNanos()).format(DateTimeFormatter.ofPattern(DURATION_FORMAT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a formatted String into a Duration object.
|
||||
*
|
||||
* @param formattedDuration
|
||||
* String in {@link #DURATION_FORMAT}
|
||||
* @return duration
|
||||
* @throws DateTimeParseException
|
||||
* when String is in wrong format
|
||||
*/
|
||||
public Duration formattedStringToDuration(final String formattedDuration) throws DateTimeParseException {
|
||||
if (formattedDuration == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final TemporalAccessor ta = DateTimeFormatter.ofPattern(DURATION_FORMAT).parse(formattedDuration.trim());
|
||||
return Duration.between(LocalTime.MIDNIGHT, LocalTime.from(ta));
|
||||
}
|
||||
|
||||
/**
|
||||
* converts values of time constants to a Duration object..
|
||||
*
|
||||
* @param hours
|
||||
* count of hours
|
||||
* @param minutes
|
||||
* count of minutes
|
||||
* @param seconds
|
||||
* count of seconds
|
||||
* @return duration
|
||||
*/
|
||||
public Duration getDurationByTimeValues(final long hours, final long minutes, final long seconds) {
|
||||
return Duration.ofHours(hours).plusMinutes(minutes).plusSeconds(seconds);
|
||||
}
|
||||
|
||||
public DurationRangeValidator durationRangeValidator(final Duration min, final Duration max) {
|
||||
return new DurationRangeValidator(min, max);
|
||||
}
|
||||
|
||||
public static class DurationRangeValidator {
|
||||
final Duration min;
|
||||
final Duration max;
|
||||
|
||||
private DurationRangeValidator(final Duration min, final Duration max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public boolean isWithinRange(final Duration duration) {
|
||||
return duration.compareTo(min) > 0 && duration.compareTo(max) < 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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 org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* The {@link #InvalidTenantConfigurationKeyException} is thrown when an invalid
|
||||
* configuration key is used.
|
||||
*
|
||||
*/
|
||||
public class InvalidTenantConfigurationKeyException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_KEY_INVALID;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public InvalidTenantConfigurationKeyException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,12 +8,21 @@
|
||||
*/
|
||||
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 seperately.
|
||||
*
|
||||
*
|
||||
*
|
||||
* configured for each tenant separately. The non overridable properties are
|
||||
* configured in {@link ControllerPollProperties} instead.
|
||||
*
|
||||
*/
|
||||
public enum TenantConfigurationKey {
|
||||
@@ -21,51 +30,68 @@ public enum TenantConfigurationKey {
|
||||
/**
|
||||
* boolean value {@code true} {@code false}.
|
||||
*/
|
||||
AUTHENTICATION_MODE_HEADER_ENABLED("authentication.header.enabled",
|
||||
"hawkbit.server.ddi.security.authentication.header.enabled", Boolean.FALSE.toString()),
|
||||
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", Boolean.FALSE.toString()),
|
||||
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.FALSE.toString()),
|
||||
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.FALSE.toString()),
|
||||
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", null),
|
||||
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", null);
|
||||
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("pollingOverdueTime", "hawkbit.controller.pollingOverdueTime", String.class, null, TenantConfigurationPollingDurationValidator.class),
|
||||
|
||||
/**
|
||||
* string value which holds the polling time interval in the format HH:mm:ss
|
||||
*/
|
||||
POLLING_OVERDUE_TIME_INTERVAL("pollingTime", "hawkbit.controller.pollingTime", String.class, null, TenantConfigurationPollingDurationValidator.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 allowedValues
|
||||
* @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
|
||||
*/
|
||||
private TenantConfigurationKey(final String key, final String defaultKeyName, final String defaultValue) {
|
||||
private 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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,4 +114,49 @@ public enum TenantConfigurationKey {
|
||||
public String getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the data type of the tenant configuration value. (e.g.
|
||||
* Integer.class, String.class)
|
||||
*/
|
||||
public Class<?> getDataType() {
|
||||
return 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,22 @@
|
||||
/**
|
||||
* 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.validator;
|
||||
|
||||
/**
|
||||
* specific tenant configuration validator, which validates that the given value
|
||||
* is a booleans.
|
||||
*/
|
||||
public class TenantConfigurationBooleanValidator implements TenantConfigurationValidator {
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* 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.validator;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.format.DateTimeParseException;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This class is used to validate, that the property is a String and that it is
|
||||
* in the correct duration format.
|
||||
*
|
||||
*/
|
||||
public class TenantConfigurationPollingDurationValidator implements TenantConfigurationValidator {
|
||||
|
||||
private final DurationHelper durationHelper = new DurationHelper();
|
||||
|
||||
private final Duration minDuration;
|
||||
|
||||
private final Duration maxDuration;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param properties
|
||||
* property accessor for poll configuration
|
||||
*/
|
||||
@Autowired
|
||||
public TenantConfigurationPollingDurationValidator(final ControllerPollProperties properties) {
|
||||
minDuration = durationHelper.formattedStringToDuration(properties.getMinPollingTime());
|
||||
maxDuration = durationHelper.formattedStringToDuration(properties.getMaxPollingTime());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(final Object tenantConfigurationObject) {
|
||||
TenantConfigurationValidator.super.validate(tenantConfigurationObject);
|
||||
final String tenantConfigurationString = (String) tenantConfigurationObject;
|
||||
|
||||
final Duration tenantConfigurationValue;
|
||||
try {
|
||||
tenantConfigurationValue = durationHelper.formattedStringToDuration(tenantConfigurationString);
|
||||
} catch (final DateTimeParseException ex) {
|
||||
throw new TenantConfigurationValidatorException(
|
||||
String.format("The given configuration value is expected as a string in the format %s.",
|
||||
DurationHelper.DURATION_FORMAT));
|
||||
}
|
||||
|
||||
if (!durationHelper.durationRangeValidator(minDuration, maxDuration).isWithinRange(tenantConfigurationValue)) {
|
||||
throw new TenantConfigurationValidatorException(
|
||||
String.format("The given configuration value is not in the allowed range from %s to %s.",
|
||||
durationHelper.durationToFormattedString(minDuration),
|
||||
durationHelper.durationToFormattedString(maxDuration)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.validator;
|
||||
|
||||
/**
|
||||
* specific tenant configuration validator, which validates Strings.
|
||||
*/
|
||||
public class TenantConfigurationStringValidator implements TenantConfigurationValidator {
|
||||
|
||||
@Override
|
||||
public Class<?> validateToClass() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
@@ -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.tenancy.configuration.validator;
|
||||
|
||||
/**
|
||||
* base interface for clases which can validate tenant configuration values.
|
||||
*
|
||||
*/
|
||||
public interface TenantConfigurationValidator {
|
||||
|
||||
/**
|
||||
* validates the tenant configuration value
|
||||
*
|
||||
* @param tenantConfigurationValue
|
||||
* value which will be validated.
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* is thrown, when parameter is invalid.
|
||||
*/
|
||||
default void validate(final Object tenantConfigurationValue) throws TenantConfigurationValidatorException {
|
||||
if (tenantConfigurationValue != null
|
||||
&& validateToClass().isAssignableFrom(tenantConfigurationValue.getClass())) {
|
||||
return;
|
||||
}
|
||||
throw new TenantConfigurationValidatorException(
|
||||
"The given configuration value is expected as a " + validateToClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the generic class to check the object
|
||||
*
|
||||
* @return the class to check the value
|
||||
*/
|
||||
default Class<?> validateToClass() {
|
||||
return Object.class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.validator;
|
||||
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.exception.SpServerRtException;
|
||||
|
||||
/**
|
||||
* Exception which is thrown, when the validation of the configuration value has
|
||||
* not been successful.
|
||||
*
|
||||
*/
|
||||
public class TenantConfigurationValidatorException extends SpServerRtException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final SpServerError THIS_ERROR = SpServerError.SP_CONFIGURATION_VALUE_INVALID;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public TenantConfigurationValidatorException() {
|
||||
super(THIS_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final Throwable cause) {
|
||||
super(THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
* @param cause
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final String message, final Throwable cause) {
|
||||
super(message, THIS_ERROR, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameterized constructor.
|
||||
*
|
||||
* @param message
|
||||
* of the exception
|
||||
*/
|
||||
public TenantConfigurationValidatorException(final String message) {
|
||||
super(message, THIS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import javax.annotation.PostConstruct;
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.CoapAnonymousPreAuthenticatedFilter;
|
||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticateSecurityTokenFilter;
|
||||
import org.eclipse.hawkbit.security.ControllerPreAuthenticatedGatewaySecurityTokenFilter;
|
||||
@@ -24,6 +24,7 @@ import org.eclipse.hawkbit.security.ControllerPreAuthenticatedSecurityHeaderFilt
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
import org.eclipse.hawkbit.security.PreAuthTokenSourceTrustAuthenticationProvider;
|
||||
import org.eclipse.hawkbit.security.PreAuthenficationFilter;
|
||||
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -49,7 +50,7 @@ public class AmqpControllerAuthentfication {
|
||||
private ControllerManagement controllerManagement;
|
||||
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
@@ -57,6 +58,9 @@ public class AmqpControllerAuthentfication {
|
||||
@Autowired
|
||||
private DdiSecurityProperties ddiSecruityProperties;
|
||||
|
||||
@Autowired
|
||||
private SystemSecurityContext systemSecurityContext;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -74,16 +78,16 @@ public class AmqpControllerAuthentfication {
|
||||
|
||||
private void addFilter() {
|
||||
final ControllerPreAuthenticatedGatewaySecurityTokenFilter gatewaySecurityTokenFilter = new ControllerPreAuthenticatedGatewaySecurityTokenFilter(
|
||||
systemManagement, tenantAware);
|
||||
tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
filterChain.add(gatewaySecurityTokenFilter);
|
||||
|
||||
final ControllerPreAuthenticatedSecurityHeaderFilter securityHeaderFilter = new ControllerPreAuthenticatedSecurityHeaderFilter(
|
||||
ddiSecruityProperties.getRp().getCnHeader(), ddiSecruityProperties.getRp().getSslIssuerHashHeader(),
|
||||
systemManagement, tenantAware);
|
||||
tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
filterChain.add(securityHeaderFilter);
|
||||
|
||||
final ControllerPreAuthenticateSecurityTokenFilter securityTokenFilter = new ControllerPreAuthenticateSecurityTokenFilter(
|
||||
systemManagement, controllerManagement, tenantAware);
|
||||
tenantConfigurationManagement, controllerManagement, tenantAware, systemSecurityContext);
|
||||
filterChain.add(securityTokenFilter);
|
||||
|
||||
filterChain.add(new CoapAnonymousPreAuthenticatedFilter());
|
||||
@@ -138,12 +142,15 @@ public class AmqpControllerAuthentfication {
|
||||
this.ddiSecruityProperties = secruityProperties;
|
||||
}
|
||||
|
||||
public void setSystemManagement(final SystemManagement systemManagement) {
|
||||
this.systemManagement = systemManagement;
|
||||
public void setTenantConfigurationManagement(final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
}
|
||||
|
||||
public void setTenantAware(final TenantAware tenantAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
void setSystemSecurityContext(final SystemSecurityContext systemSecurityContext) {
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,10 +22,12 @@ import org.eclipse.hawkbit.dmf.json.model.DownloadResponse;
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.security.DdiSecurityProperties;
|
||||
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.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -56,9 +58,15 @@ public class AmqpControllerAuthenticationTest {
|
||||
private static String CONTROLLLER_ID = "123";
|
||||
private AmqpMessageHandlerService amqpMessageHandlerService;
|
||||
private MessageConverter messageConverter;
|
||||
private SystemManagement systemManagement;
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
private AmqpControllerAuthentfication authenticationManager;
|
||||
|
||||
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_FALSE = TenantConfigurationValue
|
||||
.<Boolean> builder().value(Boolean.FALSE).build();
|
||||
|
||||
private static final TenantConfigurationValue<Boolean> CONFIG_VALUE_TRUE = TenantConfigurationValue
|
||||
.<Boolean> builder().value(Boolean.TRUE).build();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
messageConverter = new Jackson2JsonMessageConverter();
|
||||
@@ -74,16 +82,22 @@ public class AmqpControllerAuthenticationTest {
|
||||
when(secruityProperties.getRp()).thenReturn(rp);
|
||||
when(rp.getSslIssuerHashHeader()).thenReturn("X-Ssl-Issuer-Hash-%d");
|
||||
authenticationManager.setSecruityProperties(secruityProperties);
|
||||
systemManagement = mock(SystemManagement.class);
|
||||
authenticationManager.setSystemManagement(systemManagement);
|
||||
when(systemManagement.getConfigurationValue(any(), any())).thenReturn(Boolean.FALSE);
|
||||
|
||||
tenantConfigurationManagement = mock(TenantConfigurationManagement.class);
|
||||
authenticationManager.setTenantConfigurationManagement(tenantConfigurationManagement);
|
||||
|
||||
when(tenantConfigurationManagement.getConfigurationValue(any(), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_FALSE);
|
||||
|
||||
final ControllerManagement controllerManagement = mock(ControllerManagement.class);
|
||||
when(controllerManagement.getSecurityTokenByControllerId(anyString())).thenReturn(CONTROLLLER_ID);
|
||||
authenticationManager.setControllerManagement(controllerManagement);
|
||||
amqpMessageHandlerService.setArtifactManagement(mock(ArtifactManagement.class));
|
||||
|
||||
authenticationManager.setTenantAware(new SecurityContextTenantAware());
|
||||
final SecurityContextTenantAware tenantAware = new SecurityContextTenantAware();
|
||||
authenticationManager.setTenantAware(tenantAware);
|
||||
final SystemSecurityContext systemSecurityContext = new SystemSecurityContext(tenantAware);
|
||||
authenticationManager.setSystemSecurityContext(systemSecurityContext);
|
||||
authenticationManager.postConstruct();
|
||||
amqpMessageHandlerService.setAuthenticationManager(authenticationManager);
|
||||
}
|
||||
@@ -105,9 +119,9 @@ public class AmqpControllerAuthenticationTest {
|
||||
@Description("Tests authentication manager without wrong credential")
|
||||
public void testAuthenticationBadCredantialsWithWrongCredential() {
|
||||
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345");
|
||||
when(systemManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), any()))
|
||||
.thenReturn(Boolean.TRUE);
|
||||
when(tenantConfigurationManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_TRUE);
|
||||
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
|
||||
try {
|
||||
authenticationManager.doAuthenticate(securityToken);
|
||||
@@ -122,9 +136,9 @@ public class AmqpControllerAuthenticationTest {
|
||||
@Description("Tests authentication successfull")
|
||||
public void testSuccessfullAuthentication() {
|
||||
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345");
|
||||
when(systemManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), any()))
|
||||
.thenReturn(Boolean.TRUE);
|
||||
when(tenantConfigurationManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_TRUE);
|
||||
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
|
||||
final Authentication authentication = authenticationManager.doAuthenticate(securityToken);
|
||||
assertThat(authentication).isNotNull();
|
||||
@@ -154,9 +168,9 @@ public class AmqpControllerAuthenticationTest {
|
||||
public void testAuthenticationMessageBadCredantialsWithWrongCredential() {
|
||||
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
|
||||
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345");
|
||||
when(systemManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), any()))
|
||||
.thenReturn(Boolean.TRUE);
|
||||
when(tenantConfigurationManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_TRUE);
|
||||
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken 12" + CONTROLLLER_ID);
|
||||
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
|
||||
messageProperties);
|
||||
@@ -176,9 +190,9 @@ public class AmqpControllerAuthenticationTest {
|
||||
public void testSuccessfullMessageAuthentication() {
|
||||
final MessageProperties messageProperties = createMessageProperties(MessageType.AUTHENTIFICATION);
|
||||
final TenantSecruityToken securityToken = new TenantSecruityToken(TENANT, CONTROLLLER_ID, "12345");
|
||||
when(systemManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), any()))
|
||||
.thenReturn(Boolean.TRUE);
|
||||
when(tenantConfigurationManagement.getConfigurationValue(
|
||||
eq(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED), eq(Boolean.class)))
|
||||
.thenReturn(CONFIG_VALUE_TRUE);
|
||||
securityToken.getHeaders().put(TenantSecruityToken.AUTHORIZATION_HEADER, "TargetToken " + CONTROLLLER_ID);
|
||||
final Message message = amqpMessageHandlerService.getMessageConverter().toMessage(securityToken,
|
||||
messageProperties);
|
||||
|
||||
@@ -18,7 +18,7 @@ import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -55,8 +55,9 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
|
||||
|
||||
private static final String CONTROLLER_DL_REQUEST_ANT_PATTERN = "/{" + TENANT_PLACE_HOLDER
|
||||
+ "}/controller/artifacts/v1/**";
|
||||
protected SystemManagement systemManagement;
|
||||
protected TenantConfigurationManagement tenantConfigurationManagement;
|
||||
protected TenantAware tenantAware;
|
||||
protected SystemSecurityContext systemSecurityContext;
|
||||
|
||||
private final AntPathMatcher pathExtractor;
|
||||
|
||||
@@ -70,10 +71,11 @@ public abstract class AbstractHttpControllerAuthenticationFilter extends Abstrac
|
||||
* @param tenantAware
|
||||
* the tenant aware service
|
||||
*/
|
||||
public AbstractHttpControllerAuthenticationFilter(final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
this.systemManagement = systemManagement;
|
||||
public AbstractHttpControllerAuthenticationFilter(final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
this.tenantAware = tenantAware;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
pathExtractor = new AntPathMatcher();
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ public class HttpControllerPreAuthenticateSecurityTokenFilter extends AbstractHt
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param systemManagement
|
||||
* @param tenantConfigurationManagement
|
||||
* the system management service to retrieve configuration
|
||||
* properties
|
||||
* @param tenantAware
|
||||
@@ -44,16 +44,20 @@ public class HttpControllerPreAuthenticateSecurityTokenFilter extends AbstractHt
|
||||
* @param controllerManagement
|
||||
* the controller management to retrieve the specific target
|
||||
* security token to verify
|
||||
* @param systemSecurityContext
|
||||
* the system security context
|
||||
*/
|
||||
public HttpControllerPreAuthenticateSecurityTokenFilter(final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware, final ControllerManagement controllerManagement) {
|
||||
super(systemManagement, tenantAware);
|
||||
public HttpControllerPreAuthenticateSecurityTokenFilter(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
|
||||
final ControllerManagement controllerManagement, final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
this.controllerManagement = controllerManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreAuthenficationFilter createControllerAuthenticationFilter() {
|
||||
return new ControllerPreAuthenticateSecurityTokenFilter(systemManagement, controllerManagement, tenantAware);
|
||||
return new ControllerPreAuthenticateSecurityTokenFilter(tenantConfigurationManagement, controllerManagement,
|
||||
tenantAware, systemSecurityContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
|
||||
/**
|
||||
@@ -27,21 +27,25 @@ public class HttpControllerPreAuthenticatedGatewaySecurityTokenFilter
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param systemManagement
|
||||
* @param tenantConfigurationManagement
|
||||
* the system management service to retrieve configuration
|
||||
* properties
|
||||
* @param tenantAware
|
||||
* the tenant aware service to get configuration for the specific
|
||||
* tenant
|
||||
* @param systemSecurityContext
|
||||
* * @param systemSecurityContext the system security context
|
||||
*/
|
||||
public HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
super(systemManagement, tenantAware);
|
||||
public HttpControllerPreAuthenticatedGatewaySecurityTokenFilter(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PreAuthenficationFilter createControllerAuthenticationFilter() {
|
||||
return new ControllerPreAuthenticatedGatewaySecurityTokenFilter(systemManagement, tenantAware);
|
||||
return new ControllerPreAuthenticatedGatewaySecurityTokenFilter(tenantConfigurationManagement, tenantAware,
|
||||
systemSecurityContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
|
||||
/**
|
||||
@@ -35,18 +35,20 @@ public class HttpControllerPreAuthenticatedSecurityHeaderFilter extends Abstract
|
||||
* @param caAuthorityNameHeader
|
||||
* the http-header which holds the ca-authority name of the
|
||||
* certificate
|
||||
* @param systemManagement
|
||||
* the system management service to retrieve configuration
|
||||
* properties to check if the header authentication is enabled
|
||||
* for this tenant
|
||||
* @param tenantConfigurationManagement
|
||||
* the tenant configuration management service to retrieve
|
||||
* configuration properties to check if the header authentication
|
||||
* is enabled for this tenant
|
||||
* @param tenantAware
|
||||
* the tenant aware service to get configuration for the specific
|
||||
* tenant
|
||||
* @param systemSecurityContext
|
||||
* the system security context
|
||||
*/
|
||||
public HttpControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
|
||||
final String caAuthorityNameHeader, final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
super(systemManagement, tenantAware);
|
||||
final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
this.caCommonNameHeader = caCommonNameHeader;
|
||||
this.caAuthorityNameHeader = caAuthorityNameHeader;
|
||||
}
|
||||
@@ -54,7 +56,7 @@ public class HttpControllerPreAuthenticatedSecurityHeaderFilter extends Abstract
|
||||
@Override
|
||||
protected PreAuthenficationFilter createControllerAuthenticationFilter() {
|
||||
return new ControllerPreAuthenticatedSecurityHeaderFilter(caCommonNameHeader, caAuthorityNameHeader,
|
||||
systemManagement, tenantAware);
|
||||
tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,17 +14,15 @@ import java.util.Map;
|
||||
import org.eclipse.hawkbit.aspects.ExceptionMappingAspectHandler;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.helper.AfterTransactionCommitExecutorHolder;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.helper.CacheManagerHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SecurityTokenGeneratorHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.SystemManagementHolder;
|
||||
import org.eclipse.hawkbit.repository.model.helper.TenantAwareHolder;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -51,21 +49,13 @@ import org.springframework.validation.beanvalidation.MethodValidationPostProcess
|
||||
public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
|
||||
/**
|
||||
* @return simple default {@link AsyncUncaughtExceptionHandler}
|
||||
* implementation
|
||||
* @Bean public SimpleAsyncUncaughtExceptionHandler
|
||||
* simpleAsyncUncaughtExceptionHandler() { return new
|
||||
* SimpleAsyncUncaughtExceptionHandler(); }
|
||||
*
|
||||
* /**
|
||||
* @return the {@link PollConfigurationHelper} singleton bean which holds
|
||||
* the polling and polling overdue configuration and make it
|
||||
* accessible in beans which cannot not be autowired or retrieve
|
||||
* environment variables due {@link EnvironmentAware} interface.
|
||||
* @return the {@link TenantConfigurationManagement} singleton bean which
|
||||
* make it accessible in beans which cannot access the service
|
||||
* directly, e.g. JPA entities.
|
||||
*/
|
||||
@Bean
|
||||
public PollConfigurationHelper pollConfigurationHelper() {
|
||||
return PollConfigurationHelper.getInstance();
|
||||
public TenantConfigurationManagement tenantConfigurationManagement() {
|
||||
return TenantConfigurationManagement.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,5 +171,4 @@ public class RepositoryApplicationConfiguration extends JpaBaseConfiguration {
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return new MultiTenantJpaTransactionManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@ 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.Target_;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.security.HawkbitSecurityProperties;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -86,6 +88,33 @@ public class ControllerManagement {
|
||||
@Autowired
|
||||
private HawkbitSecurityProperties securityProperties;
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
/**
|
||||
* Retrieves all {@link SoftwareModule}s which are assigned to the given
|
||||
* {@link DistributionSet}.
|
||||
*
|
||||
* @param distributionSet
|
||||
* the distribution set which should be assigned to the returned
|
||||
* {@link SoftwareModule}s
|
||||
* @return a list of {@link SoftwareModule}s assigned to given
|
||||
* {@code distributionSet}
|
||||
*/
|
||||
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER)
|
||||
public String findPollingTime() {
|
||||
final TenantConfigurationKey configurationKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
|
||||
final Class<String> propertyType = String.class;
|
||||
tenantConfigurationManagement.validateTenantConfigurationDataType(configurationKey, propertyType);
|
||||
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||
.findByKey(configurationKey.getKeyName());
|
||||
return tenantConfigurationManagement
|
||||
.buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the time of the last time the controller has been connected to
|
||||
* the server.
|
||||
|
||||
@@ -22,10 +22,8 @@ import org.eclipse.hawkbit.report.model.SystemUsageReport;
|
||||
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.persistence.config.PersistenceUnitProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
@@ -33,12 +31,7 @@ import org.springframework.cache.annotation.CachePut;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.cache.interceptor.SimpleKeyGenerator;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
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.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -53,7 +46,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
@Service
|
||||
public class SystemManagement implements EnvironmentAware {
|
||||
public class SystemManagement {
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
@@ -113,10 +106,6 @@ public class SystemManagement implements EnvironmentAware {
|
||||
|
||||
private final ThreadLocal<String> createInitialTenant = new ThreadLocal<>();
|
||||
|
||||
private final ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Calculated system usage statistics, both overall for the entire system
|
||||
* and per tenant;
|
||||
@@ -320,88 +309,6 @@ public class SystemManagement implements EnvironmentAware {
|
||||
return tenantMetaDataRepository.save(metaData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the key of the configuration
|
||||
* @param propertyType
|
||||
* the type of the configuration value, e.g. {@code String.class}
|
||||
* , {@code Integer.class}, etc
|
||||
* @return the converted configuration value either from the tenant specific
|
||||
* configuration stored or from the fallback default values or
|
||||
* {@code null} in case key has not been configured and not default
|
||||
* value exists
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
public <T> T getConfigurationValue(final TenantConfigurationKey configurationKey, final Class<T> propertyType) {
|
||||
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||
.findByKey(configurationKey.getKeyName());
|
||||
if (tenantConfiguration != null) {
|
||||
return conversionService.convert(tenantConfiguration.getValue(), propertyType);
|
||||
} else if (configurationKey.getDefaultKeyName() != null) {
|
||||
final T defaultKeyNameValue = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType);
|
||||
return defaultKeyNameValue != null ? defaultKeyNameValue
|
||||
: conversionService.convert(configurationKey.getDefaultValue(), propertyType);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a specific configuration for a specific tenant.
|
||||
*
|
||||
* @param tenantConf
|
||||
* the tenant configuration object which contains the key and
|
||||
* value of the specific configuration to update
|
||||
* @return the added or updated TenantConfiguration
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#tenantConf.getKey()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
public TenantConfiguration addOrUpdateConfiguration(final TenantConfiguration tenantConf) {
|
||||
TenantConfiguration tenantConfiguration = tenantConfigurationRepository.findByKey(tenantConf.getKey());
|
||||
if (tenantConfiguration != null) {
|
||||
tenantConfiguration.setValue(tenantConf.getValue());
|
||||
} else {
|
||||
tenantConfiguration = new TenantConfiguration(tenantConf.getKey(), tenantConf.getValue());
|
||||
}
|
||||
return tenantConfigurationRepository.save(tenantConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific configuration for the current tenant.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the configuration key to be deleted
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
public void deleteConfiguration(final TenantConfigurationKey configurationKey) {
|
||||
tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<TenantConfiguration> getTenantConfigurations() {
|
||||
return tenantConfigurationRepository.findAll();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.context.EnvironmentAware#setEnvironment(org.
|
||||
* springframework.core.env. Environment)
|
||||
*/
|
||||
@Override
|
||||
public void setEnvironment(final Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
private DistributionSetType createStandardSoftwareDataSetup() {
|
||||
|
||||
// Edge Controller Linux standard setup
|
||||
@@ -458,7 +365,5 @@ public class SystemManagement implements EnvironmentAware {
|
||||
return SimpleKeyGenerator.generateKey(initialTenantCreation.toUpperCase(),
|
||||
initialTenantCreation.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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.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.ConversionFailedException;
|
||||
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.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Central tenant configuration management operations of the SP server.
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
@Validated
|
||||
public class TenantConfigurationManagement implements EnvironmentAware {
|
||||
|
||||
private static final TenantConfigurationManagement INSTANCE = new TenantConfigurationManagement();
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationRepository tenantConfigurationRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private final ConfigurableConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Get Singleton instance, needed for classes which are not managed in
|
||||
* Spring context
|
||||
*
|
||||
* @return singleton instance of TenantConfigurationManagement
|
||||
*/
|
||||
public static TenantConfigurationManagement getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <T>
|
||||
* the type of the configuration value
|
||||
* @param configurationKey
|
||||
* the key of the configuration
|
||||
* @param propertyType
|
||||
* the type of the configuration value, e.g. {@code String.class}
|
||||
* , {@code Integer.class}, etc
|
||||
* @return the converted configuration value either from the tenant specific
|
||||
* configuration stored or from the fallback default values or
|
||||
* {@code null} in case key has not been configured and not default
|
||||
* value exists
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* if the {@code propertyType} and the value in general does not
|
||||
* match the expected type and format defined by the Key
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
|
||||
@Cacheable(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION + SpringEvalExpressions.HAS_AUTH_OR
|
||||
+ SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||
public <T> TenantConfigurationValue<T> getConfigurationValue(final TenantConfigurationKey configurationKey,
|
||||
final Class<T> propertyType) {
|
||||
validateTenantConfigurationDataType(configurationKey, propertyType);
|
||||
|
||||
final TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||
.findByKey(configurationKey.getKeyName());
|
||||
|
||||
return buildTenantConfigurationValueByKey(configurationKey, propertyType, tenantConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the data type of the tenant configuration. If it is possible to
|
||||
* cast to the given data type.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the key
|
||||
* @param propertyType
|
||||
* the class
|
||||
*/
|
||||
protected <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.",
|
||||
configurationKey.getDataType(), propertyType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the tenant configuration by the given key
|
||||
*
|
||||
* @param configurationKey
|
||||
* the key
|
||||
* @param propertyType
|
||||
* the property type
|
||||
* @param tenantConfiguration
|
||||
* the configuration
|
||||
* @return <null> if no default value is set and no database value available
|
||||
* or returns the tenant configuration value
|
||||
*/
|
||||
protected <T> TenantConfigurationValue<T> buildTenantConfigurationValueByKey(
|
||||
final TenantConfigurationKey configurationKey, final Class<T> propertyType,
|
||||
final TenantConfiguration tenantConfiguration) {
|
||||
if (tenantConfiguration != null) {
|
||||
return TenantConfigurationValue.<T> builder().isGlobal(false).createdBy(tenantConfiguration.getCreatedBy())
|
||||
.createdAt(tenantConfiguration.getCreatedAt())
|
||||
.lastModifiedAt(tenantConfiguration.getLastModifiedAt())
|
||||
.lastModifiedBy(tenantConfiguration.getLastModifiedBy())
|
||||
.value(conversionService.convert(tenantConfiguration.getValue(), propertyType)).build();
|
||||
|
||||
} else if (configurationKey.getDefaultKeyName() != null) {
|
||||
|
||||
return TenantConfigurationValue.<T> builder().isGlobal(true).createdBy(null).createdAt(null)
|
||||
.lastModifiedAt(null).lastModifiedBy(null)
|
||||
.value(getGlobalConfigurationValue(configurationKey, propertyType)).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the key of the configuration
|
||||
* @return the converted configuration value either from the tenant specific
|
||||
* configuration stored or from the fallback default values or
|
||||
* {@code null} in case key has not been configured and not default
|
||||
* value exists
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* if the {@code propertyType} and the value in general does not
|
||||
* match the expected type and format defined by the Key
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
public TenantConfigurationValue<?> getConfigurationValue(final TenantConfigurationKey configurationKey) {
|
||||
return getConfigurationValue(configurationKey, configurationKey.getDataType());
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the global configuration property either defined in the property
|
||||
* file or an default value otherwise.
|
||||
*
|
||||
* @param <T>
|
||||
* the type of the configuration value
|
||||
* @param configurationKey
|
||||
* the key of the configuration
|
||||
* @param propertyType
|
||||
* the type of the configuration value, e.g. {@code String.class}
|
||||
* , {@code Integer.class}, etc
|
||||
* @return the global configured value
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* if the {@code propertyType} and the value in the property
|
||||
* file or the default value does not match the expected type
|
||||
* and format defined by the Key
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
* {@code propertyType}
|
||||
*/
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
public <T> T getGlobalConfigurationValue(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.",
|
||||
configurationKey.getDataType(), propertyType));
|
||||
}
|
||||
|
||||
final T valueInProperties = environment.getProperty(configurationKey.getDefaultKeyName(), propertyType);
|
||||
|
||||
if (valueInProperties == null) {
|
||||
return conversionService.convert(configurationKey.getDefaultValue(), propertyType);
|
||||
}
|
||||
|
||||
return valueInProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a specific configuration for a specific tenant.
|
||||
*
|
||||
*
|
||||
* @param configurationKey
|
||||
* the key of the configuration
|
||||
* @param value
|
||||
* the configuration value which will be written into the
|
||||
* database.
|
||||
* @return the configuration value which was just written into the database.
|
||||
* @throws TenantConfigurationValidatorException
|
||||
* if the {@code propertyType} and the value in general does not
|
||||
* match the expected type and format defined by the Key
|
||||
* @throws ConversionFailedException
|
||||
* if the property cannot be converted to the given
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
public <T> TenantConfigurationValue<T> addOrUpdateConfiguration(final TenantConfigurationKey configurationKey,
|
||||
final T value) {
|
||||
|
||||
if (!configurationKey.getDataType().isAssignableFrom(value.getClass())) {
|
||||
throw new TenantConfigurationValidatorException(String.format(
|
||||
"Cannot parse the value %s of type %s into the type %s defined by the configuration key.", value,
|
||||
value.getClass(), configurationKey.getDataType()));
|
||||
}
|
||||
|
||||
configurationKey.validate(applicationContext, value);
|
||||
|
||||
TenantConfiguration tenantConfiguration = tenantConfigurationRepository
|
||||
.findByKey(configurationKey.getKeyName());
|
||||
|
||||
if (tenantConfiguration == null) {
|
||||
tenantConfiguration = new TenantConfiguration(configurationKey.getKeyName(), value.toString());
|
||||
} else {
|
||||
tenantConfiguration.setValue(value.toString());
|
||||
}
|
||||
|
||||
final TenantConfiguration updatedTenantConfiguration = tenantConfigurationRepository.save(tenantConfiguration);
|
||||
|
||||
final Class<T> clazzT = (Class<T>) value.getClass();
|
||||
|
||||
return TenantConfigurationValue.<T> builder().isGlobal(false)
|
||||
.createdBy(updatedTenantConfiguration.getCreatedBy())
|
||||
.createdAt(updatedTenantConfiguration.getCreatedAt())
|
||||
.lastModifiedAt(updatedTenantConfiguration.getLastModifiedAt())
|
||||
.lastModifiedBy(updatedTenantConfiguration.getLastModifiedBy())
|
||||
.value(conversionService.convert(updatedTenantConfiguration.getValue(), clazzT)).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a specific configuration for the current tenant. Does nothing in
|
||||
* case there is no tenant specific configuration value.
|
||||
*
|
||||
* @param configurationKey
|
||||
* the configuration key to be deleted
|
||||
*/
|
||||
@CacheEvict(value = "tenantConfiguration", key = "#configurationKey.getKeyName()")
|
||||
@Transactional
|
||||
@Modifying
|
||||
@PreAuthorize(value = SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||
public void deleteConfiguration(final TenantConfigurationKey configurationKey) {
|
||||
tenantConfigurationRepository.deleteByKey(configurationKey.getKeyName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(final Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,9 @@ import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import org.eclipse.hawkbit.repository.model.helper.PollConfigurationHelper;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.persistence.annotations.CascadeOnDelete;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -110,7 +112,7 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
@CollectionTable(name = "sp_target_attributes", joinColumns = {
|
||||
@JoinColumn(name = "target_id") }, foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "fk_targ_attrib_target"))
|
||||
// use deprecated annotation until HHH-8862 is fixed
|
||||
@SuppressWarnings("deprecation")
|
||||
|
||||
// @org.hibernate.annotations.ForeignKey( name = "fk_targ_attrib_target" )
|
||||
private final Map<String, String> controllerAttributes = Collections.synchronizedMap(new HashMap<String, String>());
|
||||
|
||||
@@ -120,6 +122,9 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
@Column(name = "request_controller_attributes", nullable = false)
|
||||
private boolean requestControllerAttributes = true;
|
||||
|
||||
@Transient
|
||||
private final DurationHelper durationHelper = new DurationHelper();
|
||||
|
||||
/**
|
||||
* Constructor for {@link TargetStatus}.
|
||||
*
|
||||
@@ -181,7 +186,7 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ipAddress
|
||||
* @param address
|
||||
* the ipAddress to set
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
@@ -315,17 +320,21 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
* before this method returns {@code null}
|
||||
*/
|
||||
public PollStatus getPollStatus() {
|
||||
if (lastTargetQuery != null) {
|
||||
final Duration pollTime = PollConfigurationHelper.getInstance().getPollTimeInterval();
|
||||
final Duration overdueTime = PollConfigurationHelper.getInstance().getOverduePollTimeInterval();
|
||||
final LocalDateTime currentDate = LocalDateTime.now();
|
||||
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
|
||||
ZoneId.systemDefault());
|
||||
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
|
||||
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
|
||||
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
|
||||
if (lastTargetQuery == null) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
|
||||
final Duration pollTime = durationHelper.formattedStringToDuration(TenantConfigurationManagement.getInstance()
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class).getValue());
|
||||
final Duration overdueTime = durationHelper.formattedStringToDuration(TenantConfigurationManagement
|
||||
.getInstance().getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class)
|
||||
.getValue());
|
||||
final LocalDateTime currentDate = LocalDateTime.now();
|
||||
final LocalDateTime lastPollDate = LocalDateTime.ofInstant(Instant.ofEpochMilli(lastTargetQuery),
|
||||
ZoneId.systemDefault());
|
||||
final LocalDateTime nextPollDate = lastPollDate.plus(pollTime);
|
||||
final LocalDateTime overdueDate = nextPollDate.plus(overdueTime);
|
||||
return new PollStatus(lastPollDate, nextPollDate, overdueDate, currentDate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -368,16 +377,10 @@ public class TargetInfo implements Persistable<Long>, Serializable {
|
||||
return lastPollDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nextPollDate
|
||||
*/
|
||||
public LocalDateTime getNextPollDate() {
|
||||
return nextPollDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the overdueDate
|
||||
*/
|
||||
public LocalDateTime getOverdueDate() {
|
||||
return overdueDate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/**
|
||||
* 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.model;
|
||||
|
||||
/**
|
||||
* represents a tenant configuration value including some meta data
|
||||
*
|
||||
* @param <T>
|
||||
* type of the configuration value
|
||||
*/
|
||||
public class TenantConfigurationValue<T> {
|
||||
|
||||
private T value;
|
||||
private Long lastModifiedAt;
|
||||
private String lastModifiedBy;
|
||||
private Long createdAt;
|
||||
private String createdBy;
|
||||
private boolean isGlobal = true;
|
||||
|
||||
private TenantConfigurationValue() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if is global.
|
||||
*
|
||||
* @return true, if is global
|
||||
*/
|
||||
public boolean isGlobal() {
|
||||
return isGlobal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified at.
|
||||
*
|
||||
* @return the last modified at
|
||||
*/
|
||||
public Long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the last modified by.
|
||||
*
|
||||
* @return the last modified by
|
||||
*/
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the created at.
|
||||
*
|
||||
* @return the created at
|
||||
*/
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the created by.
|
||||
*
|
||||
* @return the created by
|
||||
*/
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder.
|
||||
*
|
||||
* @param <K>
|
||||
* the key type
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public static <K> TenantConfigurationValueBuilder<K> builder() {
|
||||
|
||||
return new TenantConfigurationValueBuilder<K>();
|
||||
}
|
||||
|
||||
/**
|
||||
* builds the tenant configuration value including some meta data
|
||||
*
|
||||
* @param <T>
|
||||
* type of the configuration value
|
||||
*/
|
||||
public static class TenantConfigurationValueBuilder<T> {
|
||||
|
||||
private final TenantConfigurationValue<T> configuration = new TenantConfigurationValue<>();
|
||||
|
||||
/**
|
||||
* Builds the.
|
||||
*
|
||||
* @return the tenant configuration value
|
||||
*/
|
||||
public TenantConfigurationValue<T> build() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the configuration value itself
|
||||
*
|
||||
* @param value
|
||||
* the value
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> value(final T value) {
|
||||
this.configuration.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the is global attribute.
|
||||
*
|
||||
* @param isGlobal
|
||||
* true when there is no tenant specific value, false
|
||||
* otherwise
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> isGlobal(final boolean isGlobal) {
|
||||
this.configuration.isGlobal = isGlobal;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last modified at attribute
|
||||
*
|
||||
* @param lastModifiedAt
|
||||
* timestamp of last modification
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> lastModifiedAt(final Long lastModifiedAt) {
|
||||
this.configuration.lastModifiedAt = lastModifiedAt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the last modified by attribute
|
||||
*
|
||||
* @param lastModifiedBy
|
||||
* the last modified by
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> lastModifiedBy(final String lastModifiedBy) {
|
||||
this.configuration.lastModifiedBy = lastModifiedBy;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the created at attribute
|
||||
*
|
||||
* @param createdAt
|
||||
* defined when the configuration has been created
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> createdAt(final Long createdAt) {
|
||||
this.configuration.createdAt = createdAt;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the created by attribute
|
||||
*
|
||||
* @param createdBy
|
||||
* defines by whom the configuration has been created
|
||||
* @return the tenant configuration value builder
|
||||
*/
|
||||
public TenantConfigurationValueBuilder<T> createdBy(final String createdBy) {
|
||||
this.configuration.createdBy = createdBy;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,113 +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.repository.model.helper;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
|
||||
/**
|
||||
* A singleton bean which holds configuration of the poll time
|
||||
* {@code hawkbit.server.controller.polling} and
|
||||
* {@code hawkbit.server.controller.polling.overdue} to have access to the
|
||||
* configuration in beans not instatinated by spring e.g. JPA entities which
|
||||
* cannot implement the {@link EnvironmentAware} interface to retrieve
|
||||
* environment variables.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public final class PollConfigurationHelper {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PollConfigurationHelper.class);
|
||||
private static final PollConfigurationHelper INSTANCE = new PollConfigurationHelper();
|
||||
|
||||
private static final int DEFAULT_OVERDUE_HOUR = 0;
|
||||
private static final int DEFAULT_OVERDUE_MINUTE = 5;
|
||||
private static final int DEFAULT_OVERDUE_SECOND = 0;
|
||||
|
||||
private static final int DEFAULT_POLL_HOUR = 0;
|
||||
private static final int DEFAULT_POLL_MINUTE = 5;
|
||||
private static final int DEFAULT_POLL_SECOND = 0;
|
||||
|
||||
@Autowired
|
||||
private ControllerPollProperties controllerPollProperties;
|
||||
|
||||
private Duration controllerPollTimeDuration;
|
||||
private Duration controllerOverduePollTimeDuration;
|
||||
|
||||
private PollConfigurationHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean post construct to calcualte the poll time and poll overdue time only
|
||||
* once.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
final long[] controllerPollTimeSplit = splitInterval(controllerPollProperties.getPollingTime(),
|
||||
DEFAULT_POLL_HOUR, DEFAULT_POLL_MINUTE, DEFAULT_POLL_SECOND);
|
||||
this.controllerPollTimeDuration = Duration.ZERO.plusHours(controllerPollTimeSplit[0])
|
||||
.plusMinutes(controllerPollTimeSplit[1]).plusSeconds(controllerPollTimeSplit[2]);
|
||||
|
||||
final long[] controllerOverduePollTimeSplit = splitInterval(controllerPollProperties.getPollingOverdueTime(),
|
||||
DEFAULT_OVERDUE_HOUR, DEFAULT_OVERDUE_MINUTE, DEFAULT_OVERDUE_SECOND);
|
||||
this.controllerOverduePollTimeDuration = Duration.ZERO.plusHours(controllerOverduePollTimeSplit[0])
|
||||
.plusMinutes(controllerOverduePollTimeSplit[1]).plusSeconds(controllerOverduePollTimeSplit[2]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the poll time interval configured in the configuration
|
||||
* {@code hawkbit.server.controller.polling} or the default value
|
||||
* which is {@code 00:05:00} never {@code null}.
|
||||
*/
|
||||
public Duration getPollTimeInterval() {
|
||||
return controllerPollTimeDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the overdue poll threshold configured in the configuration
|
||||
* {@code hawkbit.server.controller.polling.overdue} or the default
|
||||
* value which is {@code 00:05:00} never {@code null}.
|
||||
*/
|
||||
public Duration getOverduePollTimeInterval() {
|
||||
return controllerOverduePollTimeDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a singleton instance of the environment helper.
|
||||
*/
|
||||
public static PollConfigurationHelper getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private long[] splitInterval(final String interval, final long defaultHour, final long defaultMinute,
|
||||
final long defaultSecond) {
|
||||
if (interval != null) {
|
||||
final String[] split = interval.split(":");
|
||||
if (split.length == 3) {
|
||||
try {
|
||||
return new long[] { Long.parseLong(split[0]), Long.parseLong(split[1]), Long.parseLong(split[2]) };
|
||||
} catch (final NumberFormatException e) {
|
||||
LOG.warn("Cannot parse the given poll configuration {}", interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG.warn("Using default configuration hour:{} min:{}, second:{}", defaultHour, defaultMinute, defaultSecond);
|
||||
return new long[] { defaultHour, defaultMinute, defaultSecond };
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ import org.eclipse.hawkbit.repository.TargetInfoRepository;
|
||||
import org.eclipse.hawkbit.repository.TargetManagement;
|
||||
import org.eclipse.hawkbit.repository.TargetRepository;
|
||||
import org.eclipse.hawkbit.repository.TargetTagRepository;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantMetaDataRepository;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSetType;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModuleType;
|
||||
@@ -180,6 +181,10 @@ public abstract class AbstractIntegrationTest implements EnvironmentAware {
|
||||
|
||||
@Autowired
|
||||
protected TenantAwareCacheManager cacheManager;
|
||||
|
||||
@Autowired
|
||||
protected TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
|
||||
@Autowired
|
||||
protected RolloutManagement rolloutManagement;
|
||||
|
||||
@@ -47,7 +47,7 @@ import com.mongodb.MongoClientOptions;
|
||||
*/
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ, proxyTargetClass = true, securedEnabled = true)
|
||||
@EnableConfigurationProperties({ DdiSecurityProperties.class, ControllerPollProperties.class })
|
||||
@EnableConfigurationProperties({ HawkbitServerProperties.class, DdiSecurityProperties.class })
|
||||
@Profile("test")
|
||||
public class TestConfiguration implements AsyncConfigurer {
|
||||
|
||||
|
||||
@@ -21,10 +21,7 @@ import org.eclipse.hawkbit.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
@@ -151,91 +148,4 @@ public class SystemManagementTest extends AbstractIntegrationTestWithMongoDB {
|
||||
});
|
||||
}
|
||||
|
||||
@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 storeTenantSpecificConfiguration() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
|
||||
final String envPropertyDefault = environment.getProperty(configKey.getDefaultKeyName());
|
||||
assertThat(envPropertyDefault).isNotNull();
|
||||
|
||||
// get the configuration from the system management
|
||||
final String defaultConfigValue = systemManagement.getConfigurationValue(configKey, String.class);
|
||||
assertThat(envPropertyDefault).isEqualTo(defaultConfigValue);
|
||||
|
||||
// update the tenant specific configuration
|
||||
final String newConfigurationValue = "thisIsAnotherValueForPolling";
|
||||
assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue);
|
||||
systemManagement
|
||||
.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), newConfigurationValue));
|
||||
|
||||
// verify that new configuration value is used
|
||||
final String updatedConfigurationValue = systemManagement.getConfigurationValue(configKey, String.class);
|
||||
assertThat(updatedConfigurationValue).isEqualTo(newConfigurationValue);
|
||||
assertThat(systemManagement.getTenantConfigurations()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests that the tenant specific configuration can be updated")
|
||||
public void updateTenantSpecifcConfiguration() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
|
||||
final String value1 = "firstValue";
|
||||
final String value2 = "secondValue";
|
||||
|
||||
// add value first
|
||||
systemManagement.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), value1));
|
||||
assertThat(systemManagement.getConfigurationValue(configKey, String.class)).isEqualTo(value1);
|
||||
|
||||
// update to value second
|
||||
systemManagement.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), value2));
|
||||
assertThat(systemManagement.getConfigurationValue(configKey, String.class)).isEqualTo(value2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Tests that the configuration value can be converted from String to Integer automatically")
|
||||
public void tenantConfigurationValueConversion() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
|
||||
final Integer value1 = 123;
|
||||
systemManagement
|
||||
.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), String.valueOf(value1)));
|
||||
assertThat(systemManagement.getConfigurationValue(configKey, Integer.class)).isEqualTo(value1);
|
||||
}
|
||||
|
||||
@Test(expected = ConversionFailedException.class)
|
||||
@Description("Tests that the get configuration throws exception in case the value cannot be automatically converted from String to Integer")
|
||||
public void wrongTenantConfigurationValueConversionThrowsException() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED;
|
||||
final String value1 = "thisIsNotANumber";
|
||||
// add value as String
|
||||
systemManagement
|
||||
.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), String.valueOf(value1)));
|
||||
// try to get it as Integer
|
||||
systemManagement.getConfigurationValue(configKey, Integer.class);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
// gateway token does not have default value so no configuration value
|
||||
// is should be available
|
||||
final String defaultConfigValue = systemManagement.getConfigurationValue(configKey, String.class);
|
||||
assertThat(defaultConfigValue).isNull();
|
||||
|
||||
// update the tenant specific configuration
|
||||
final String newConfigurationValue = "thisIsAnotherValueForPolling";
|
||||
assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue);
|
||||
systemManagement
|
||||
.addOrUpdateConfiguration(new TenantConfiguration(configKey.getKeyName(), newConfigurationValue));
|
||||
|
||||
// verify that new configuration value is used
|
||||
final String updatedConfigurationValue = systemManagement.getConfigurationValue(configKey, String.class);
|
||||
assertThat(updatedConfigurationValue).isEqualTo(newConfigurationValue);
|
||||
|
||||
// delete the tenant specific configuration
|
||||
systemManagement.deleteConfiguration(configKey);
|
||||
// ensure that now gateway token is set again, because is deleted and
|
||||
// must be null now
|
||||
assertThat(systemManagement.getConfigurationValue(configKey, String.class)).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.AbstractIntegrationTestWithMongoDB;
|
||||
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.validator.TenantConfigurationValidatorException;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Repository")
|
||||
@Stories("Tenant Configuration Management")
|
||||
public class TenantConfigurationManagementTest extends AbstractIntegrationTestWithMongoDB {
|
||||
|
||||
final DurationHelper durationHelper = new DurationHelper();
|
||||
|
||||
@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());
|
||||
assertThat(envPropertyDefault).isNotNull();
|
||||
|
||||
// get the configuration from the system management
|
||||
final TenantConfigurationValue<String> defaultConfigValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(configKey, String.class);
|
||||
|
||||
assertThat(defaultConfigValue.isGlobal()).isEqualTo(true);
|
||||
assertThat(defaultConfigValue.getValue()).isEqualTo(envPropertyDefault);
|
||||
|
||||
// update the tenant specific configuration
|
||||
final String newConfigurationValue = "thisIsAnotherTokenName";
|
||||
assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue.getValue());
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, newConfigurationValue);
|
||||
|
||||
// verify that new configuration value is used
|
||||
final TenantConfigurationValue<String> updatedConfigurationValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(configKey, String.class);
|
||||
|
||||
assertThat(updatedConfigurationValue.isGlobal()).isEqualTo(false);
|
||||
assertThat(updatedConfigurationValue.getValue()).isEqualTo(newConfigurationValue);
|
||||
// assertThat(tenantConfigurationManagement.getTenantConfigurations()).hasSize(1);
|
||||
}
|
||||
|
||||
@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 value1 = "firstValue";
|
||||
final String value2 = "secondValue";
|
||||
|
||||
// add value first
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue())
|
||||
.isEqualTo(value1);
|
||||
|
||||
// update to value second
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value2);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, String.class).getValue())
|
||||
.isEqualTo(value2);
|
||||
}
|
||||
|
||||
@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 Boolean value1 = true;
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue())
|
||||
.isEqualTo(value1);
|
||||
final Boolean value2 = false;
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value2);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(configKey, Boolean.class).getValue())
|
||||
.isEqualTo(value2);
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 value1 = "thisIsNotABoolean";
|
||||
// add value as String
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, value1);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
// gateway token does not have default value so no configuration value
|
||||
// is should be available
|
||||
final String defaultConfigValue = tenantConfigurationManagement.getConfigurationValue(configKey, String.class)
|
||||
.getValue();
|
||||
assertThat(defaultConfigValue).isNull();
|
||||
|
||||
// update the tenant specific configuration
|
||||
final String newConfigurationValue = "thisIsAnotherValueForPolling";
|
||||
assertThat(newConfigurationValue).isNotEqualTo(defaultConfigValue);
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, newConfigurationValue);
|
||||
|
||||
// verify that new configuration value is used
|
||||
final String updatedConfigurationValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(configKey, String.class).getValue();
|
||||
assertThat(updatedConfigurationValue).isEqualTo(newConfigurationValue);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 Integer wrongDataype = 123;
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype);
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 Integer wrongDataype = 123;
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype);
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 Integer wrongDataype = 123;
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongDataype);
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 wrongFormatted = "wrongFormatted";
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, wrongFormatted);
|
||||
}
|
||||
|
||||
@Test(expected = TenantConfigurationValidatorException.class)
|
||||
@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 tooSmallDuration = durationHelper
|
||||
.durationToFormattedString(durationHelper.getDurationByTimeValues(0, 0, 1));
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey, tooSmallDuration);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Stores a correct formatted PollignTime and reads it again.")
|
||||
public void storesCorrectDurationAsPollingInterval() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
|
||||
|
||||
final Duration duration = durationHelper.getDurationByTimeValues(1, 2, 0);
|
||||
assertThat(duration).isEqualTo(Duration.ofHours(1).plusMinutes(2));
|
||||
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(configKey,
|
||||
durationHelper.durationToFormattedString(duration));
|
||||
|
||||
final String storedDurationString = tenantConfigurationManagement.getConfigurationValue(configKey, String.class)
|
||||
.getValue();
|
||||
assertThat(duration).isEqualTo(durationHelper.formattedStringToDuration(storedDurationString));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Request a config value in a wrong Value")
|
||||
public void requestConfigValueWithWrongType() {
|
||||
try {
|
||||
tenantConfigurationManagement.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL,
|
||||
Object.class);
|
||||
Assert.fail("");
|
||||
} catch (final TenantConfigurationValidatorException e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Verifies that every TenenatConfiguraationKeyName exists only once")
|
||||
public void verifyThatAllKeysAreDifferent() {
|
||||
final Map<String, Void> keynames = new HashMap<String, Void>();
|
||||
|
||||
Arrays.stream(TenantConfigurationKey.values()).forEach(key -> {
|
||||
|
||||
if (keynames.containsKey(key.getKeyName())) {
|
||||
throw new IllegalStateException("The key names are not unique");
|
||||
}
|
||||
|
||||
keynames.put(key.getKeyName(), null);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Get TenantConfigurationKeyByName")
|
||||
public void getTenantConfigurationKeyByName() {
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.POLLING_TIME_INTERVAL;
|
||||
|
||||
assertThat(TenantConfigurationKey.fromKeyName(configKey.getKeyName())).isEqualTo(configKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,6 +11,7 @@ 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
|
||||
|
||||
hawkbit.server.artifact.repo.upload.maxFileSize=5MB
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@ public final class RestConstants {
|
||||
* The target URL mapping rest resource.
|
||||
*/
|
||||
public static final String TARGET_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/targets";
|
||||
|
||||
public static final String SYSTEM_V1_REQUEST_MAPPING = BASE_V1_REQUEST_MAPPING + "/system";
|
||||
/**
|
||||
* The software module URL mapping rest resource.
|
||||
*/
|
||||
|
||||
@@ -11,45 +11,33 @@ package org.eclipse.hawkbit.rest.resource.model.system;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Response body for tenant configuration requests.
|
||||
*
|
||||
* A json annotated rest model for System Configuration for PUT.
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TenantConfigurationRest {
|
||||
public class TenantConfigurationValueRequest {
|
||||
|
||||
private String key;
|
||||
private String value;
|
||||
@JsonProperty(required = true)
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*
|
||||
* @return the value of the TenantConfigurationValueRequest
|
||||
*/
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key
|
||||
* the key to set
|
||||
*/
|
||||
public void setKey(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public String getValue() {
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TenantConfigurationValueRequest
|
||||
*
|
||||
* @param value
|
||||
* the value to set
|
||||
*/
|
||||
public void setValue(final String value) {
|
||||
public void setValue(final Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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.rest.resource.model.system;
|
||||
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* A json annotated rest model for a tenant configuration value to RESTful API
|
||||
* representation.
|
||||
*
|
||||
*/
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class TenantConfigurationValueRest extends ResourceSupport {
|
||||
|
||||
@JsonInclude(Include.ALWAYS)
|
||||
private Object value;
|
||||
|
||||
@JsonInclude(Include.ALWAYS)
|
||||
private boolean isGlobal = true;
|
||||
|
||||
private Long lastModifiedAt;
|
||||
private String lastModifiedBy;
|
||||
private Long createdAt;
|
||||
private String createdBy;
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(final Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean isGlobal() {
|
||||
return isGlobal;
|
||||
}
|
||||
|
||||
public void setGlobal(final boolean isGlobal) {
|
||||
this.isGlobal = isGlobal;
|
||||
}
|
||||
|
||||
public Long getLastModifiedAt() {
|
||||
return lastModifiedAt;
|
||||
}
|
||||
|
||||
public void setLastModifiedAt(final Long lastModifiedAt) {
|
||||
this.lastModifiedAt = lastModifiedAt;
|
||||
}
|
||||
|
||||
public String getLastModifiedBy() {
|
||||
return lastModifiedBy;
|
||||
}
|
||||
|
||||
public void setLastModifiedBy(final String lastModifiedBy) {
|
||||
this.lastModifiedBy = lastModifiedBy;
|
||||
}
|
||||
|
||||
public Long getCreatedAt() {
|
||||
return createdAt;
|
||||
}
|
||||
|
||||
public void setCreatedAt(final Long createdAt) {
|
||||
this.createdAt = createdAt;
|
||||
}
|
||||
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
public void setCreatedBy(final String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest.resource.model.system;
|
||||
package org.eclipse.hawkbit.rest.resource.model.systemmanagement;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest.resource.model.system;
|
||||
package org.eclipse.hawkbit.rest.resource.model.systemmanagement;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.rest.resource.model.system;
|
||||
package org.eclipse.hawkbit.rest.resource.model.systemmanagement;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@@ -15,7 +15,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.eclipse.hawkbit.ControllerPollProperties;
|
||||
import org.eclipse.hawkbit.artifact.repository.model.DbArtifact;
|
||||
import org.eclipse.hawkbit.cache.CacheWriteNotify;
|
||||
import org.eclipse.hawkbit.controller.model.ActionFeedback;
|
||||
@@ -77,8 +76,6 @@ public class RootController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RootController.class);
|
||||
private static final String GIVEN_ACTION_IS_NOT_ASSIGNED_TO_GIVEN_TARGET = "given action ({}) is not assigned to given target ({}).";
|
||||
|
||||
private static final String SP_SERVER_CONFIG_PREFIX = "hawkbit.server.";
|
||||
|
||||
@Autowired
|
||||
private ControllerManagement controllerManagement;
|
||||
|
||||
@@ -88,9 +85,6 @@ public class RootController {
|
||||
@Autowired
|
||||
private ArtifactManagement artifactManagement;
|
||||
|
||||
@Autowired
|
||||
private ControllerPollProperties controllerPollProperties;
|
||||
|
||||
@Autowired
|
||||
private CacheWriteNotify cacheWriteNotify;
|
||||
|
||||
@@ -156,7 +150,7 @@ public class RootController {
|
||||
|
||||
return new ResponseEntity<>(
|
||||
DataConversionHelper.fromTarget(target, controllerManagement.findActionByTargetAndActive(target),
|
||||
controllerPollProperties.getPollingTime(), tenantAware),
|
||||
controllerManagement.findPollingTime(), tenantAware),
|
||||
HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ public class ResponseExceptionHandler {
|
||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_REPO_TENANT_NOT_EXISTS, HttpStatus.BAD_REQUEST);
|
||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ENTITY_LOCKED, HttpStatus.LOCKED);
|
||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_ROLLOUT_ILLEGAL_STATE, HttpStatus.BAD_REQUEST);
|
||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_VALUE_INVALID, HttpStatus.BAD_REQUEST);
|
||||
ERROR_TO_HTTP_STATUS.put(SpServerError.SP_CONFIGURATION_KEY_INVALID, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
private static HttpStatus getStatusOrDefault(final SpServerError error) {
|
||||
|
||||
@@ -17,11 +17,10 @@ import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.report.model.SystemUsageReport;
|
||||
import org.eclipse.hawkbit.report.model.TenantUsage;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.CacheRest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.SystemStatisticsRest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationRest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.TenantSystemUsageRest;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.rest.resource.model.systemmanagement.CacheRest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.systemmanagement.SystemStatisticsRest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.systemmanagement.TenantSystemUsageRest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -32,7 +31,6 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -53,6 +51,9 @@ public class SystemManagementResource {
|
||||
@Autowired
|
||||
private SystemManagement systemManagement;
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
@Autowired
|
||||
private CacheManager cacheManager;
|
||||
|
||||
@@ -129,24 +130,6 @@ public class SystemManagementResource {
|
||||
return ResponseEntity.ok(cacheNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a configuration for a specific tenant to the tenant
|
||||
* configuration.
|
||||
*
|
||||
* @param configuration
|
||||
* the configuration value to add or update
|
||||
* @param key
|
||||
* the key of the configuration to add or update
|
||||
* @return the response entity with status OK.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/conf/{key}")
|
||||
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_SYSTEM_ADMIN)
|
||||
public ResponseEntity<Void> addUpdateConfig(@RequestBody final TenantConfigurationRest configuration,
|
||||
@PathVariable final String key) {
|
||||
systemManagement.addOrUpdateConfiguration(new TenantConfiguration(key, configuration.getValue()));
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
private CacheRest cacheRest(final Cache cache) {
|
||||
final Object nativeCache = cache.getNativeCache();
|
||||
if (nativeCache instanceof com.google.common.cache.Cache) {
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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.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 org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRest;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
|
||||
/**
|
||||
* A mapper which maps repository model to RESTful model representation and
|
||||
* back.
|
||||
*/
|
||||
public class SystemMapper {
|
||||
|
||||
private SystemMapper() {
|
||||
// Utility class
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tenantConfigurationManagement
|
||||
* instance of TenantConfigurationManagement
|
||||
* @return a map of all existing configuration values
|
||||
*/
|
||||
public static Map<String, TenantConfigurationValueRest> toResponse(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
|
||||
final Map<String, TenantConfigurationValueRest> configurationMap = new HashMap<>();
|
||||
|
||||
for (final TenantConfigurationKey key : TenantConfigurationKey.values()) {
|
||||
configurationMap.put(key.getKeyName(),
|
||||
toResponse(key.getKeyName(), tenantConfigurationManagement.getConfigurationValue(key)));
|
||||
}
|
||||
|
||||
return configurationMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* maps a TenantConfigurationValue from the repository model to a
|
||||
* TenantConfigurationValueRest, the RESTful model.
|
||||
*
|
||||
* @param repoConfValue
|
||||
* configuration value as repository model
|
||||
* @return configuration value as RESTful model
|
||||
*/
|
||||
public static TenantConfigurationValueRest toResponse(final String key,
|
||||
final TenantConfigurationValue<?> repoConfValue) {
|
||||
final TenantConfigurationValueRest restConfValue = new TenantConfigurationValueRest();
|
||||
|
||||
restConfValue.setValue(repoConfValue.getValue());
|
||||
restConfValue.setGlobal(repoConfValue.isGlobal());
|
||||
restConfValue.setCreatedAt(repoConfValue.getCreatedAt());
|
||||
restConfValue.setCreatedBy(repoConfValue.getCreatedBy());
|
||||
restConfValue.setLastModifiedAt(repoConfValue.getLastModifiedAt());
|
||||
restConfValue.setLastModifiedBy(repoConfValue.getLastModifiedBy());
|
||||
|
||||
restConfValue.add(linkTo(methodOn(SystemResource.class).getConfigurationValue(key)).withRel("self"));
|
||||
|
||||
return restConfValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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.rest.resource;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRequest;
|
||||
import org.eclipse.hawkbit.rest.resource.model.system.TenantConfigurationValueRest;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* REST Resource handling tenant specific configuration operations.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(RestConstants.SYSTEM_V1_REQUEST_MAPPING)
|
||||
public class SystemResource {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SystemResource.class);
|
||||
|
||||
@Autowired
|
||||
private TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE })
|
||||
public ResponseEntity<ResourceSupport> getSystem() {
|
||||
final ResourceSupport resourceSupport = new ResourceSupport();
|
||||
resourceSupport.add(linkTo(methodOn(SystemResource.class).getSystemConfiguration()).withRel("configs"));
|
||||
return ResponseEntity.ok(resourceSupport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a Map of all configuration values.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/configs", produces = { "application/hal+json",
|
||||
MediaType.APPLICATION_JSON_VALUE })
|
||||
public ResponseEntity<Map<String, TenantConfigurationValueRest>> getSystemConfiguration() {
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(tenantConfigurationManagement), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the DELETE request of deleting a tenant specific configuration
|
||||
* value within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @return If the given configuration value exists and could be deleted Http
|
||||
* OK. In any failure the JsonResponseExceptionHandler is handling
|
||||
* the response.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.DELETE, value = "/configs/{keyName}", produces = { "application/hal+json",
|
||||
MediaType.APPLICATION_JSON_VALUE })
|
||||
public ResponseEntity<Void> deleteConfigurationValue(@PathVariable final String keyName) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
tenantConfigurationManagement.deleteConfiguration(configKey);
|
||||
|
||||
LOG.debug("{} config value deleted, return status {}", keyName, HttpStatus.OK);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the GET request of deleting a tenant specific configuration value
|
||||
* within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @return If the given configuration value exists and could be get Http OK.
|
||||
* In any failure the JsonResponseExceptionHandler is handling the
|
||||
* response.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/configs/{keyName}", produces = { "application/hal+json",
|
||||
MediaType.APPLICATION_JSON_VALUE })
|
||||
public ResponseEntity<TenantConfigurationValueRest> getConfigurationValue(@PathVariable final String keyName) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
LOG.debug("{} config value getted, return status {}", keyName, HttpStatus.OK);
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(configKey.getKeyName(),
|
||||
tenantConfigurationManagement.getConfigurationValue(configKey)), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the GET request of deleting a tenant specific configuration value
|
||||
* within SP.
|
||||
*
|
||||
* @param keyName
|
||||
* the Name of the configuration key
|
||||
* @param configurationValueRest
|
||||
* the new value for the configuration
|
||||
* @return If the given configuration value exists and could be get Http OK.
|
||||
* In any failure the JsonResponseExceptionHandler is handling the
|
||||
* response.
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.PUT, value = "/configs/{keyName}", consumes = { "application/hal+json",
|
||||
MediaType.APPLICATION_JSON_VALUE }, produces = { "application/hal+json", MediaType.APPLICATION_JSON_VALUE })
|
||||
public ResponseEntity<TenantConfigurationValueRest> updateConfigurationValue(@PathVariable final String keyName,
|
||||
@RequestBody final TenantConfigurationValueRequest configurationValueRest) {
|
||||
|
||||
final TenantConfigurationKey configKey = TenantConfigurationKey.fromKeyName(keyName);
|
||||
|
||||
final TenantConfigurationValue<Object> updatedValue = tenantConfigurationManagement
|
||||
|
||||
.addOrUpdateConfiguration(configKey, configurationValueRest.getValue());
|
||||
return new ResponseEntity<>(SystemMapper.toResponse(keyName, updatedValue), HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||
import org.eclipse.hawkbit.repository.model.Target;
|
||||
import org.eclipse.hawkbit.repository.model.TargetUpdateStatus;
|
||||
import org.eclipse.hawkbit.rest.resource.JsonBuilder;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.util.IpUtil;
|
||||
import org.junit.Test;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
@@ -73,7 +74,7 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB {
|
||||
@Test
|
||||
@Description("Ensures that target poll request does not change audit data on the entity.")
|
||||
@WithUser(principal = "knownPrincipal", authorities = { SpPermission.READ_TARGET, SpPermission.UPDATE_TARGET,
|
||||
SpPermission.CREATE_TARGET })
|
||||
SpPermission.CREATE_TARGET }, allSpPermissions = false)
|
||||
public void targetPollDoesNotModifyAuditData() throws Exception {
|
||||
// create target first with "knownPrincipal" user and audit data
|
||||
final String knownTargetControllerId = "target1";
|
||||
@@ -133,6 +134,28 @@ public class RootControllerTest extends AbstractIntegrationTestWithMongoDB {
|
||||
.andExpect(status().isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.")
|
||||
@WithUser(principal = "knownpricipal", allSpPermissions = false)
|
||||
public void pollWithModifiedGloablPollingTime() throws Exception {
|
||||
securityRule.runAs(
|
||||
WithSpringAuthorityRule.withUser("tenantadmin", SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION),
|
||||
() -> {
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
|
||||
"00:02:00");
|
||||
return null;
|
||||
});
|
||||
|
||||
securityRule.runAs(
|
||||
WithSpringAuthorityRule.withUser("controller", SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(content().contentType(MediaTypes.HAL_JSON))
|
||||
.andExpect(jsonPath("$config.polling.sleep", equalTo("00:02:00")));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("Ensures that etag check results in not modified response if provided etag by client is identical to entity in repository.")
|
||||
public void rootRsNotModified() throws Exception {
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* 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.rest.resource;
|
||||
|
||||
import static org.fest.assertions.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.eclipse.hawkbit.AbstractIntegrationTest;
|
||||
import org.eclipse.hawkbit.MockMvcResultPrinter;
|
||||
import org.eclipse.hawkbit.exception.SpServerError;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfigurationValue;
|
||||
import org.eclipse.hawkbit.rest.resource.model.ExceptionInfo;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import ru.yandex.qatools.allure.annotations.Description;
|
||||
import ru.yandex.qatools.allure.annotations.Features;
|
||||
import ru.yandex.qatools.allure.annotations.Stories;
|
||||
|
||||
@Features("Component Tests - Management RESTful API")
|
||||
@Stories("ConfigurationResource")
|
||||
public class ConfigurationResourceTest extends AbstractIntegrationTest {
|
||||
|
||||
private static String BASE_JSON_REQUEST_STRING = "{\"value\":\"%s\"}";
|
||||
|
||||
@Test
|
||||
@Description("perform a GET request on all existing configurations.")
|
||||
public void getConfigurationValues() throws Exception {
|
||||
|
||||
final ResultActions resultActions = mvc.perform(get(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/"))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.*", hasSize(TenantConfigurationKey.values().length)));
|
||||
|
||||
for (final TenantConfigurationKey key : TenantConfigurationKey.values()) {
|
||||
|
||||
final TenantConfigurationValue<?> confValue = tenantConfigurationManagement.getConfigurationValue(key);
|
||||
resultActions.andExpect(jsonPath("$.['" + key.getKeyName() + "'].value", equalTo(confValue.getValue())))
|
||||
.andExpect(jsonPath("$.['" + key.getKeyName() + "'].global", equalTo(confValue.isGlobal())));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a GET request on a existing configuration key.")
|
||||
public void getConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String notGlobalValue = "notTheGlobalHeaderAuthoryName";
|
||||
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue);
|
||||
|
||||
mvc.perform(get(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("value", equalTo(notGlobalValue))).andExpect(jsonPath("global", equalTo(false)))
|
||||
.andExpect(jsonPath("createdAt", notNullValue())).andExpect(jsonPath("createdBy", notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a PUT request on a existing configuration key with a valid value.")
|
||||
public void putConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String testValue = "12:12:12";
|
||||
|
||||
mvc.perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName())
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue)).contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isEqualTo(testValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a DELETE request on a existing configuration key.")
|
||||
public void deleteConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME;
|
||||
final String notGlobalValue = "notTheGlobalHeaderAuthoryName";
|
||||
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key, notGlobalValue);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(false);
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isEqualTo(notGlobalValue);
|
||||
|
||||
mvc.perform(delete(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}/", key.getKeyName()))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isNoContent());
|
||||
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).isGlobal()).isEqualTo(true);
|
||||
assertThat(tenantConfigurationManagement.getConfigurationValue(key, String.class).getValue())
|
||||
.isNotEqualTo(notGlobalValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a (put) request on a not existing configuration key.")
|
||||
public void putInvalidConfigurationKey() throws Exception {
|
||||
|
||||
final String notExistingKey = "notExistingKey";
|
||||
final String testValue = "12:12:12";
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", notExistingKey)
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_KEY_INVALID.getKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Description("perform a put request with a not matching configuration value.")
|
||||
public void putInvalidConfigurationValue() throws Exception {
|
||||
|
||||
final TenantConfigurationKey key = TenantConfigurationKey.POLLING_TIME_INTERVAL;
|
||||
final String testValue = "invalidFormattedDuration";
|
||||
|
||||
final MvcResult mvcResult = mvc
|
||||
.perform(put(RestConstants.SYSTEM_V1_REQUEST_MAPPING + "/configs/{configId}", key.getKeyName())
|
||||
.content(String.format(BASE_JSON_REQUEST_STRING, testValue))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isBadRequest()).andReturn();
|
||||
|
||||
// verify response json exception message
|
||||
final ExceptionInfo exceptionInfo = ResourceUtility
|
||||
.convertException(mvcResult.getResponse().getContentAsString());
|
||||
assertThat(exceptionInfo.getErrorCode()).isEqualTo(SpServerError.SP_CONFIGURATION_VALUE_INVALID.getKey());
|
||||
}
|
||||
}
|
||||
@@ -308,6 +308,13 @@ public final class SpPermission {
|
||||
public static final String HAS_AUTH_ROLLOUT_MANAGEMENT_WRITE = HAS_AUTH_PREFIX + ROLLOUT_MANAGEMENT
|
||||
+ HAS_AUTH_SUFFIX + HAS_AUTH_AND + HAS_AUTH_PREFIX + UPDATE_TARGET + HAS_AUTH_SUFFIX;
|
||||
|
||||
/**
|
||||
* Spring security eval hasAuthority expression to check if spring
|
||||
* context contains {@link SpPermission#TENANT_CONFIGURATION}
|
||||
*/
|
||||
public static final String HAS_AUTH_TENANT_CONFIGURATION = HAS_AUTH_PREFIX + TENANT_CONFIGURATION
|
||||
+ HAS_AUTH_SUFFIX;
|
||||
|
||||
private SpringEvalExpressions() {
|
||||
// utility class
|
||||
}
|
||||
|
||||
@@ -36,8 +36,18 @@ public class SystemSecurityContext {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SystemSecurityContext.class);
|
||||
|
||||
private final TenantAware tenantAware;
|
||||
|
||||
/**
|
||||
* Autowired constructor.
|
||||
*
|
||||
* @param tenantAware
|
||||
* the tenant aware bean to retrieve the current tenant
|
||||
*/
|
||||
@Autowired
|
||||
private TenantAware tenantAware;
|
||||
public SystemSecurityContext(final TenantAware tenantAware) {
|
||||
this.tenantAware = tenantAware;
|
||||
}
|
||||
|
||||
public <T> T runAsSystem(final Callable<T> callable) {
|
||||
final SecurityContext oldContext = SecurityContextHolder.getContext();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
@@ -26,14 +26,16 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractControllerAuthenticationFilter.class);
|
||||
|
||||
protected final SystemManagement systemManagement;
|
||||
protected final TenantConfigurationManagement tenantConfigurationManagement;
|
||||
protected final TenantAware tenantAware;
|
||||
private final SecurityConfigurationKeyTenantRunner configurationKeyTenantRunner;
|
||||
protected final SystemSecurityContext systemSecurityContext;
|
||||
|
||||
protected AbstractControllerAuthenticationFilter(final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
this.systemManagement = systemManagement;
|
||||
protected AbstractControllerAuthenticationFilter(final TenantConfigurationManagement systemManagement,
|
||||
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
|
||||
this.tenantConfigurationManagement = systemManagement;
|
||||
this.tenantAware = tenantAware;
|
||||
this.systemSecurityContext = systemSecurityContext;
|
||||
this.configurationKeyTenantRunner = new SecurityConfigurationKeyTenantRunner();
|
||||
}
|
||||
|
||||
@@ -53,8 +55,10 @@ public abstract class AbstractControllerAuthenticationFilter implements PreAuthe
|
||||
private final class SecurityConfigurationKeyTenantRunner implements TenantAware.TenantRunner<Boolean> {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
|
||||
LOGGER.trace("retrieving configuration value for configuration key {}", getTenantConfigurationKey());
|
||||
return systemManagement.getConfigurationValue(getTenantConfigurationKey(), Boolean.class);
|
||||
return systemSecurityContext.runAsSystem(() -> tenantConfigurationManagement
|
||||
.getConfigurationValue(getTenantConfigurationKey(), Boolean.class).getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
@@ -45,8 +45,8 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param systemManagement
|
||||
* the system management service to retrieve configuration
|
||||
* @param tenantConfigurationManagement
|
||||
* the tenant management service to retrieve configuration
|
||||
* properties
|
||||
* @param controllerManagement
|
||||
* the controller management to retrieve the specific target
|
||||
@@ -54,10 +54,15 @@ public class ControllerPreAuthenticateSecurityTokenFilter extends AbstractContro
|
||||
* @param tenantAware
|
||||
* the tenant aware service to get configuration for the specific
|
||||
* tenant
|
||||
* @param systemSecurityContext
|
||||
* the system security context to get access to tenant
|
||||
* configuration
|
||||
*/
|
||||
public ControllerPreAuthenticateSecurityTokenFilter(final SystemManagement systemManagement,
|
||||
final ControllerManagement controllerManagement, final TenantAware tenantAware) {
|
||||
super(systemManagement, tenantAware);
|
||||
public ControllerPreAuthenticateSecurityTokenFilter(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final ControllerManagement controllerManagement, final TenantAware tenantAware,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
this.controllerManagement = controllerManagement;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
@@ -39,16 +39,20 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param systemManagement
|
||||
* the system management service to retrieve configuration
|
||||
* @param tenantConfigurationManagement
|
||||
* the tenant management service to retrieve configuration
|
||||
* properties
|
||||
* @param tenantAware
|
||||
* the tenant aware service to get configuration for the specific
|
||||
* tenant
|
||||
* @param systemSecurityContext
|
||||
* the system security context to get access to tenant
|
||||
* configuration
|
||||
*/
|
||||
public ControllerPreAuthenticatedGatewaySecurityTokenFilter(final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
super(systemManagement, tenantAware);
|
||||
public ControllerPreAuthenticatedGatewaySecurityTokenFilter(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement, final TenantAware tenantAware,
|
||||
final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,8 +88,12 @@ public class ControllerPreAuthenticatedGatewaySecurityTokenFilter extends Abstra
|
||||
public String run() {
|
||||
LOGGER.trace("retrieving configuration value for configuration key {}",
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY);
|
||||
return systemManagement.getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class);
|
||||
|
||||
return systemSecurityContext
|
||||
.runAsSystem(() -> tenantConfigurationManagement
|
||||
.getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class)
|
||||
.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import org.eclipse.hawkbit.dmf.json.model.TenantSecruityToken;
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.slf4j.Logger;
|
||||
@@ -56,18 +56,20 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
|
||||
* @param caAuthorityNameHeader
|
||||
* the http-header which holds the ca-authority name of the
|
||||
* certificate
|
||||
* @param systemManagement
|
||||
* the system management service to retrieve configuration
|
||||
* properties to check if the header authentication is enabled
|
||||
* for this tenant
|
||||
* @param tenantConfigurationManagement
|
||||
* the tenant management service to retrieve configuration
|
||||
* properties
|
||||
* @param tenantAware
|
||||
* the tenant aware service to get configuration for the specific
|
||||
* tenant
|
||||
* @param systemSecurityContext
|
||||
* the system security context to get access to tenant
|
||||
* configuration
|
||||
*/
|
||||
public ControllerPreAuthenticatedSecurityHeaderFilter(final String caCommonNameHeader,
|
||||
final String caAuthorityNameHeader, final SystemManagement systemManagement,
|
||||
final TenantAware tenantAware) {
|
||||
super(systemManagement, tenantAware);
|
||||
final String caAuthorityNameHeader, final TenantConfigurationManagement tenantConfigurationManagement,
|
||||
final TenantAware tenantAware, final SystemSecurityContext systemSecurityContext) {
|
||||
super(tenantConfigurationManagement, tenantAware, systemSecurityContext);
|
||||
this.caCommonNameHeader = caCommonNameHeader;
|
||||
this.sslIssuerHashBasicHeader = caAuthorityNameHeader;
|
||||
}
|
||||
@@ -142,8 +144,8 @@ public class ControllerPreAuthenticatedSecurityHeaderFilter extends AbstractCont
|
||||
private final class GetSecurityAuthorityNameTenantRunner implements TenantAware.TenantRunner<String> {
|
||||
@Override
|
||||
public String run() {
|
||||
return systemManagement.getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class);
|
||||
return tenantConfigurationManagement.getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class).getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,16 +8,13 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.authentication.AuthenticationConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.authentication.CertificateAuthenticationConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.authentication.GatewaySecurityTokenAuthenticationConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.authentication.TargetSecurityTokenAuthenticationConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.authentication.TenantConfigurationItem;
|
||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -26,7 +23,6 @@ import com.vaadin.data.Property.ValueChangeListener;
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.ViewScope;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
@@ -40,17 +36,11 @@ import com.vaadin.ui.VerticalLayout;
|
||||
*/
|
||||
@SpringComponent
|
||||
@ViewScope
|
||||
public class AuthenticationConfigurationView extends CustomComponent
|
||||
implements ConfigurationGroup, TenantConfigurationItem.TenantConfigurationChangeListener {
|
||||
public class AuthenticationConfigurationView extends BaseConfigurationView
|
||||
implements ConfigurationGroup, ConfigurationItem.ConfigurationItemChangeListener, ValueChangeListener {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final String DIST_CHECKBOX_STYLE = "dist-checkbox-style";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
@@ -65,8 +55,6 @@ public class AuthenticationConfigurationView extends CustomComponent
|
||||
@Autowired
|
||||
private GatewaySecurityTokenAuthenticationConfigurationItem gatewaySecurityTokenAuthenticationConfigurationItem;
|
||||
|
||||
private final List<ConfigurationGroupChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
private CheckBox gatewaySecTokenCheckBox;
|
||||
|
||||
private CheckBox targetSecTokenCheckBox;
|
||||
@@ -100,42 +88,31 @@ public class AuthenticationConfigurationView extends CustomComponent
|
||||
|
||||
certificateAuthCheckbox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
|
||||
certificateAuthCheckbox.setValue(certificateAuthenticationConfigurationItem.isConfigEnabled());
|
||||
certificateAuthCheckbox.addValueChangeListener(new AuthenticationTenantConfigurationItemChangeListener(
|
||||
certificateAuthCheckbox, certificateAuthenticationConfigurationItem));
|
||||
certificateAuthenticationConfigurationItem.addConfigurationChangeListener(this);
|
||||
certificateAuthCheckbox.addValueChangeListener(this);
|
||||
certificateAuthenticationConfigurationItem.addChangeListener(this);
|
||||
gridLayout.addComponent(certificateAuthCheckbox, 0, 0);
|
||||
gridLayout.addComponent(certificateAuthenticationConfigurationItem, 1, 0);
|
||||
|
||||
targetSecTokenCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
|
||||
targetSecTokenCheckBox.setValue(targetSecurityTokenAuthenticationConfigurationItem.isConfigEnabled());
|
||||
targetSecTokenCheckBox.addValueChangeListener(new AuthenticationTenantConfigurationItemChangeListener(
|
||||
targetSecTokenCheckBox, targetSecurityTokenAuthenticationConfigurationItem));
|
||||
targetSecurityTokenAuthenticationConfigurationItem.addConfigurationChangeListener(this);
|
||||
targetSecTokenCheckBox.addValueChangeListener(this);
|
||||
targetSecurityTokenAuthenticationConfigurationItem.addChangeListener(this);
|
||||
gridLayout.addComponent(targetSecTokenCheckBox, 0, 1);
|
||||
gridLayout.addComponent(targetSecurityTokenAuthenticationConfigurationItem, 1, 1);
|
||||
|
||||
gatewaySecTokenCheckBox = SPUIComponentProvider.getCheckBox("", DIST_CHECKBOX_STYLE, null, false, "");
|
||||
gatewaySecTokenCheckBox.setId("gatewaysecuritycheckbox");
|
||||
gatewaySecTokenCheckBox.setValue(gatewaySecurityTokenAuthenticationConfigurationItem.isConfigEnabled());
|
||||
gatewaySecTokenCheckBox.addValueChangeListener(new AuthenticationTenantConfigurationItemChangeListener(
|
||||
gatewaySecTokenCheckBox, gatewaySecurityTokenAuthenticationConfigurationItem));
|
||||
gatewaySecurityTokenAuthenticationConfigurationItem.addConfigurationChangeListener(this);
|
||||
gatewaySecTokenCheckBox.addValueChangeListener(this);
|
||||
gatewaySecurityTokenAuthenticationConfigurationItem.addChangeListener(this);
|
||||
gridLayout.addComponent(gatewaySecTokenCheckBox, 0, 2);
|
||||
gridLayout.addComponent(gatewaySecurityTokenAuthenticationConfigurationItem, 1, 2);
|
||||
|
||||
vLayout.addComponent(gridLayout);
|
||||
rootPanel.setContent(vLayout);
|
||||
setCompositionRoot(rootPanel);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.hawkbit.server.ui.tenantconfiguration.ConfigurationGroup#save
|
||||
* ()
|
||||
*/
|
||||
@Override
|
||||
public void save() {
|
||||
certificateAuthenticationConfigurationItem.save();
|
||||
@@ -143,13 +120,6 @@ public class AuthenticationConfigurationView extends CustomComponent
|
||||
gatewaySecurityTokenAuthenticationConfigurationItem.save();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.hawkbit.server.ui.tenantconfiguration.ConfigurationGroup#undo
|
||||
* ()
|
||||
*/
|
||||
@Override
|
||||
public void undo() {
|
||||
certificateAuthenticationConfigurationItem.undo();
|
||||
@@ -160,47 +130,37 @@ public class AuthenticationConfigurationView extends CustomComponent
|
||||
gatewaySecTokenCheckBox.setValue(gatewaySecurityTokenAuthenticationConfigurationItem.isConfigEnabled());
|
||||
}
|
||||
|
||||
private void notifyConfigurationChanged() {
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChangeListener(final ConfigurationGroupChangeListener listener) {
|
||||
configurationChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurationHasChanged() {
|
||||
notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
private final class AuthenticationTenantConfigurationItemChangeListener implements ValueChangeListener {
|
||||
@Override
|
||||
public void valueChange(final ValueChangeEvent event) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final CheckBox checkBox;
|
||||
private final TenantConfigurationItem configurationItem;
|
||||
|
||||
private AuthenticationTenantConfigurationItemChangeListener(final CheckBox checkBox,
|
||||
final TenantConfigurationItem configurationItem) {
|
||||
this.checkBox = checkBox;
|
||||
this.configurationItem = configurationItem;
|
||||
if (!(event.getProperty() instanceof CheckBox)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.
|
||||
* data.Property. ValueChangeEvent)
|
||||
*/
|
||||
@Override
|
||||
public void valueChange(final ValueChangeEvent event) {
|
||||
notifyConfigurationChanged();
|
||||
if (checkBox.getValue()) {
|
||||
configurationItem.configEnable();
|
||||
} else {
|
||||
configurationItem.configDisable();
|
||||
}
|
||||
notifyConfigurationChanged();
|
||||
|
||||
final CheckBox checkBox = (CheckBox) event.getProperty();
|
||||
AuthenticationConfigurationItem configurationItem;
|
||||
|
||||
if (checkBox == gatewaySecTokenCheckBox) {
|
||||
configurationItem = gatewaySecurityTokenAuthenticationConfigurationItem;
|
||||
} else if (checkBox == targetSecTokenCheckBox) {
|
||||
configurationItem = targetSecurityTokenAuthenticationConfigurationItem;
|
||||
} else if (checkBox == certificateAuthCheckbox) {
|
||||
configurationItem = certificateAuthenticationConfigurationItem;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkBox.getValue()) {
|
||||
configurationItem.configEnable();
|
||||
} else {
|
||||
configurationItem.configDisable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.ui.tenantconfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
|
||||
/**
|
||||
* base class for all configuration views. This class implements the logic for
|
||||
* the handling of the
|
||||
*
|
||||
*/
|
||||
public abstract class BaseConfigurationView extends CustomComponent implements ConfigurationGroup {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<ConfigurationItemChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
protected void notifyConfigurationChanged() {
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationHasChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChangeListener(final ConfigurationItemChangeListener listener) {
|
||||
configurationChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInputValid() {
|
||||
// default return value is true, because often user can only choose from
|
||||
// different valid options.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||
|
||||
import java.io.Serializable;
|
||||
import com.vaadin.ui.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface ConfigurationGroup {
|
||||
public interface ConfigurationGroup extends Component, ConfigurationItem {
|
||||
|
||||
/**
|
||||
* called to store any configuration changes.
|
||||
@@ -26,29 +26,4 @@ public interface ConfigurationGroup {
|
||||
* called to rollback any configuration changes.
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
* Adds a configuration change listener to notify about configuration
|
||||
* changes.
|
||||
*
|
||||
* @param listener
|
||||
* the listener to be notified in case the item changes some
|
||||
* configuration
|
||||
*/
|
||||
void addChangeListener(ConfigurationGroupChangeListener listener);
|
||||
|
||||
/**
|
||||
* Configuration Change Listener to be notified about configuration changes
|
||||
* in configuration group.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
interface ConfigurationGroupChangeListener extends Serializable {
|
||||
/**
|
||||
* called to notify about configuration has been changed.
|
||||
*/
|
||||
void configurationChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.ui.tenantconfiguration;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* represents an configurationItem, which can be modified by the user
|
||||
*/
|
||||
public interface ConfigurationItem {
|
||||
|
||||
/**
|
||||
* called to verify that the Input done by the user is valid
|
||||
*
|
||||
* @return true when the data is valid, false otherwise
|
||||
*/
|
||||
boolean isUserInputValid();
|
||||
|
||||
/**
|
||||
* Adds a configuration change listener to notify about configuration
|
||||
* changes.
|
||||
*
|
||||
* @param listener
|
||||
* the listener to be notified in case the item changes some
|
||||
* configuration
|
||||
*/
|
||||
void addChangeListener(final ConfigurationItemChangeListener listener);
|
||||
|
||||
/**
|
||||
* Configuration Change Listener to be notified about configuration changes
|
||||
* in configuration group.
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface ConfigurationItemChangeListener extends Serializable {
|
||||
/**
|
||||
* called to notify about configuration has been changed.
|
||||
*/
|
||||
void configurationHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,6 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.repository.DistributionSetManagement;
|
||||
@@ -29,7 +26,6 @@ import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.ViewScope;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.CustomComponent;
|
||||
import com.vaadin.ui.HorizontalLayout;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
@@ -43,7 +39,7 @@ import com.vaadin.ui.VerticalLayout;
|
||||
*/
|
||||
@SpringComponent
|
||||
@ViewScope
|
||||
public class DefaultDistributionSetTypeLayout extends CustomComponent implements ConfigurationGroup {
|
||||
public class DefaultDistributionSetTypeLayout extends BaseConfigurationView implements ConfigurationGroup {
|
||||
|
||||
private static final long serialVersionUID = 17896542758L;
|
||||
|
||||
@@ -66,8 +62,6 @@ public class DefaultDistributionSetTypeLayout extends CustomComponent implements
|
||||
|
||||
private Label changeIcon;
|
||||
|
||||
private final List<ConfigurationGroupChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Initialize Default Distribution Set layout.
|
||||
*/
|
||||
@@ -163,13 +157,4 @@ public class DefaultDistributionSetTypeLayout extends CustomComponent implements
|
||||
changeIcon.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyConfigurationChanged() {
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChangeListener(final ConfigurationGroupChangeListener listener) {
|
||||
configurationChangeListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* 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.ui.tenantconfiguration;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
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.ui.tenantconfiguration.polling.DurationConfigField;
|
||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import com.vaadin.spring.annotation.SpringComponent;
|
||||
import com.vaadin.spring.annotation.ViewScope;
|
||||
import com.vaadin.ui.Label;
|
||||
import com.vaadin.ui.Panel;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* View to configure the polling interval and the overdue time.
|
||||
*
|
||||
*
|
||||
*/
|
||||
@SpringComponent
|
||||
@ViewScope
|
||||
public class PollingConfigurationView extends BaseConfigurationView
|
||||
implements ConfigurationGroup, ConfigurationItem.ConfigurationItemChangeListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Autowired
|
||||
private I18N i18n;
|
||||
|
||||
@Autowired
|
||||
private ControllerPollProperties controllerPollProperties;
|
||||
|
||||
@Autowired
|
||||
private transient TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
private DurationConfigField fieldPollTime = null;
|
||||
private DurationConfigField fieldPollingOverdueTime = null;
|
||||
|
||||
private Duration minDuration;
|
||||
private Duration maxDuration;
|
||||
private Duration globalPollTime;
|
||||
private Duration globalOverdueTime;
|
||||
|
||||
private Duration tenantPollTime = null;
|
||||
private Duration tenantOverdueTime = null;
|
||||
|
||||
private final DurationHelper durationHelper = new DurationHelper();
|
||||
|
||||
/**
|
||||
* Initialize Authentication Configuration layout.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
|
||||
minDuration = durationHelper.formattedStringToDuration(controllerPollProperties.getMinPollingTime());
|
||||
maxDuration = durationHelper.formattedStringToDuration(controllerPollProperties.getMaxPollingTime());
|
||||
globalPollTime = durationHelper.formattedStringToDuration(tenantConfigurationManagement
|
||||
.getGlobalConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class));
|
||||
globalOverdueTime = durationHelper.formattedStringToDuration(tenantConfigurationManagement
|
||||
.getGlobalConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class));
|
||||
|
||||
final TenantConfigurationValue<String> pollTimeConfValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, String.class);
|
||||
if (!pollTimeConfValue.isGlobal()) {
|
||||
tenantPollTime = durationHelper.formattedStringToDuration(pollTimeConfValue.getValue());
|
||||
}
|
||||
|
||||
final TenantConfigurationValue<String> overdueTimeConfValue = tenantConfigurationManagement
|
||||
.getConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, String.class);
|
||||
if (!overdueTimeConfValue.isGlobal()) {
|
||||
tenantOverdueTime = durationHelper.formattedStringToDuration(overdueTimeConfValue.getValue());
|
||||
}
|
||||
|
||||
final Panel rootPanel = new Panel();
|
||||
rootPanel.setSizeFull();
|
||||
rootPanel.addStyleName("config-panel");
|
||||
|
||||
final VerticalLayout vLayout = new VerticalLayout();
|
||||
vLayout.setMargin(true);
|
||||
|
||||
final Label headerDisSetType = new Label(i18n.get("configuration.polling.title"));
|
||||
headerDisSetType.addStyleName("config-panel-header");
|
||||
vLayout.addComponent(headerDisSetType);
|
||||
|
||||
fieldPollTime = DurationConfigField.builder().caption(i18n.get("configuration.polling.time"))
|
||||
.checkBoxTooltip(i18n.get("configuration.polling.custom.value")).range(minDuration, maxDuration)
|
||||
.globalDuration(globalPollTime).tenantDuration(tenantPollTime).build();
|
||||
fieldPollTime.addChangeListener(this);
|
||||
vLayout.addComponent(fieldPollTime);
|
||||
|
||||
fieldPollingOverdueTime = DurationConfigField.builder().caption(i18n.get("configuration.polling.overduetime"))
|
||||
.checkBoxTooltip(i18n.get("configuration.polling.custom.value")).range(minDuration, maxDuration)
|
||||
.globalDuration(globalOverdueTime).tenantDuration(tenantOverdueTime).build();
|
||||
fieldPollingOverdueTime.addChangeListener(this);
|
||||
vLayout.addComponent(fieldPollingOverdueTime);
|
||||
|
||||
rootPanel.setContent(vLayout);
|
||||
setCompositionRoot(rootPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// make sure values are only saved, when the value has been changed
|
||||
|
||||
if (!compareDurations(tenantPollTime, fieldPollTime.getValue())) {
|
||||
tenantPollTime = fieldPollTime.getValue();
|
||||
saveDurationConfigurationValue(TenantConfigurationKey.POLLING_TIME_INTERVAL, tenantPollTime);
|
||||
}
|
||||
|
||||
if (!compareDurations(tenantOverdueTime, fieldPollingOverdueTime.getValue())) {
|
||||
tenantOverdueTime = fieldPollingOverdueTime.getValue();
|
||||
saveDurationConfigurationValue(TenantConfigurationKey.POLLING_OVERDUE_TIME_INTERVAL, tenantOverdueTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDurationConfigurationValue(final TenantConfigurationKey key, final Duration duration) {
|
||||
if (duration == null) {
|
||||
tenantConfigurationManagement.deleteConfiguration(key);
|
||||
} else {
|
||||
tenantConfigurationManagement.addOrUpdateConfiguration(key,
|
||||
durationHelper.durationToFormattedString(duration));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
fieldPollTime.setValue(tenantPollTime);
|
||||
fieldPollingOverdueTime.setValue(tenantOverdueTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInputValid() {
|
||||
return fieldPollTime.isUserInputValid() && fieldPollingOverdueTime.isUserInputValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurationHasChanged() {
|
||||
notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
private boolean compareDurations(final Duration d1, final Duration d2) {
|
||||
if (d1 == null && d2 == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (d1 != null) {
|
||||
return d1.equals(d2);
|
||||
}
|
||||
|
||||
// d1 == null, d2 != null
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.tenantconfiguration;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.ui.HawkbitUI;
|
||||
import org.eclipse.hawkbit.ui.UiProperties;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.decorators.SPUIButtonStyleSmallNoBorder;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationGroup.ConfigurationGroupChangeListener;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationItem.ConfigurationItemChangeListener;
|
||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUIComponetIdProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.UINotification;
|
||||
@@ -33,14 +38,13 @@ import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Main UI for the system configuration view.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@SpringView(name = TenantConfigurationDashboardView.VIEW_NAME, ui = HawkbitUI.class)
|
||||
@ViewScope
|
||||
public class TenantConfigurationDashboardView extends CustomComponent
|
||||
implements View, ConfigurationGroupChangeListener {
|
||||
public class TenantConfigurationDashboardView extends CustomComponent implements View, ConfigurationItemChangeListener {
|
||||
|
||||
public static final String VIEW_NAME = "spSystemConfig";
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -51,6 +55,9 @@ public class TenantConfigurationDashboardView extends CustomComponent
|
||||
@Autowired
|
||||
private AuthenticationConfigurationView authenticationConfigurationView;
|
||||
|
||||
@Autowired
|
||||
private PollingConfigurationView pollingConfigurationView;
|
||||
|
||||
@Autowired
|
||||
private I18N i18n;
|
||||
|
||||
@@ -63,6 +70,18 @@ public class TenantConfigurationDashboardView extends CustomComponent
|
||||
private Button saveConfigurationBtn;
|
||||
private Button undoConfigurationBtn;
|
||||
|
||||
private final List<ConfigurationGroup> configurationViews = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* init method adds all Configuration Views to the list of Views.
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
configurationViews.add(defaultDistributionSetTypeLayout);
|
||||
configurationViews.add(authenticationConfigurationView);
|
||||
configurationViews.add(pollingConfigurationView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enter(final ViewChangeEvent event) {
|
||||
|
||||
@@ -73,17 +92,16 @@ public class TenantConfigurationDashboardView extends CustomComponent
|
||||
rootLayout.setSizeFull();
|
||||
rootLayout.setMargin(true);
|
||||
rootLayout.setSpacing(true);
|
||||
rootLayout.addComponent(defaultDistributionSetTypeLayout);
|
||||
rootLayout.addComponent(authenticationConfigurationView);
|
||||
|
||||
configurationViews.forEach(view -> rootLayout.addComponent(view));
|
||||
|
||||
final HorizontalLayout buttonContent = saveConfigurationButtonsLayout();
|
||||
rootLayout.addComponent(buttonContent);
|
||||
rootLayout.setComponentAlignment(buttonContent, Alignment.BOTTOM_LEFT);
|
||||
rootPanel.setContent(rootLayout);
|
||||
setCompositionRoot(rootPanel);
|
||||
|
||||
authenticationConfigurationView.addChangeListener(this);
|
||||
defaultDistributionSetTypeLayout.addChangeListener(this);
|
||||
|
||||
configurationViews.forEach(view -> view.addChangeListener(this));
|
||||
}
|
||||
|
||||
private HorizontalLayout saveConfigurationButtonsLayout() {
|
||||
@@ -112,19 +130,25 @@ public class TenantConfigurationDashboardView extends CustomComponent
|
||||
}
|
||||
|
||||
private void saveConfiguration() {
|
||||
defaultDistributionSetTypeLayout.save();
|
||||
authenticationConfigurationView.save();
|
||||
|
||||
final boolean isUserInputValid = configurationViews.stream().allMatch(confView -> confView.isUserInputValid());
|
||||
|
||||
if (!isUserInputValid) {
|
||||
uINotification.displayValidationError(i18n.get("notification.configuration.save.notpossible"));
|
||||
return;
|
||||
}
|
||||
configurationViews.forEach(confView -> confView.save());
|
||||
|
||||
// More methods
|
||||
saveConfigurationBtn.setEnabled(false);
|
||||
undoConfigurationBtn.setEnabled(false);
|
||||
uINotification.displaySuccess(i18n.get("notification.configuration.save"));
|
||||
uINotification.displaySuccess(i18n.get("notification.configuration.save.successful"));
|
||||
}
|
||||
|
||||
private void undoConfiguration() {
|
||||
defaultDistributionSetTypeLayout.undo();
|
||||
authenticationConfigurationView.undo();
|
||||
|
||||
configurationViews.forEach(confView -> {
|
||||
confView.undo();
|
||||
});
|
||||
// More methods
|
||||
saveConfigurationBtn.setEnabled(false);
|
||||
undoConfigurationBtn.setEnabled(false);
|
||||
@@ -132,13 +156,13 @@ public class TenantConfigurationDashboardView extends CustomComponent
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see
|
||||
* org.eclipse.hawkbit.server.ui.tenantconfiguration.ConfigurationGroup.
|
||||
* ConfigurationGroupChangeListener #configurationChanged()
|
||||
*/
|
||||
@Override
|
||||
public void configurationChanged() {
|
||||
public void configurationHasChanged() {
|
||||
saveConfigurationBtn.setEnabled(true);
|
||||
undoConfigurationBtn.setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
|
||||
@@ -19,34 +19,33 @@ import org.eclipse.hawkbit.ui.utils.SPUILabelDefinitions;
|
||||
import com.vaadin.ui.VerticalLayout;
|
||||
|
||||
/**
|
||||
* Ab abstract authentication configuration item.
|
||||
* abstract authentication configuration item.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLayout implements TenantConfigurationItem {
|
||||
abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLayout
|
||||
implements AuthenticationConfigurationItem {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final TenantConfigurationKey configurationKey;
|
||||
private final transient SystemManagement systemManagement;
|
||||
private final transient TenantConfigurationManagement tenantConfigurationManagement;
|
||||
|
||||
private final List<TenantConfigurationChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
private final List<ConfigurationItemChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param configurationKey
|
||||
* the key for this configuration
|
||||
* @param systemManagement
|
||||
* the system management to retrive the configuration value
|
||||
* @param tenantConfigurationManagement
|
||||
* the tenant configuration management to retrieve the
|
||||
* configuration value
|
||||
*/
|
||||
public AbstractAuthenticationTenantConfigurationItem(final TenantConfigurationKey configurationKey,
|
||||
final SystemManagement systemManagement) {
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
this.configurationKey = configurationKey;
|
||||
this.systemManagement = systemManagement;
|
||||
this.tenantConfigurationManagement = tenantConfigurationManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,22 +56,16 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay
|
||||
addComponent(SPUIComponentProvider.getLabel(labelText, SPUILabelDefinitions.SP_LABEL_SIMPLE));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
|
||||
* TenantConfigurationItem# isConfigEnabled()
|
||||
*/
|
||||
@Override
|
||||
public boolean isConfigEnabled() {
|
||||
return systemManagement.getConfigurationValue(configurationKey, Boolean.class);
|
||||
return tenantConfigurationManagement.getConfigurationValue(configurationKey, Boolean.class).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the systemManagement
|
||||
*/
|
||||
protected SystemManagement getSystemManagement() {
|
||||
return systemManagement;
|
||||
protected TenantConfigurationManagement getTenantConfigurationManagement() {
|
||||
return tenantConfigurationManagement;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,16 +79,13 @@ abstract class AbstractAuthenticationTenantConfigurationItem extends VerticalLay
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationHasChanged());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.eclipse.hawkbit.server.ui.tenantconfiguration.
|
||||
* TenantConfigurationItem# addConfigurationChangeListener
|
||||
* (hawkbit.server.ui.tenantconfiguration.TenantConfigurationItem.
|
||||
* TenantConfigurationChangeListener)
|
||||
*/
|
||||
@Override
|
||||
public void addConfigurationChangeListener(final TenantConfigurationChangeListener listener) {
|
||||
public void addChangeListener(final ConfigurationItemChangeListener listener) {
|
||||
configurationChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInputValid() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.ui.tenantconfiguration.authentication;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationItem;
|
||||
|
||||
import com.vaadin.ui.Component;
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.vaadin.ui.Component;
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface TenantConfigurationItem extends Component {
|
||||
public interface AuthenticationConfigurationItem extends Component, ConfigurationItem {
|
||||
|
||||
/**
|
||||
* @return {@code true} if configuration is enabled, otherwise {@code false}
|
||||
@@ -47,28 +47,4 @@ public interface TenantConfigurationItem extends Component {
|
||||
*/
|
||||
void undo();
|
||||
|
||||
/**
|
||||
* Adds a configuration change listener to notify about configuration
|
||||
* changes.
|
||||
*
|
||||
* @param listener
|
||||
* the listener to be notified in case the item changes some
|
||||
* configuration
|
||||
*/
|
||||
void addConfigurationChangeListener(TenantConfigurationChangeListener listener);
|
||||
|
||||
/**
|
||||
* Configuration Change Listener to be notified about configuration changes
|
||||
* in configuration item.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
interface TenantConfigurationChangeListener extends Serializable {
|
||||
/**
|
||||
* called to notify about configuration has been changed.
|
||||
*/
|
||||
void configurationHasChanged();
|
||||
}
|
||||
}
|
||||
@@ -10,8 +10,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||
@@ -54,8 +53,9 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
|
||||
* the system management to retrie the configuration
|
||||
*/
|
||||
@Autowired
|
||||
public CertificateAuthenticationConfigurationItem(final SystemManagement systemManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, systemManagement);
|
||||
public CertificateAuthenticationConfigurationItem(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_ENABLED, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,13 +133,12 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
|
||||
@Override
|
||||
public void save() {
|
||||
if (configurationEnabledChange) {
|
||||
getSystemManagement().addOrUpdateConfiguration(
|
||||
new TenantConfiguration(getConfigurationKey().getKeyName(), String.valueOf(configurationEnabled)));
|
||||
getTenantConfigurationManagement().addOrUpdateConfiguration(getConfigurationKey(), configurationEnabled);
|
||||
}
|
||||
if (configurationCaRootAuthorityChanged) {
|
||||
final String value = caRootAuthorityTextField.getValue() != null ? caRootAuthorityTextField.getValue() : "";
|
||||
getSystemManagement().addOrUpdateConfiguration(new TenantConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME.getKeyName(), value));
|
||||
getTenantConfigurationManagement()
|
||||
.addOrUpdateConfiguration(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,13 +152,15 @@ public class CertificateAuthenticationConfigurationItem extends AbstractAuthenti
|
||||
configurationEnabledChange = false;
|
||||
configurationCaRootAuthorityChanged = false;
|
||||
|
||||
configurationEnabled = getSystemManagement().getConfigurationValue(getConfigurationKey(), Boolean.class);
|
||||
configurationEnabled = getTenantConfigurationManagement()
|
||||
.getConfigurationValue(getConfigurationKey(), Boolean.class).getValue();
|
||||
caRootAuthorityTextField.setValue(getCaRootAuthorityValue());
|
||||
}
|
||||
|
||||
private String getCaRootAuthorityValue() {
|
||||
return getSystemManagement()
|
||||
.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class);
|
||||
return getTenantConfigurationManagement()
|
||||
.getConfigurationValue(TenantConfigurationKey.AUTHENTICATION_MODE_HEADER_AUTHORITY_NAME, String.class)
|
||||
.getValue();
|
||||
}
|
||||
|
||||
private void setDetailVisible(final boolean visible) {
|
||||
|
||||
@@ -10,8 +10,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.security.SecurityTokenGenerator;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.ui.components.SPUIComponentProvider;
|
||||
@@ -62,12 +61,12 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac
|
||||
private VerticalLayout detailLayout;
|
||||
|
||||
/**
|
||||
* @param configurationKey
|
||||
* @param systemManagement
|
||||
* @param tenantConfigurationManagement
|
||||
*/
|
||||
@Autowired
|
||||
public GatewaySecurityTokenAuthenticationConfigurationItem(final SystemManagement systemManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, systemManagement);
|
||||
public GatewaySecurityTokenAuthenticationConfigurationItem(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,13 +162,13 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac
|
||||
}
|
||||
|
||||
private String getSecurityTokenName() {
|
||||
return getSystemManagement().getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME, String.class);
|
||||
return getTenantConfigurationManagement().getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME, String.class).getValue();
|
||||
}
|
||||
|
||||
private String getSecurityTokenKey() {
|
||||
return getSystemManagement().getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class);
|
||||
return getTenantConfigurationManagement().getConfigurationValue(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY, String.class).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,20 +183,19 @@ public class GatewaySecurityTokenAuthenticationConfigurationItem extends Abstrac
|
||||
@Override
|
||||
public void save() {
|
||||
if (configurationEnabledChange) {
|
||||
getSystemManagement().addOrUpdateConfiguration(new TenantConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED.getKeyName(),
|
||||
String.valueOf(configurationEnabled)));
|
||||
getTenantConfigurationManagement().addOrUpdateConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_ENABLED, configurationEnabled);
|
||||
}
|
||||
|
||||
if (keyNameChanged) {
|
||||
getSystemManagement().addOrUpdateConfiguration(new TenantConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME.getKeyName(),
|
||||
gatewayTokenNameTextField.getValue()));
|
||||
getTenantConfigurationManagement().addOrUpdateConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_NAME,
|
||||
gatewayTokenNameTextField.getValue());
|
||||
}
|
||||
if (keyChanged) {
|
||||
getSystemManagement().addOrUpdateConfiguration(new TenantConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY.getKeyName(),
|
||||
gatewayTokenkeyLabel.getValue()));
|
||||
getTenantConfigurationManagement().addOrUpdateConfiguration(
|
||||
TenantConfigurationKey.AUTHENTICATION_MODE_GATEWAY_SECURITY_TOKEN_KEY,
|
||||
gatewayTokenkeyLabel.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,7 @@ package org.eclipse.hawkbit.ui.tenantconfiguration.authentication;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.eclipse.hawkbit.repository.SystemManagement;
|
||||
import org.eclipse.hawkbit.repository.model.TenantConfiguration;
|
||||
import org.eclipse.hawkbit.repository.TenantConfigurationManagement;
|
||||
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationKey;
|
||||
import org.eclipse.hawkbit.ui.utils.I18N;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -44,8 +43,9 @@ public class TargetSecurityTokenAuthenticationConfigurationItem extends Abstract
|
||||
* the system management to retrie the configuration
|
||||
*/
|
||||
@Autowired
|
||||
public TargetSecurityTokenAuthenticationConfigurationItem(final SystemManagement systemManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED, systemManagement);
|
||||
public TargetSecurityTokenAuthenticationConfigurationItem(
|
||||
final TenantConfigurationManagement tenantConfigurationManagement) {
|
||||
super(TenantConfigurationKey.AUTHENTICATION_MODE_TARGET_SECURITY_TOKEN_ENABLED, tenantConfigurationManagement);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,15 +87,16 @@ public class TargetSecurityTokenAuthenticationConfigurationItem extends Abstract
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
if (configurationEnabledChange) {
|
||||
getSystemManagement().addOrUpdateConfiguration(
|
||||
new TenantConfiguration(getConfigurationKey().getKeyName(), String.valueOf(configurationEnabled)));
|
||||
if (!configurationEnabledChange) {
|
||||
return;
|
||||
}
|
||||
getTenantConfigurationManagement().addOrUpdateConfiguration(getConfigurationKey(), configurationEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void undo() {
|
||||
configurationEnabledChange = false;
|
||||
configurationEnabled = getSystemManagement().getConfigurationValue(getConfigurationKey(), Boolean.class);
|
||||
configurationEnabled = getTenantConfigurationManagement()
|
||||
.getConfigurationValue(getConfigurationKey(), Boolean.class).getValue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* 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.ui.tenantconfiguration.polling;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.ui.tenantconfiguration.ConfigurationItem;
|
||||
|
||||
import com.vaadin.data.Property.ValueChangeEvent;
|
||||
import com.vaadin.data.Property.ValueChangeListener;
|
||||
import com.vaadin.ui.Alignment;
|
||||
import com.vaadin.ui.CheckBox;
|
||||
import com.vaadin.ui.GridLayout;
|
||||
|
||||
/**
|
||||
* The DurationConfigField consists of three vaadin fields. A {@link #Label}
|
||||
* {@link #DurationField} and a {@link #CheckBox}. The user can then enter a
|
||||
* duration in the DurationField or he can configure using the global duration
|
||||
* by changing the CheckBox.
|
||||
*/
|
||||
public class DurationConfigField extends GridLayout implements ConfigurationItem {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final List<ConfigurationItemChangeListener> configurationChangeListeners = new ArrayList<>();
|
||||
|
||||
private final CheckBox checkBox = new CheckBox();
|
||||
private final DurationField durationField = new DurationField();
|
||||
private Duration globalDuration;
|
||||
|
||||
private DurationConfigField() {
|
||||
super(2, 2);
|
||||
|
||||
this.addStyleName("duration-config-field");
|
||||
this.setSpacing(true);
|
||||
this.setImmediate(true);
|
||||
this.setColumnExpandRatio(1, 1.0F);
|
||||
|
||||
this.addComponent(checkBox, 0, 0);
|
||||
this.setComponentAlignment(checkBox, Alignment.MIDDLE_LEFT);
|
||||
|
||||
this.addComponent(durationField, 1, 0);
|
||||
this.setComponentAlignment(durationField, Alignment.MIDDLE_LEFT);
|
||||
|
||||
checkBox.addValueChangeListener(event->checkBoxChange());
|
||||
durationField.addValueChangeListener(event->notifyConfigurationChanged());
|
||||
}
|
||||
|
||||
private void checkBoxChange() {
|
||||
durationField.setEnabled(checkBox.getValue());
|
||||
|
||||
if (!checkBox.getValue()) {
|
||||
durationField.setDuration(globalDuration);
|
||||
}
|
||||
|
||||
notifyConfigurationChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* has to be called before using, see Builder Implementation.
|
||||
*
|
||||
* @param tenantDuration
|
||||
* tenant specific duration value
|
||||
* @param globalDuration
|
||||
* duration value which is stored in the global configuration
|
||||
*/
|
||||
private void init(final Duration globalDuration, final Duration tenantDuration) {
|
||||
this.globalDuration = globalDuration;
|
||||
this.setValue(tenantDuration);
|
||||
}
|
||||
|
||||
private void setCheckBoxTooltip(final String label) {
|
||||
checkBox.setDescription(label);
|
||||
}
|
||||
|
||||
private void setAllowedRange(final Duration minimumDuration, final Duration maximumDuration) {
|
||||
durationField.setMinimumDuration(minimumDuration);
|
||||
durationField.setMaximumDuration(maximumDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the duration field
|
||||
*
|
||||
* @param tenantDuration
|
||||
* duration which will be set in to the duration field, when
|
||||
* {@code null} the global configuration will be used.
|
||||
*/
|
||||
public void setValue(final Duration tenantDuration) {
|
||||
if (tenantDuration == null) {
|
||||
// no tenant specific configuration
|
||||
checkBox.setValue(false);
|
||||
durationField.setDuration(globalDuration);
|
||||
durationField.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
checkBox.setValue(true);
|
||||
durationField.setDuration(tenantDuration);
|
||||
durationField.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration of the duration field or null, when the user has
|
||||
* configured to use the global value.
|
||||
*/
|
||||
public Duration getValue() {
|
||||
if (checkBox.getValue()) {
|
||||
return durationField.getDuration();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserInputValid() {
|
||||
return !checkBox.getValue() || (durationField.isValid() && durationField.getValue() != null);
|
||||
}
|
||||
|
||||
private void notifyConfigurationChanged() {
|
||||
configurationChangeListeners.forEach(listener -> listener.configurationHasChanged());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addChangeListener(final ConfigurationItemChangeListener listener) {
|
||||
configurationChangeListeners.add(listener);
|
||||
}
|
||||
|
||||
public static DurationConfigFieldBuilder builder() {
|
||||
return new DurationConfigFieldBuilder();
|
||||
}
|
||||
|
||||
public static class DurationConfigFieldBuilder {
|
||||
private final DurationConfigField field;
|
||||
|
||||
private Duration globalDuration = null;
|
||||
private Duration tenantDuration = null;
|
||||
|
||||
private DurationConfigFieldBuilder() {
|
||||
field = new DurationConfigField();
|
||||
};
|
||||
|
||||
public DurationConfigFieldBuilder checkBoxTooltip(final String label) {
|
||||
field.setCheckBoxTooltip(label);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DurationConfigFieldBuilder globalDuration(final Duration globalDuration) {
|
||||
this.globalDuration = globalDuration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DurationConfigFieldBuilder caption(final String caption) {
|
||||
field.setCaption(caption);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DurationConfigFieldBuilder range(final Duration minDuration, final Duration maxDuration) {
|
||||
field.setAllowedRange(minDuration, maxDuration);
|
||||
return this;
|
||||
}
|
||||
|
||||
public DurationConfigFieldBuilder tenantDuration(final Duration tenantDuration) {
|
||||
this.tenantDuration = tenantDuration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DurationConfigField build() {
|
||||
if (globalDuration == null) {
|
||||
throw new IllegalStateException(
|
||||
"Cannot build DurationConfigField without a value for global duration.");
|
||||
}
|
||||
|
||||
field.init(globalDuration, tenantDuration);
|
||||
return field;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/**
|
||||
* 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.ui.tenantconfiguration.polling;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.vaadin.data.Property;
|
||||
import com.vaadin.data.Validator.InvalidValueException;
|
||||
import com.vaadin.data.util.converter.Converter.ConversionException;
|
||||
import com.vaadin.shared.ui.datefield.Resolution;
|
||||
import com.vaadin.ui.DateField;
|
||||
import com.vaadin.ui.themes.ValoTheme;
|
||||
|
||||
/**
|
||||
* This class represents a Field which is optimized to enter a time duration in
|
||||
* form HH:mm:ss (see {@link #DURATION_FORMAT_STIRNG}). It uses the vaadin
|
||||
* DateField as a basic element, but the format is optimized for the duration
|
||||
* input. For a correct view of the popup it is recommended not to display the
|
||||
* css-class "v-datefield-calendarpanel-header" and
|
||||
* "v-datefield-calendarpanel-body" (see systemconfig.scss}
|
||||
*/
|
||||
public class DurationField extends DateField {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String CSS_STYLE_NAME = "durationfield";
|
||||
|
||||
private static final String ADDITIONAL_DURATION_STRING = "HHmmss";
|
||||
private static final String DURATION_FORMAT_STIRNG = "HH:mm:ss";
|
||||
|
||||
private static final ZoneId ZONEID_UTC = ZoneId.of("+0");
|
||||
|
||||
private static final Duration MAXIMUM_DURATION = Duration.ofHours(23).plusMinutes(59).plusSeconds(59);
|
||||
|
||||
private final SimpleDateFormat durationFormat = new SimpleDateFormat(DURATION_FORMAT_STIRNG);
|
||||
private final SimpleDateFormat additionalFormat = new SimpleDateFormat(ADDITIONAL_DURATION_STRING);
|
||||
|
||||
private Date minimumDuration;
|
||||
private Date maximumDuration;
|
||||
|
||||
/**
|
||||
* Creates a DurationField
|
||||
*/
|
||||
protected DurationField() {
|
||||
super();
|
||||
|
||||
this.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||
durationFormat.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||
additionalFormat.setTimeZone(TimeZone.getTimeZone(ZONEID_UTC));
|
||||
durationFormat.setLenient(false);
|
||||
additionalFormat.setLenient(false);
|
||||
|
||||
this.setResolution(Resolution.SECOND);
|
||||
this.setDateFormat(DURATION_FORMAT_STIRNG);
|
||||
this.addStyleName(CSS_STYLE_NAME);
|
||||
this.addStyleName(ValoTheme.TEXTFIELD_TINY);
|
||||
this.setWidth("100px");
|
||||
|
||||
// needed that popup shows a 24h clock
|
||||
this.setLocale(Locale.GERMANY);
|
||||
|
||||
this.addValueChangeListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to handle a non-empty date string from the client
|
||||
* if the client could not parse it as a Date. In the current case two
|
||||
* different parsing schemas are tried. If parsing is not possible a
|
||||
* ConversionException is thrown which marks the DurationField as invalid.
|
||||
*/
|
||||
@Override
|
||||
protected Date handleUnparsableDateString(final String value) throws ConversionException {
|
||||
|
||||
try {
|
||||
return durationFormat.parse(value);
|
||||
|
||||
} catch (final ParseException e1) {
|
||||
try {
|
||||
|
||||
return additionalFormat.parse("000000".substring(value.length() <= 6 ? value.length() : 6) + value);
|
||||
} catch (final ParseException e2) {
|
||||
// if Parsing is not possible ConversionException is thrown
|
||||
}
|
||||
}
|
||||
throw new ConversionException("input is not in HH:MM:SS format.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChange(final Property.ValueChangeEvent event) {
|
||||
// do not delete this method, even when removing the code inside this
|
||||
// method. This method overwrites the super method, which is
|
||||
// necessary, that parsing works correctly on pressing enter key
|
||||
|
||||
if (!(event.getProperty() instanceof DurationField)) {
|
||||
return;
|
||||
}
|
||||
final Date value = (Date) event.getProperty().getValue();
|
||||
|
||||
// setValue() calls valueChanged again, when the minimum is greater
|
||||
// than the maximum this can lead to an endless loop
|
||||
if (value != null && minimumDuration != null && maximumDuration != null
|
||||
&& minimumDuration.before(maximumDuration)) {
|
||||
|
||||
if (compareTimeOfDates(value, maximumDuration) > 0) {
|
||||
((DateField) event.getProperty()).setValue(maximumDuration);
|
||||
}
|
||||
|
||||
if (compareTimeOfDates(minimumDuration, value) > 0) {
|
||||
((DateField) event.getProperty()).setValue(minimumDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(final Date value) throws InvalidValueException {
|
||||
super.validate(value);
|
||||
|
||||
if (value != null && maximumDuration != null && compareTimeOfDates(value, maximumDuration) > 0) {
|
||||
throw new InvalidValueException("value is greater than the allowed maximum value");
|
||||
}
|
||||
|
||||
if (value != null && minimumDuration != null && compareTimeOfDates(minimumDuration, value) > 0) {
|
||||
throw new InvalidValueException("value is smaller than the allowed minimum value");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the duration value
|
||||
*
|
||||
* @param duration
|
||||
* duration, only values <= 23:59:59 are excepted
|
||||
*/
|
||||
public void setDuration(@NotNull final Duration duration) {
|
||||
if (duration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||
throw new IllegalArgumentException("The duaration has to be smaller than 23:59:59.");
|
||||
}
|
||||
super.setValue(durationToDate(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration value of the TextField
|
||||
*
|
||||
* @return duration which is written in the vaadin Field
|
||||
*/
|
||||
public Duration getDuration() {
|
||||
if (this.getValue() == null) {
|
||||
return null;
|
||||
}
|
||||
return dateToDuration(this.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimal allowed duration value as a String
|
||||
*
|
||||
* @param minimumDuration
|
||||
* minimum Duration, only values smaller 23:59:59 are excepted
|
||||
*/
|
||||
public void setMinimumDuration(@NotNull final Duration minimumDuration) {
|
||||
if (minimumDuration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||
throw new IllegalArgumentException("The minimum duaration has to be smaller than 23:59:59.");
|
||||
}
|
||||
this.minimumDuration = durationToDate(minimumDuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum allowed duration value as a String
|
||||
*
|
||||
* @param maximumDuration
|
||||
* maximumDuration, only values smaller 23:59:59 are excepted
|
||||
*/
|
||||
public void setMaximumDuration(@NotNull final Duration maximumDuration) {
|
||||
if (maximumDuration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||
throw new IllegalArgumentException("The maximum duaration has to be smaller than 23:59:59.");
|
||||
}
|
||||
this.maximumDuration = durationToDate(maximumDuration);
|
||||
}
|
||||
|
||||
private static Date durationToDate(final Duration duration) {
|
||||
if (duration.compareTo(MAXIMUM_DURATION) > 0) {
|
||||
throw new IllegalArgumentException("The duaration has to be smaller than 23:59:59.");
|
||||
}
|
||||
|
||||
final LocalTime lt = LocalTime.ofNanoOfDay(duration.toNanos());
|
||||
return Date.from(lt.atDate(LocalDate.now(ZONEID_UTC)).atZone(ZONEID_UTC).toInstant());
|
||||
}
|
||||
|
||||
private static Duration dateToDuration(final Date date) {
|
||||
final LocalTime endExclusive = LocalDateTime.ofInstant(date.toInstant(), ZONEID_UTC).toLocalTime();
|
||||
return Duration.between(LocalTime.MIDNIGHT, LocalTime.from(endExclusive));
|
||||
}
|
||||
|
||||
/**
|
||||
* Because parsing done by base class returns a different date than parsing
|
||||
* done by the user or converting duration to a date. But for the
|
||||
* DurationField comparison only the time is important. This function helps
|
||||
* comparing the time and ignores the values for day, month and year.
|
||||
*
|
||||
* @param d1
|
||||
* date, which time will compared with the time of d2
|
||||
* @param d2
|
||||
* date, which time will compared with the time of d1
|
||||
* @return the value 0 if the time represented d1 is equal to the time
|
||||
* represented by d2; a value less than 0 if the time of d1 is
|
||||
* before the time of d2; and a value greater than 0 if the time of
|
||||
* d1 is after the time represented by d2.
|
||||
*/
|
||||
private int compareTimeOfDates(final Date d1, final Date d2) {
|
||||
final LocalTime lt1 = LocalDateTime.ofInstant(d1.toInstant(), ZONEID_UTC).toLocalTime();
|
||||
final LocalTime lt2 = LocalDateTime.ofInstant(d2.toInstant(), ZONEID_UTC).toLocalTime();
|
||||
|
||||
return lt1.compareTo(lt2);
|
||||
}
|
||||
}
|
||||
@@ -44,5 +44,11 @@
|
||||
bottom: 13px;
|
||||
color: $button-icon-color;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.durationfield .v-datefield-calendarpanel-header,
|
||||
.durationfield .v-datefield-calendarpanel-body {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -390,12 +390,17 @@ link.support.name=Support
|
||||
link.usermanagement.name=User Management
|
||||
|
||||
# System Configuration View
|
||||
notification.configuration.save=Saved changes
|
||||
notification.configuration.save.successful=Saved changes
|
||||
notification.configuration.save.notpossible = Saving was not possible, because of invalid user input.
|
||||
configuration.defaultdistributionset.title=Distribution Set Type
|
||||
configuration.defaultdistributionset.select.label=Select the default Distribution Set type:
|
||||
configuration.savebutton.tooltip=Save Configurations
|
||||
configuration.cancellbutton.tooltip=Cancel Configurations
|
||||
configuration.authentication.title=Authentication Configuration
|
||||
configuration.polling.title=Polling Configuration
|
||||
configuration.polling.time=Polling Time
|
||||
configuration.polling.overduetime=Polling Overdue Time
|
||||
configuration.polling.custom.value=use a custom value
|
||||
|
||||
#Calendar
|
||||
calendar.year=year
|
||||
|
||||
@@ -380,6 +380,9 @@ configuration.defaultdistributionset.select.label=Select the default Distributio
|
||||
configuration.savebutton.tooltip=Save Configurations
|
||||
configuration.cancellbutton.tooltip=Cancel Configurations
|
||||
configuration.authentication.title=Authentication Configuration
|
||||
controller.polling.title=Polling Configuration
|
||||
controller.polling.time=Polling Time
|
||||
controller.polling.overduetime=Polling Overdue Time
|
||||
|
||||
#Calendar
|
||||
calendar.year=year
|
||||
|
||||
Reference in New Issue
Block a user