Incorporated the review comments.
Signed-off-by: Gaurav <gaurav.sahay@in.bosch.com>
This commit is contained in:
@@ -73,6 +73,7 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
|
|||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
@@ -290,6 +291,9 @@ public class SecurityManagedConfiguration {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SecurityProperties springSecurityProperties;
|
private SecurityProperties springSecurityProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure(final HttpSecurity http) throws Exception {
|
protected void configure(final HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
@@ -318,14 +322,14 @@ public class SecurityManagedConfiguration {
|
|||||||
userAuthenticationFilter.destroy();
|
userAuthenticationFilter.destroy();
|
||||||
}
|
}
|
||||||
}, RequestHeaderAuthenticationFilter.class)
|
}, RequestHeaderAuthenticationFilter.class)
|
||||||
.addFilterAfter(
|
.addFilterAfter(new AuthenticationSuccessTenantMetadataCreationFilter(systemManagement,
|
||||||
new AuthenticationSuccessTenantMetadataCreationFilter(tenantAware, systemManagement),
|
systemSecurityContext), SessionManagementFilter.class)
|
||||||
SessionManagementFilter.class)
|
|
||||||
.authorizeRequests().anyRequest().authenticated()
|
.authorizeRequests().anyRequest().authenticated()
|
||||||
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
|
.antMatchers(MgmtRestConstants.BASE_SYSTEM_MAPPING + "/admin/**")
|
||||||
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN);
|
.hasAnyAuthority(SpPermission.SYSTEM_ADMIN);
|
||||||
|
|
||||||
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
|
httpSec.httpBasic().and().exceptionHandling().authenticationEntryPoint(basicAuthEntryPoint);
|
||||||
|
httpSec.anonymous().disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,12 +526,15 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SystemManagement systemManagement;
|
private SystemManagement systemManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
|
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
|
||||||
|
|
||||||
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
|
if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
|
||||||
systemManagement
|
systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(),
|
||||||
.getTenantMetadata(((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
|
((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
|
||||||
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
|
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
|
||||||
// TODO: vaadin4spring-ext-security does not give us the
|
// TODO: vaadin4spring-ext-security does not give us the
|
||||||
// fullyAuthenticatedToken
|
// fullyAuthenticatedToken
|
||||||
@@ -536,7 +543,8 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
|
|||||||
// LoginView. This needs to be changed with the update of
|
// LoginView. This needs to be changed with the update of
|
||||||
// vaadin4spring 0.0.7 because it
|
// vaadin4spring 0.0.7 because it
|
||||||
// has been fixed.
|
// has been fixed.
|
||||||
systemManagement.getTenantMetadata("DEFAULT");
|
final String defaultTenant = "DEFAULT";
|
||||||
|
systemSecurityContext.runAsSystemAsTenant(() -> systemManagement.getTenantMetadata(), defaultTenant);
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onAuthenticationSuccess(authentication);
|
super.onAuthenticationSuccess(authentication);
|
||||||
@@ -548,13 +556,13 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
|
|||||||
*/
|
*/
|
||||||
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
|
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
|
||||||
|
|
||||||
private final TenantAware tenantAware;
|
|
||||||
private final SystemManagement systemManagement;
|
private final SystemManagement systemManagement;
|
||||||
|
private final SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
AuthenticationSuccessTenantMetadataCreationFilter(final TenantAware tenantAware,
|
AuthenticationSuccessTenantMetadataCreationFilter(final SystemManagement systemManagement,
|
||||||
final SystemManagement systemManagement) {
|
final SystemSecurityContext systemSecurityContext) {
|
||||||
this.tenantAware = tenantAware;
|
|
||||||
this.systemManagement = systemManagement;
|
this.systemManagement = systemManagement;
|
||||||
|
this.systemSecurityContext = systemSecurityContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -565,14 +573,16 @@ class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {
|
|||||||
@Override
|
@Override
|
||||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
|
lazyCreateTenantMetadata();
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
|
||||||
final String currentTenant = tenantAware.getCurrentTenant();
|
|
||||||
if (currentTenant != null) {
|
|
||||||
// lazy initialize tenant meta data after successful authentication
|
|
||||||
systemManagement.getTenantMetadata(currentTenant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chain.doFilter(request, response);
|
private void lazyCreateTenantMetadata() {
|
||||||
|
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (authentication != null && authentication.isAuthenticated()) {
|
||||||
|
systemSecurityContext.runAsSystem(() -> systemManagement.getTenantMetadata());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.ddi.rest.resource;
|
package org.eclipse.hawkbit.ddi.rest.resource;
|
||||||
|
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE;
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS;
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION;
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.SYSTEM_ROLE;
|
||||||
import static org.fest.assertions.api.Assertions.assertThat;
|
import static org.fest.assertions.api.Assertions.assertThat;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
@@ -23,7 +27,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
|
||||||
import org.eclipse.hawkbit.repository.model.Action;
|
import org.eclipse.hawkbit.repository.model.Action;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
@@ -57,7 +60,8 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.")
|
@Description("Ensures that targets cannot be created e.g. in plug'n play scenarios when tenant does not exists but can be created if the tenant exists.")
|
||||||
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = "ROLE_CONTROLLER", autoCreateTenant = false)
|
@WithUser(tenantId = "tenantDoesNotExists", allSpPermissions = true, authorities = { CONTROLLER_ROLE,
|
||||||
|
SYSTEM_ROLE }, autoCreateTenant = false)
|
||||||
public void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception {
|
public void targetCannotBeRegisteredIfTenantDoesNotExistsButWhenExists() throws Exception {
|
||||||
|
|
||||||
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
|
mvc.perform(get("/default-tenant/", tenantAware.getCurrentTenant())).andDo(MockMvcResultPrinter.print())
|
||||||
@@ -91,10 +95,8 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
|
|||||||
|
|
||||||
// make a poll, audit information should not be changed, run as
|
// make a poll, audit information should not be changed, run as
|
||||||
// controller principal!
|
// controller principal!
|
||||||
securityRule.runAs(
|
securityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||||
WithSpringAuthorityRule.withUser("controller", SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), () -> {
|
mvc.perform(get("/{tenant}/controller/v1/" + knownTargetControllerId, tenantAware.getCurrentTenant()))
|
||||||
mvc.perform(
|
|
||||||
get("/{tenant}/controller/v1/" + knownTargetControllerId, tenantAware.getCurrentTenant()))
|
|
||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk());
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@@ -143,16 +145,13 @@ public class DdiRootControllerTest extends AbstractRestIntegrationTestWithMongoD
|
|||||||
@Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.")
|
@Description("Ensures that tenant specific polling time, which is saved in the db, is delivered to the controller.")
|
||||||
@WithUser(principal = "knownpricipal", allSpPermissions = false)
|
@WithUser(principal = "knownpricipal", allSpPermissions = false)
|
||||||
public void pollWithModifiedGloablPollingTime() throws Exception {
|
public void pollWithModifiedGloablPollingTime() throws Exception {
|
||||||
securityRule.runAs(
|
securityRule.runAs(WithSpringAuthorityRule.withUser("tenantadmin", HAS_AUTH_TENANT_CONFIGURATION), () -> {
|
||||||
WithSpringAuthorityRule.withUser("tenantadmin", SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION),
|
|
||||||
() -> {
|
|
||||||
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
|
tenantConfigurationManagement.addOrUpdateConfiguration(TenantConfigurationKey.POLLING_TIME_INTERVAL,
|
||||||
"00:02:00");
|
"00:02:00");
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
securityRule.runAs(
|
securityRule.runAs(WithSpringAuthorityRule.withUser("controller", CONTROLLER_ROLE_ANONYMOUS), () -> {
|
||||||
WithSpringAuthorityRule.withUser("controller", SpringEvalExpressions.CONTROLLER_ROLE_ANONYMOUS), () -> {
|
|
||||||
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
|
mvc.perform(get("/{tenant}/controller/v1/4711", tenantAware.getCurrentTenant()))
|
||||||
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
.andDo(MockMvcResultPrinter.print()).andExpect(status().isOk())
|
||||||
.andExpect(content().contentType(MediaTypes.HAL_JSON))
|
.andExpect(content().contentType(MediaTypes.HAL_JSON))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import org.eclipse.hawkbit.repository.model.DistributionSetMetadata;
|
|||||||
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
import org.eclipse.hawkbit.repository.model.SoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
import org.eclipse.hawkbit.repository.model.TargetWithActionType;
|
||||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
import org.eclipse.hawkbit.security.SystemSecurityContext;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -72,15 +72,15 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SystemManagement systemManagement;
|
private SystemManagement systemManagement;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TenantAware currentTenant;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private EntityFactory entityFactory;
|
private EntityFactory entityFactory;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private DistributionSetManagement distributionSetManagement;
|
private DistributionSetManagement distributionSetManagement;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemSecurityContext systemSecurityContext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
|
public ResponseEntity<PagedList<MgmtDistributionSet>> getDistributionSets(
|
||||||
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
@RequestParam(value = MgmtRestConstants.REQUEST_PARAMETER_PAGING_OFFSET, defaultValue = MgmtRestConstants.REQUEST_PARAMETER_PAGING_DEFAULT_OFFSET) final int pagingOffsetParam,
|
||||||
@@ -119,8 +119,9 @@ public class MgmtDistributionSetResource implements MgmtDistributionSetRestApi {
|
|||||||
|
|
||||||
LOG.debug("creating {} distribution sets", sets.size());
|
LOG.debug("creating {} distribution sets", sets.size());
|
||||||
// set default Ds type if ds type is null
|
// set default Ds type if ds type is null
|
||||||
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(this.systemManagement
|
final String defaultDsKey = systemSecurityContext
|
||||||
.getTenantMetadata(this.currentTenant.getCurrentTenant()).getDefaultDsType().getKey()));
|
.runAsSystem(() -> this.systemManagement.getTenantMetadata().getDefaultDsType().getKey());
|
||||||
|
sets.stream().filter(ds -> ds.getType() == null).forEach(ds -> ds.setType(defaultDsKey));
|
||||||
|
|
||||||
final Iterable<DistributionSet> createdDSets = this.distributionSetManagement
|
final Iterable<DistributionSet> createdDSets = this.distributionSetManagement
|
||||||
.createDistributionSets(MgmtDistributionSetMapper.dsFromRequest(sets, this.softwareManagement,
|
.createDistributionSets(MgmtDistributionSetMapper.dsFromRequest(sets, this.softwareManagement,
|
||||||
|
|||||||
@@ -40,10 +40,29 @@
|
|||||||
<groupId>org.springframework.hateoas</groupId>
|
<groupId>org.springframework.hateoas</groupId>
|
||||||
<artifactId>spring-hateoas</artifactId>
|
<artifactId>spring-hateoas</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Optional -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- TEST -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ru.yandex.qatools.allure</groupId>
|
||||||
|
<artifactId>allure-junit-adaptor</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easytesting</groupId>
|
||||||
|
<artifactId>fest-assert-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.easytesting</groupId>
|
||||||
|
<artifactId>fest-assert</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -183,6 +183,8 @@ public interface ControllerManagement {
|
|||||||
* @return the security context of the target, in case no target exists for
|
* @return the security context of the target, in case no target exists for
|
||||||
* the given controllerId {@code null} is returned
|
* the given controllerId {@code null} is returned
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.IS_CONTROLLER + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
|
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET_SEC_TOKEN)
|
||||||
String getSecurityTokenByControllerId(@NotEmpty String controllerId);
|
String getSecurityTokenByControllerId(@NotEmpty String controllerId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ public interface DistributionSetManagement {
|
|||||||
@NotNull Pageable pageable);
|
@NotNull Pageable pageable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all meta data by the given distribution set id.
|
* Finds all meta data by the given distribution set id.
|
||||||
*
|
*
|
||||||
* @param distributionSetId
|
* @param distributionSetId
|
||||||
* the distribution set id to retrieve the meta data from
|
* the distribution set id to retrieve the meta data from
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ public interface SoftwareManagement {
|
|||||||
* to search for
|
* to search for
|
||||||
* @return {@link List} of found {@link SoftwareModule}s
|
* @return {@link List} of found {@link SoftwareModule}s
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
|
||||||
List<SoftwareModule> findSoftwareModulesById(@NotEmpty Collection<Long> ids);
|
List<SoftwareModule> findSoftwareModulesById(@NotEmpty Collection<Long> ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -484,7 +485,7 @@ public interface SoftwareManagement {
|
|||||||
SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm);
|
SoftwareModuleType updateSoftwareModuleType(@NotNull SoftwareModuleType sm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* finds all meta data by the given software module id.
|
* Finds all meta data by the given software module id.
|
||||||
*
|
*
|
||||||
* @param softwareModuleId
|
* @param softwareModuleId
|
||||||
* the software module id to retrieve the meta data from
|
* the software module id to retrieve the meta data from
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ public interface SystemManagement {
|
|||||||
/**
|
/**
|
||||||
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
|
* @return {@link TenantMetaData} of {@link TenantAware#getCurrentTenant()}
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
|
+ SpringEvalExpressions.HAS_AUTH_READ_TARGET + SpringEvalExpressions.HAS_AUTH_OR
|
||||||
|
+ SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||||
TenantMetaData getTenantMetadata();
|
TenantMetaData getTenantMetadata();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,6 +80,7 @@ public interface SystemManagement {
|
|||||||
* to retrieve data for
|
* to retrieve data for
|
||||||
* @return {@link TenantMetaData} of given tenant
|
* @return {@link TenantMetaData} of given tenant
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.IS_SYSTEM_CODE)
|
||||||
TenantMetaData getTenantMetadata(@NotNull String tenant);
|
TenantMetaData getTenantMetadata(@NotNull String tenant);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -86,6 +90,7 @@ public interface SystemManagement {
|
|||||||
* to update
|
* to update
|
||||||
* @return updated {@link TenantMetaData} entity
|
* @return updated {@link TenantMetaData} entity
|
||||||
*/
|
*/
|
||||||
|
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_TENANT_CONFIGURATION)
|
||||||
TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData);
|
TenantMetaData updateTenantMetadata(@NotNull TenantMetaData metaData);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ public class DistributionDeletedEvent extends AbstractDistributedEvent {
|
|||||||
/**
|
/**
|
||||||
* @param tenant
|
* @param tenant
|
||||||
* the tenant for this event
|
* the tenant for this event
|
||||||
* @param distributionSetId
|
* @param distributionId
|
||||||
* the ID of the distribution set which has been deleted
|
* the ID of the distribution set which has been deleted
|
||||||
*/
|
*/
|
||||||
public DistributionDeletedEvent(final String tenant, final Long distributionId) {
|
public DistributionDeletedEvent(final String tenant, final Long distributionId) {
|
||||||
|
|||||||
@@ -18,11 +18,10 @@ public class DistributionSetUpdateEvent extends AbstractBaseEntityEvent<Distribu
|
|||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor
|
||||||
*
|
* @param ds Distribution Set
|
||||||
* @param tag
|
|
||||||
* the tag which is updated
|
|
||||||
*/
|
*/
|
||||||
public DistributionSetUpdateEvent(final DistributionSet ds) {
|
public DistributionSetUpdateEvent(final DistributionSet ds) {
|
||||||
super(ds);
|
super(ds);
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ public class TargetUpdatedEvent extends AbstractBaseEntityEvent<Target> {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 5665118668865832477L;
|
private static final long serialVersionUID = 5665118668865832477L;
|
||||||
|
|
||||||
public TargetUpdatedEvent(Target baseEntity) {
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @param baseEntity Target entity
|
||||||
|
*/
|
||||||
|
public TargetUpdatedEvent(final Target baseEntity) {
|
||||||
super(baseEntity);
|
super(baseEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* 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.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
|
||||||
|
import com.google.common.reflect.ClassPath;
|
||||||
|
|
||||||
|
import ru.yandex.qatools.allure.annotations.Description;
|
||||||
|
import ru.yandex.qatools.allure.annotations.Features;
|
||||||
|
import ru.yandex.qatools.allure.annotations.Stories;
|
||||||
|
|
||||||
|
@Features("Unit Tests - Repository")
|
||||||
|
@Stories("Security Test")
|
||||||
|
public class RepositoryManagementMethodPreAuthorizeAnnotatedTest {
|
||||||
|
|
||||||
|
private static final Set<Method> METHOD_SECURITY_EXCLUSION = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
METHOD_SECURITY_EXCLUSION.add(getMethod(SystemManagement.class, "currentTenant"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Description("Verfies that repository methods are @PreAuthorize annotated")
|
||||||
|
public void repositoryManagementMethodsArePreAuthorizedAnnotated()
|
||||||
|
throws ClassNotFoundException, URISyntaxException, IOException {
|
||||||
|
final List<Class<?>> findInterfacesInPackage = findInterfacesInPackage(getClass().getPackage(),
|
||||||
|
Pattern.compile(".*Management"));
|
||||||
|
|
||||||
|
assertThat(findInterfacesInPackage).isNotEmpty();
|
||||||
|
for (final Class<?> interfaceToCheck : findInterfacesInPackage) {
|
||||||
|
assertDeclaredMethodsContainsPreAuthorizeAnnotaions(interfaceToCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all exclusion should be used, otherwise the method exlusion should be
|
||||||
|
// cleaned up again
|
||||||
|
assertThat(METHOD_SECURITY_EXCLUSION).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* asserts that the given methods are annotated with the
|
||||||
|
* {@link PreAuthorize} annotation for security. Inherited methods are not
|
||||||
|
* checked. The following methods are excluded due inherited from
|
||||||
|
* {@link Object}, like equals() or toString().
|
||||||
|
*
|
||||||
|
* @param clazz
|
||||||
|
* the class to retrieve the public declared methods
|
||||||
|
*/
|
||||||
|
private static void assertDeclaredMethodsContainsPreAuthorizeAnnotaions(final Class<?> clazz) {
|
||||||
|
final Method[] declaredMethods = clazz.getDeclaredMethods();
|
||||||
|
for (final Method method : declaredMethods) {
|
||||||
|
final boolean methodExcluded = METHOD_SECURITY_EXCLUSION.contains(method);
|
||||||
|
if (methodExcluded || method.isSynthetic() || Modifier.isPublic(method.getModifiers())) {
|
||||||
|
// skip method because it should be excluded
|
||||||
|
METHOD_SECURITY_EXCLUSION.remove(method);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);
|
||||||
|
assertThat(annotation).as("The public method " + method.getName() + " in class " + clazz.getName()
|
||||||
|
+ " is not annoated with @PreAuthorize, security leak?").isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Class<?>> findInterfacesInPackage(final Package p, final Pattern includeFilter)
|
||||||
|
throws URISyntaxException, IOException, ClassNotFoundException {
|
||||||
|
return ClassPath.from(Thread.currentThread().getContextClassLoader()).getTopLevelClasses(p.getName()).stream()
|
||||||
|
.filter(clazzInfo -> includeFilter.matcher(clazzInfo.getSimpleName()).matches())
|
||||||
|
.map(clazzInfo -> clazzInfo.load()).filter(clazz -> clazz.isInterface()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Method getMethod(final Class<?> clazz, final String methodName, final Class<?>... parameterTypes) {
|
||||||
|
try {
|
||||||
|
return clazz.getMethod(methodName, parameterTypes);
|
||||||
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
|
throw new RuntimeException(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -484,12 +484,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
|||||||
throwMetadataKeyAlreadyExists(metadata.getId().getKey());
|
throwMetadataKeyAlreadyExists(metadata.getId().getKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
final DistributionSet latestDistributionSet = findDistributionSetById(metadata.getDistributionSet().getId());
|
touch(metadata.getDistributionSet());
|
||||||
// merge base distribution set so optLockRevision gets updated and audit
|
|
||||||
// log written because
|
|
||||||
// modifying metadata is modifying the base distribution set itself for
|
|
||||||
// auditing purposes.
|
|
||||||
entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L);
|
|
||||||
return distributionSetMetadataRepository.save(metadata);
|
return distributionSetMetadataRepository.save(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,7 +499,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
|||||||
for (final JpaDistributionSetMetadata distributionSetMetadata : metadata) {
|
for (final JpaDistributionSetMetadata distributionSetMetadata : metadata) {
|
||||||
checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId());
|
checkAndThrowAlreadyIfDistributionSetMetadataExists(distributionSetMetadata.getId());
|
||||||
}
|
}
|
||||||
metadata.forEach(m -> entityManager.merge((JpaDistributionSet) findDistributionSetById(m.getDistributionSet().getId())).setLastModifiedAt(0L));
|
metadata.forEach(m -> touch(m.getDistributionSet()));
|
||||||
|
|
||||||
return new ArrayList<>(
|
return new ArrayList<>(
|
||||||
(Collection<? extends DistributionSetMetadata>) distributionSetMetadataRepository.save(metadata));
|
(Collection<? extends DistributionSetMetadata>) distributionSetMetadataRepository.save(metadata));
|
||||||
@@ -520,8 +515,7 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
|||||||
findOne(metadata.getDistributionSet(), metadata.getKey());
|
findOne(metadata.getDistributionSet(), metadata.getKey());
|
||||||
// touch it to update the lock revision because we are modifying the
|
// touch it to update the lock revision because we are modifying the
|
||||||
// DS indirectly
|
// DS indirectly
|
||||||
final DistributionSet latestDistributionSet = findDistributionSetById(metadata.getDistributionSet().getId());
|
touch(metadata.getDistributionSet());;
|
||||||
entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L);
|
|
||||||
return distributionSetMetadataRepository.save(metadata);
|
return distributionSetMetadataRepository.save(metadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,11 +523,23 @@ public class JpaDistributionSetManagement implements DistributionSetManagement {
|
|||||||
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
|
||||||
@Modifying
|
@Modifying
|
||||||
public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) {
|
public void deleteDistributionSetMetadata(final DistributionSet distributionSet, final String key) {
|
||||||
final DistributionSet latestDistributionSet = findDistributionSetById(distributionSet.getId());
|
touch(distributionSet);
|
||||||
entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L);
|
|
||||||
distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key));
|
distributionSetMetadataRepository.delete(new DsMetadataCompositeKey(distributionSet, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get the latest distribution set based on ds ID after the metadata changes for that distribution set.
|
||||||
|
* @param distributionSet Distribution set
|
||||||
|
*/
|
||||||
|
private void touch(final DistributionSet distributionSet) {
|
||||||
|
final DistributionSet latestDistributionSet = findDistributionSetById(distributionSet.getId());
|
||||||
|
// merge base distribution set so optLockRevision gets updated and audit
|
||||||
|
// log written because
|
||||||
|
// modifying metadata is modifying the base distribution set itself for
|
||||||
|
// auditing purposes.
|
||||||
|
entityManager.merge((JpaDistributionSet) latestDistributionSet).setLastModifiedAt(0L);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<DistributionSetMetadata> findDistributionSetMetadataByDistributionSetId(final Long distributionSetId,
|
public Page<DistributionSetMetadata> findDistributionSetMetadataByDistributionSetId(final Long distributionSetId,
|
||||||
final Pageable pageable) {
|
final Pageable pageable) {
|
||||||
|
|||||||
@@ -21,12 +21,17 @@ public class DescriptorEventDetails {
|
|||||||
CREATE, UPDATE;
|
CREATE, UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DescriptorEvent descriptorEvent;
|
private final DescriptorEvent descriptorEvent;
|
||||||
|
|
||||||
private ActionType actiontype;
|
private final ActionType actiontype;
|
||||||
|
|
||||||
public DescriptorEventDetails(ActionType actionType,
|
/**
|
||||||
DescriptorEvent descriptorEvent) {
|
* Constructor
|
||||||
|
* @param actionType Action type
|
||||||
|
* @param descriptorEvent Descriptor Event
|
||||||
|
*/
|
||||||
|
public DescriptorEventDetails(final ActionType actionType,
|
||||||
|
final DescriptorEvent descriptorEvent) {
|
||||||
this.descriptorEvent = descriptorEvent;
|
this.descriptorEvent = descriptorEvent;
|
||||||
this.actiontype = actionType;
|
this.actiontype = actionType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,20 @@ import org.eclipse.persistence.internal.sessions.ObjectChangeSet;
|
|||||||
import org.eclipse.persistence.queries.UpdateObjectQuery;
|
import org.eclipse.persistence.queries.UpdateObjectQuery;
|
||||||
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
|
import org.eclipse.persistence.sessions.changesets.DirectToFieldChangeRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*Helper class to get the change set for the property changes in the Entity.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
public class EntityPropertyChangeHelper<T extends TenantAwareBaseEntity> {
|
public class EntityPropertyChangeHelper<T extends TenantAwareBaseEntity> {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To get the map of entity property change set
|
||||||
|
* @param clazz
|
||||||
|
* @param event
|
||||||
|
* @return the map of the changeSet
|
||||||
|
*/
|
||||||
public static <T extends TenantAwareBaseEntity> Map<String, AbstractPropertyChangeEvent<T>.Values> getChangeSet(
|
public static <T extends TenantAwareBaseEntity> Map<String, AbstractPropertyChangeEvent<T>.Values> getChangeSet(
|
||||||
final Class<T> clazz, final DescriptorEvent event) {
|
final Class<T> clazz, final DescriptorEvent event) {
|
||||||
final T rolloutGroup = clazz.cast(event.getObject());
|
final T rolloutGroup = clazz.cast(event.getObject());
|
||||||
|
|||||||
@@ -1,63 +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.jpa;
|
|
||||||
|
|
||||||
import static org.fest.assertions.Assertions.assertThat;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
|
||||||
|
|
||||||
public class MethodSecurityUtil {
|
|
||||||
|
|
||||||
private static final Set<String> METHOD_SECURITY_EXCLUSION = new HashSet<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("equals");
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("toString");
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("hashCode");
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("clone");
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("setEnvironment");
|
|
||||||
// this method shouldn't be public on the DeploymentManagemeht but it is
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("setOverrideObsoleteUpdateActions");
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("isOverrideObsoleteUpdateActions");
|
|
||||||
// this method must be public accessible without security because it's
|
|
||||||
// necessary to acccess
|
|
||||||
// the security-token of a target without being authenticated because
|
|
||||||
// the security-token is
|
|
||||||
// the authentication process
|
|
||||||
// ControllerManagement#getSecurityTokenByControllerId()
|
|
||||||
METHOD_SECURITY_EXCLUSION.add("getSecurityTokenByControllerId");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* asserts that the given methods are annotated with the
|
|
||||||
* {@link PreAuthorize} annotation for security. Inherited methods are not
|
|
||||||
* checked. The following methods are excluded due inherited from
|
|
||||||
* {@link Object}, like equals() or toString().
|
|
||||||
*
|
|
||||||
* @param clazz
|
|
||||||
* the class to retrieve the public declared methods
|
|
||||||
*/
|
|
||||||
public static void assertDeclaredMethodsContainsPreAuthorizeAnnotaions(final Class<?> clazz) {
|
|
||||||
final Method[] declaredMethods = clazz.getDeclaredMethods();
|
|
||||||
for (final Method method : declaredMethods) {
|
|
||||||
if (!METHOD_SECURITY_EXCLUSION.contains(method.getName()) && !method.isSynthetic()
|
|
||||||
&& Modifier.isPublic(method.getModifiers())) {
|
|
||||||
final PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);
|
|
||||||
assertThat(annotation).as(
|
|
||||||
"The public method " + method.getName() + " is not annoated with @PreAuthorize, security leak?")
|
|
||||||
.isNotNull();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,10 +14,10 @@ import java.io.ByteArrayInputStream;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
import org.eclipse.hawkbit.repository.jpa.model.JpaSoftwareModule;
|
||||||
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
import org.eclipse.hawkbit.repository.model.DistributionSet;
|
||||||
import org.eclipse.hawkbit.repository.model.Target;
|
import org.eclipse.hawkbit.repository.model.Target;
|
||||||
import org.eclipse.hawkbit.repository.model.TenantMetaData;
|
|
||||||
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
import org.eclipse.hawkbit.repository.report.model.TenantUsage;
|
||||||
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
import org.eclipse.hawkbit.repository.test.util.WithSpringAuthorityRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -30,15 +30,6 @@ import ru.yandex.qatools.allure.annotations.Stories;
|
|||||||
@Stories("System Management")
|
@Stories("System Management")
|
||||||
public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB {
|
||||||
|
|
||||||
@Test
|
|
||||||
@Description("Ensures that you can create a tenant without setting the necessary security context which holds a current tenant")
|
|
||||||
public void createInitialTenantWithoutSecurityContext() {
|
|
||||||
securityRule.clear();
|
|
||||||
final String tenantToBeCreated = "newTenantToCreate";
|
|
||||||
final TenantMetaData tenantMetadata = systemManagement.getTenantMetadata(tenantToBeCreated);
|
|
||||||
assertThat(tenantMetadata).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Description("Ensures that findTenants returns all tenants and not only restricted to the tenant which currently is logged in")
|
@Description("Ensures that findTenants returns all tenants and not only restricted to the tenant which currently is logged in")
|
||||||
public void findTenantsReturnsAllTenantsNotOnlyWhichLoggedIn() throws Exception {
|
public void findTenantsReturnsAllTenantsNotOnlyWhichLoggedIn() throws Exception {
|
||||||
@@ -109,7 +100,8 @@ public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB
|
|||||||
|
|
||||||
for (int i = 0; i < tenants; i++) {
|
for (int i = 0; i < tenants; i++) {
|
||||||
final String tenantname = "tenant" + i;
|
final String tenantname = "tenant" + i;
|
||||||
securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("bumlux", tenantname), () -> {
|
securityRule.runAs(WithSpringAuthorityRule.withUserAndTenant("bumlux", tenantname, true, true,
|
||||||
|
SpringEvalExpressions.SYSTEM_ROLE), () -> {
|
||||||
systemManagement.getTenantMetadata(tenantname);
|
systemManagement.getTenantMetadata(tenantname);
|
||||||
if (artifactSize > 0) {
|
if (artifactSize > 0) {
|
||||||
createTestArtifact(random);
|
createTestArtifact(random);
|
||||||
@@ -119,8 +111,8 @@ public class SystemManagementTest extends AbstractJpaIntegrationTestWithMongoDB
|
|||||||
final List<Target> createdTargets = createTestTargets(targets);
|
final List<Target> createdTargets = createTestTargets(targets);
|
||||||
if (updates > 0) {
|
if (updates > 0) {
|
||||||
for (int x = 0; x < updates; x++) {
|
for (int x = 0; x < updates; x++) {
|
||||||
final DistributionSet ds = testdataFactory.createDistributionSet("to be deployed" + x,
|
final DistributionSet ds = testdataFactory
|
||||||
true);
|
.createDistributionSet("to be deployed" + x, true);
|
||||||
|
|
||||||
deploymentManagement.assignDistributionSet(ds, createdTargets);
|
deploymentManagement.assignDistributionSet(ds, createdTargets);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.eclipse.hawkbit.repository.test.util;
|
package org.eclipse.hawkbit.repository.test.util;
|
||||||
|
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.CONTROLLER_ROLE;
|
||||||
|
import static org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions.SYSTEM_ROLE;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
|
import org.eclipse.hawkbit.ExcludePathAwareShallowETagFilter;
|
||||||
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
import org.eclipse.hawkbit.repository.ArtifactManagement;
|
||||||
import org.eclipse.hawkbit.repository.ControllerManagement;
|
import org.eclipse.hawkbit.repository.ControllerManagement;
|
||||||
@@ -58,7 +61,7 @@ import org.springframework.web.context.WebApplicationContext;
|
|||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@WebAppConfiguration
|
@WebAppConfiguration
|
||||||
@ActiveProfiles({ "test" })
|
@ActiveProfiles({ "test" })
|
||||||
@WithUser(principal = "bumlux", allSpPermissions = true, authorities = "ROLE_CONTROLLER")
|
@WithUser(principal = "bumlux", allSpPermissions = true, authorities = { CONTROLLER_ROLE, SYSTEM_ROLE })
|
||||||
@SpringApplicationConfiguration(classes = { TestConfiguration.class })
|
@SpringApplicationConfiguration(classes = { TestConfiguration.class })
|
||||||
// destroy the context after each test class because otherwise we get problem
|
// destroy the context after each test class because otherwise we get problem
|
||||||
// when context is
|
// when context is
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
import org.eclipse.hawkbit.im.authentication.SpPermission;
|
||||||
|
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||||
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
|
import org.eclipse.hawkbit.repository.jpa.model.helper.SystemManagementHolder;
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
@@ -56,10 +57,10 @@ public class WithSpringAuthorityRule implements TestRule {
|
|||||||
annotation = description.getTestClass().getAnnotation(WithUser.class);
|
annotation = description.getTestClass().getAnnotation(WithUser.class);
|
||||||
}
|
}
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
setSecurityContext(annotation);
|
|
||||||
if (annotation.autoCreateTenant()) {
|
if (annotation.autoCreateTenant()) {
|
||||||
SystemManagementHolder.getInstance().getSystemManagement().getTenantMetadata(annotation.tenantId());
|
createTenant(annotation.tenantId());
|
||||||
}
|
}
|
||||||
|
setSecurityContext(annotation);
|
||||||
}
|
}
|
||||||
return oldContext;
|
return oldContext;
|
||||||
}
|
}
|
||||||
@@ -158,7 +159,7 @@ public class WithSpringAuthorityRule implements TestRule {
|
|||||||
final SecurityContext oldContext = SecurityContextHolder.getContext();
|
final SecurityContext oldContext = SecurityContextHolder.getContext();
|
||||||
setSecurityContext(withUser);
|
setSecurityContext(withUser);
|
||||||
if (withUser.autoCreateTenant()) {
|
if (withUser.autoCreateTenant()) {
|
||||||
SystemManagementHolder.getInstance().getSystemManagement().getTenantMetadata(withUser.tenantId());
|
createTenant(withUser.tenantId());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return callable.call();
|
return callable.call();
|
||||||
@@ -167,6 +168,18 @@ public class WithSpringAuthorityRule implements TestRule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createTenant(final String tenantId) throws Exception {
|
||||||
|
final SecurityContext oldContext = SecurityContextHolder.getContext();
|
||||||
|
setSecurityContext(privilegedUser());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SystemManagementHolder.getInstance().getSystemManagement().getTenantMetadata(tenantId);
|
||||||
|
}finally
|
||||||
|
{
|
||||||
|
after(oldContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static WithUser withUser(final String principal, final String... authorities) {
|
public static WithUser withUser(final String principal, final String... authorities) {
|
||||||
return withUserAndTenant(principal, "default", true, true, authorities);
|
return withUserAndTenant(principal, "default", true, true, authorities);
|
||||||
}
|
}
|
||||||
@@ -254,7 +267,7 @@ public class WithSpringAuthorityRule implements TestRule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] authorities() {
|
public String[] authorities() {
|
||||||
return new String[] { "ROLE_CONTROLLER" };
|
return new String[] { "ROLE_CONTROLLER", "ROLE_SYSTEM_CODE" };
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -290,6 +290,14 @@ public final class SpPermission {
|
|||||||
public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR
|
public static final String HAS_AUTH_READ_TARGET = HAS_AUTH_PREFIX + READ_TARGET + HAS_AUTH_SUFFIX + HAS_AUTH_OR
|
||||||
+ IS_SYSTEM_CODE;
|
+ IS_SYSTEM_CODE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spring security eval hasAuthority expression to check if spring
|
||||||
|
* context contains {@link SpPermission#READ_TARGET_SEC_TOKEN} or
|
||||||
|
* {@link #IS_SYSTEM_CODE}.
|
||||||
|
*/
|
||||||
|
public static final String HAS_AUTH_READ_TARGET_SEC_TOKEN = HAS_AUTH_PREFIX + READ_TARGET_SEC_TOKEN
|
||||||
|
+ HAS_AUTH_SUFFIX + HAS_AUTH_OR + IS_SYSTEM_CODE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring security eval hasAuthority expression to check if spring
|
* Spring security eval hasAuthority expression to check if spring
|
||||||
* context contains {@link SpPermission#CREATE_TARGET} or
|
* context contains {@link SpPermission#CREATE_TARGET} or
|
||||||
|
|||||||
@@ -61,11 +61,12 @@ public class DistributionSetMetadatadetailslayout extends Table {
|
|||||||
private Long selectedDistSetId;
|
private Long selectedDistSetId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Initialize the component.
|
||||||
* @param i18n
|
* @param i18n
|
||||||
* @param permissionChecker
|
* @param permissionChecker
|
||||||
* @param distributionSetManagement
|
* @param distributionSetManagement
|
||||||
* @param dsMetadataPopupLayout
|
* @param dsMetadataPopupLayout
|
||||||
|
* @param entityFactory
|
||||||
*/
|
*/
|
||||||
public void init(final I18N i18n, final SpPermissionChecker permissionChecker,
|
public void init(final I18N i18n, final SpPermissionChecker permissionChecker,
|
||||||
final DistributionSetManagement distributionSetManagement,
|
final DistributionSetManagement distributionSetManagement,
|
||||||
|
|||||||
@@ -186,6 +186,9 @@ public class SoftwareModuleDetailsTable extends Table {
|
|||||||
private void unassignSW(final ClickEvent event, final DistributionSet distributionSet,
|
private void unassignSW(final ClickEvent event, final DistributionSet distributionSet,
|
||||||
final Set<SoftwareModule> alreadyAssignedSwModules) {
|
final Set<SoftwareModule> alreadyAssignedSwModules) {
|
||||||
final SoftwareModule unAssignedSw = getSoftwareModule(event.getButton().getId(), alreadyAssignedSwModules);
|
final SoftwareModule unAssignedSw = getSoftwareModule(event.getButton().getId(), alreadyAssignedSwModules);
|
||||||
|
if (distributionSetManagement.isDistributionSetInUse(distributionSet)) {
|
||||||
|
uiNotification.displayValidationError(i18n.get("message.error.notification.ds.target.assigned",distributionSet.getName(), distributionSet.getVersion()));
|
||||||
|
} else {
|
||||||
final DistributionSet newDistributionSet = distributionSetManagement.unassignSoftwareModule(distributionSet,
|
final DistributionSet newDistributionSet = distributionSetManagement.unassignSoftwareModule(distributionSet,
|
||||||
unAssignedSw);
|
unAssignedSw);
|
||||||
manageDistUIState.setLastSelectedEntity(DistributionSetIdName.generate(newDistributionSet));
|
manageDistUIState.setLastSelectedEntity(DistributionSetIdName.generate(newDistributionSet));
|
||||||
@@ -194,6 +197,8 @@ public class SoftwareModuleDetailsTable extends Table {
|
|||||||
uiNotification.displaySuccess(i18n.get("message.sw.unassigned", unAssignedSw.getName()));
|
uiNotification.displaySuccess(i18n.get("message.sw.unassigned", unAssignedSw.getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isSoftModAvaiableForSoftType(final Set<SoftwareModule> swModulesSet,
|
private static boolean isSoftModAvaiableForSoftType(final Set<SoftwareModule> swModulesSet,
|
||||||
final SoftwareModuleType swModType) {
|
final SoftwareModuleType swModType) {
|
||||||
for (final SoftwareModule sw : swModulesSet) {
|
for (final SoftwareModule sw : swModulesSet) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.io.Serializable;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.annotation.PreDestroy;
|
import javax.annotation.PreDestroy;
|
||||||
@@ -54,7 +55,7 @@ public abstract class AbstractTagToken<T extends BaseEntity> implements Serializ
|
|||||||
|
|
||||||
protected IndexedContainer container;
|
protected IndexedContainer container;
|
||||||
|
|
||||||
protected final transient Map<Long, TagData> tagDetails = new HashMap<>();
|
protected final transient Map<Long, TagData> tagDetails = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
protected final transient Map<Long, TagData> tokensAdded = new HashMap<>();
|
protected final transient Map<Long, TagData> tokensAdded = new HashMap<>();
|
||||||
|
|
||||||
@@ -140,11 +141,13 @@ public abstract class AbstractTagToken<T extends BaseEntity> implements Serializ
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void setContainerPropertValues(final Long tagId, final String tagName, final String tagColor) {
|
protected void setContainerPropertValues(final Long tagId, final String tagName, final String tagColor) {
|
||||||
tagDetails.put(tagId, new TagData(tagId, tagName, tagColor));
|
final TagData tagData = tagDetails.putIfAbsent(tagId, new TagData(tagId, tagName, tagColor));
|
||||||
|
if(tagData == null){
|
||||||
final Item item = container.addItem(tagId);
|
final Item item = container.addItem(tagId);
|
||||||
item.getItemProperty("id").setValue(tagId);
|
item.getItemProperty("id").setValue(tagId);
|
||||||
updateItem(tagName, tagColor, item);
|
updateItem(tagName, tagColor, item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateItem(final String tagName, final String tagColor, final Item item) {
|
protected void updateItem(final String tagName, final String tagColor, final Item item) {
|
||||||
item.getItemProperty("name").setValue(tagName);
|
item.getItemProperty("name").setValue(tagName);
|
||||||
|
|||||||
@@ -364,9 +364,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable<Distribution
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (distributionSetManagement.isDistributionSetInUse(ds)) {
|
if (distributionSetManagement.isDistributionSetInUse(ds)) {
|
||||||
notification.displayValidationError(
|
notification.displayValidationError(i18n.get("message.error.notification.ds.target.assigned", ds.getName(), ds.getVersion()));
|
||||||
String.format("Distribution set %s:%s is already assigned to targets and cannot be changed",
|
|
||||||
ds.getName(), ds.getVersion()));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -472,7 +470,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable<Distribution
|
|||||||
|
|
||||||
@EventBusListenerMethod(scope = EventScope.SESSION)
|
@EventBusListenerMethod(scope = EventScope.SESSION)
|
||||||
void onEvent(final SaveActionWindowEvent event) {
|
void onEvent(final SaveActionWindowEvent event) {
|
||||||
if (event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) {
|
if (event == SaveActionWindowEvent.DELETED_DISTRIBUTIONS || event == SaveActionWindowEvent.SAVED_ASSIGNMENTS) {
|
||||||
UI.getCurrent().access(() -> refreshFilter());
|
UI.getCurrent().access(() -> refreshFilter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -552,7 +550,7 @@ public class DistributionSetTable extends AbstractNamedVersionTable<Distribution
|
|||||||
|
|
||||||
private void showMetadataDetails(final Long itemId) {
|
private void showMetadataDetails(final Long itemId) {
|
||||||
final DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(itemId);
|
final DistributionSet ds = distributionSetManagement.findDistributionSetByIdWithDetails(itemId);
|
||||||
UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds, null));
|
UI.getCurrent().addWindow(dsMetadataPopupLayout.getWindow(ds,null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNameAndVerion(final Object itemId) {
|
private String getNameAndVerion(final Object itemId) {
|
||||||
|
|||||||
@@ -386,6 +386,7 @@ message.metadata.updated = Metadata with key {0} successfully updated !
|
|||||||
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
||||||
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
||||||
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
||||||
|
message.error.notification.ds.target.assigned = Distribution set {0}:{1} is already assigned to targets and cannot be changed
|
||||||
|
|
||||||
# Login view
|
# Login view
|
||||||
notification.login.title=Welcome to Bosch IoT Software Provisioning.
|
notification.login.title=Welcome to Bosch IoT Software Provisioning.
|
||||||
|
|||||||
@@ -375,6 +375,7 @@ message.metadata.updated = Metadata with key {0} successfully updated !
|
|||||||
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
||||||
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
||||||
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
||||||
|
message.error.notification.ds.target.assigned = Distribution set {0}:{1} is already assigned to targets and cannot be changed
|
||||||
|
|
||||||
|
|
||||||
# Login view
|
# Login view
|
||||||
|
|||||||
@@ -371,6 +371,7 @@ message.metadata.updated = Metadata with key {0} successfully updated !
|
|||||||
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
message.metadata.duplicate.check = Metadata with key {0} already exists, please enter another value
|
||||||
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
message.metadata.deleted.successfully = Metadata with key {0} successfully deleted !
|
||||||
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
message.confirm.delete.metadata = Are you sure that you want to delete metadata with key {0} ?
|
||||||
|
message.error.notification.ds.target.assigned = Distribution set {0}:{1} is already assigned to targets and cannot be changed
|
||||||
|
|
||||||
# Login view
|
# Login view
|
||||||
notification.login.title=Welcome to Bosch IoT Software Provisioning.
|
notification.login.title=Welcome to Bosch IoT Software Provisioning.
|
||||||
|
|||||||
Reference in New Issue
Block a user