Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.net.URL;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.List;

@Configuration
public class ApplicationPropertiesConfiguration {
Expand Down Expand Up @@ -40,12 +39,6 @@ public ComponentProvisionerParametersProps componentProvisionerParametersProps()
return ComponentProvisionerParametersProps.builder().build();
}

@Bean("catalogItemGroupsRestrictionConfig")
@ConfigurationProperties(prefix = "catalog.user-action.groups-restriction")
public CatalogItemUserActionGroupsRestrictionProps catalogItemGroupsRestrictionConfig() {
return CatalogItemUserActionGroupsRestrictionProps.builder().build();
}

@Bean("projectsInfoServiceCacheConfig")
@ConfigurationProperties(prefix = "component-provisioner.caching.projects-info-services-cache")
public ProjectsInfoServicesCacheProps projectsInfoServicesCacheProps() {
Expand Down Expand Up @@ -115,10 +108,4 @@ public static class ComponentProvisionerParametersProps {
private String[] blacklist;
}

@Builder
@Data
public static class CatalogItemUserActionGroupsRestrictionProps {
private List<String> prefix;
private List<String> suffix;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,19 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItem;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserAction;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserActionParameter;
import org.opendevstack.component_provisioner.config.ApplicationPropertiesConfiguration;
import org.opendevstack.component_provisioner.server.controllers.exceptions.InvalidRestEntityException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.ProjectComponentAlreadyProvisionedException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.UserNotAllowedException;
import org.opendevstack.component_provisioner.server.controllers.model.ActionType;
import org.opendevstack.component_provisioner.server.model.ProvisionAction;
import org.opendevstack.component_provisioner.server.services.AuthenticationProvider;
import org.opendevstack.component_provisioner.server.services.ComponentCatalogService;
import org.opendevstack.component_provisioner.server.services.ProjectsInfoService;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.CatalogItemUserActionGroupsRestriction;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.EvaluationRestrictions;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.GroupsRestrictionsEvaluator;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.RestrictionsParams;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.UserActionEntityRestrictions;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
Expand All @@ -40,9 +34,6 @@ public class ProvisionerActionsApiValidator {

private final ComponentCatalogService componentCatalogService;
private final AuthenticationProvider authenticationProvider;
private final GroupsRestrictionsEvaluator groupsRestrictionsEvaluator;
private final ApplicationPropertiesConfiguration.CatalogItemUserActionGroupsRestrictionProps catalogItemUserActionGroupsRestrictionProps;
private final ProjectsInfoService projectsInfoService;
private final MandatoryFieldsValidator mandatoryFieldsValidator;

public void validate(ProvisionAction provisionAction) {
Expand All @@ -55,8 +46,6 @@ public void validate(ProvisionAction provisionAction) {
validateInputParams(projectKey, accessToken, componentId);

validateComponentIsNotProvisioned(projectKey, componentId);

validateUserHasPermissionsToProvision(projectKey, accessToken);
}

public void validateReceivesOnlyVisibleParameters(ProvisionAction provisionAction, CatalogItem catalogItem) {
Expand Down Expand Up @@ -94,33 +83,21 @@ public void validateMandatoryFields(ProvisionAction provisionAction, CatalogItem
mandatoryFieldsValidator.validate(provisionAction, catalogItem);
}

private void validateUserHasPermissionsToProvision(String projectKey, String accessToken) {
log.debug("Validating user has permissions to provision. projectKey: {}", projectKey);

CatalogItemUserActionGroupsRestriction catalogItemUserActionGroupsRestriction = CatalogItemUserActionGroupsRestriction.builder()
.prefix(catalogItemUserActionGroupsRestrictionProps.getPrefix())
.suffix(catalogItemUserActionGroupsRestrictionProps.getSuffix())
.build();
UserActionEntityRestrictions userActionEntityRestrictions = UserActionEntityRestrictions.builder()
.groups(catalogItemUserActionGroupsRestriction)
.build();
EvaluationRestrictions restrictions = new EvaluationRestrictions(projectKey, userActionEntityRestrictions);

List<String> userGroups = projectsInfoService.getProjectGroups(accessToken);
RestrictionsParams params = RestrictionsParams.builder()
.projectKey(projectKey)
.userGroups(userGroups)
.build();
public void validateUserHasPermissionsToProvision(CatalogItem catalogItem) {
log.debug("Validating user has permissions to provision. CatalogItem: {}", catalogItem);

var groupsEvaluationResult = groupsRestrictionsEvaluator.evaluate(restrictions, params);
boolean provisionIsRequestable = Optional.ofNullable(catalogItem)
Comment thread
sergio-soria-bi marked this conversation as resolved.
.map(CatalogItem::getUserActions)
.stream()
.flatMap(Collection::stream)
.filter(action -> ActionType.PROVISION.getValue().equals(action.getId()))
.findFirst()
.map(CatalogItemUserAction::getRequestable)
.orElse(false);

if (groupsEvaluationResult == null || Boolean.FALSE.equals(groupsEvaluationResult.getLeft())) {
if (!provisionIsRequestable) {
String message = "User does not have permissions to provision this component.";

if (groupsEvaluationResult != null && groupsEvaluationResult.getRight() != null) {
message = groupsEvaluationResult.getRight();
}

throw new UserNotAllowedException(message);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public AwxResponse triggerProvisionAction(ProvisionAction provisionAction) {
var provisionActionWrapper = new ProvisionActionWrapper(provisionAction);
var resolvedActionWrapper = resolveCatalogItemIdentifier(provisionActionWrapper);
var catalogItem = fetchCatalogItem(resolvedActionWrapper);
provisionerActionsApiValidator.validateUserHasPermissionsToProvision(catalogItem);
provisionerActionsApiValidator.validateReceivesOnlyVisibleParameters(resolvedActionWrapper.toProvisionAction(), catalogItem);

var systemParametersActionWrapper = addSystemParametersToAction(resolvedActionWrapper);
Expand Down

This file was deleted.

This file was deleted.

14 changes: 0 additions & 14 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,6 @@ management:
exposure:
include: health

catalog:
user-action:
groups-restriction:
prefix:
- BI-AS-ATLASSIAN
suffix:
- MANAGER
- TEAM

catalog-collection:
id: ${CATALOG_COLLECTION_ID}
user-actions:
id: ${USER_ACTIONS_ID}

component-provisioner:
azure:
token:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.opendevstack.component_provisioner.server.controllers.validators;

import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -12,18 +11,16 @@
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserAction;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.CatalogItemUserActionParameter;
import org.opendevstack.component_provisioner.client.component_catalog.v1.model.ProjectComponentInfo;
import org.opendevstack.component_provisioner.config.ApplicationPropertiesConfiguration;
import org.opendevstack.component_provisioner.server.services.AuthenticationProvider;
import org.opendevstack.component_provisioner.server.controllers.exceptions.InvalidRestEntityException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.ProjectComponentAlreadyProvisionedException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.UserNotAllowedException;
import org.opendevstack.component_provisioner.server.controllers.model.ActionType;
import org.opendevstack.component_provisioner.server.model.ProvisionAction;
import org.opendevstack.component_provisioner.server.model.ProvisionActionMother;
import org.opendevstack.component_provisioner.server.model.ProvisionActionParameter;
import org.opendevstack.component_provisioner.server.model.ProvisionActionParameterMother;
import org.opendevstack.component_provisioner.server.services.ComponentCatalogService;
import org.opendevstack.component_provisioner.server.services.ProjectsInfoService;
import org.opendevstack.component_provisioner.server.services.restrictions.evaluators.GroupsRestrictionsEvaluator;

import java.util.ArrayList;
import java.util.Collections;
Expand All @@ -44,15 +41,6 @@ class ProvisionerActionsApiValidatorTest {
@Mock
private AuthenticationProvider authenticationProvider;

@Mock
private GroupsRestrictionsEvaluator groupsRestrictionsEvaluator;

@Mock
private ProjectsInfoService projectsInfoService;

@Mock
private ApplicationPropertiesConfiguration.CatalogItemUserActionGroupsRestrictionProps catalogItemUserActionGroupsRestrictionProps;

@Mock
private MandatoryFieldsValidator mandatoryFieldsValidator;

Expand Down Expand Up @@ -100,78 +88,34 @@ void givenAlreadyProvisionedComponent_whenValidating_thenThrowsProjectComponentA
}

@Test
void givenUserWithoutPermissions_whenValidating_thenThrowsUserNotAllowedException() {
void givenProvisionActionNotRequestable_whenValidatingUserPermission_thenThrowsUserNotAllowedException() {
// given
var projectKey = "pkey";
var componentId = "cid";
var accessToken = "accessToken";

var action = ProvisionActionMother.of(List.of(
ProvisionActionParameterMother.of("project_key", projectKey),
ProvisionActionParameterMother.of("component_id", componentId),
ProvisionActionParameterMother.of("catalog_item_id", "111"),
ProvisionActionParameterMother.of("access_token", accessToken),
ProvisionActionParameterMother.of("workflow", "123")
));

when(authenticationProvider.getAccessToken()).thenReturn(accessToken);

// Component catalog empty -> no conflict
when(componentCatalogService.getProjectComponents(any(), any()))
.thenReturn(List.of());

// User groups
when(projectsInfoService.getProjectGroups(accessToken))
.thenReturn(List.of("group1"));

// Configure restriction prefix/suffix
when(catalogItemUserActionGroupsRestrictionProps.getPrefix()).thenReturn(List.of("prefix-"));
when(catalogItemUserActionGroupsRestrictionProps.getSuffix()).thenReturn(List.of("-suffix"));

// Simulate evaluator result -> forbidden
when(groupsRestrictionsEvaluator.evaluate(any(), any()))
.thenReturn(Pair.of(false, "User is not allowed"));
var provisionAction = CatalogItemUserAction.builder()
.id(ActionType.PROVISION.getValue())
.requestable(false)
.build();
var catalogItem = CatalogItem.builder()
.userActions(List.of(provisionAction))
.build();

// when / then
assertThatThrownBy(() -> provisionerActionsApiValidator.validate(action))
assertThatThrownBy(() -> provisionerActionsApiValidator.validateUserHasPermissionsToProvision(catalogItem))
.isInstanceOf(UserNotAllowedException.class);
}

@Test
void givenUserWithPermissions_whenValidating_thenDoesNotThrow() {
void givenProvisionActionRequestable_whenValidatingUserPermission_thenDoesNotThrow() {
// given
var projectKey = "pkey";
var componentId = "cid";
var accessToken = "accessToken";

var action = ProvisionActionMother.of(List.of(
ProvisionActionParameterMother.of("project_key", projectKey),
ProvisionActionParameterMother.of("component_id", componentId),
ProvisionActionParameterMother.of("catalog_item_id", "111"),
ProvisionActionParameterMother.of("access_token", accessToken),
ProvisionActionParameterMother.of("workflow", "123")
));

when(authenticationProvider.getAccessToken()).thenReturn(accessToken);

// Component does NOT exist
when(componentCatalogService.getProjectComponents(any(), any()))
.thenReturn(List.of());

// User groups
when(projectsInfoService.getProjectGroups(accessToken))
.thenReturn(List.of("allowed-group"));

// Configure restriction prefix/suffix
when(catalogItemUserActionGroupsRestrictionProps.getPrefix()).thenReturn(List.of("prefix-"));
when(catalogItemUserActionGroupsRestrictionProps.getSuffix()).thenReturn(List.of("-suffix"));

// Simulate evaluator result -> allowed
when(groupsRestrictionsEvaluator.evaluate(any(), any()))
.thenReturn(Pair.of(true, ""));
var provisionAction = CatalogItemUserAction.builder()
.id(ActionType.PROVISION.getValue())
.requestable(true)
.build();
var catalogItem = CatalogItem.builder()
.userActions(List.of(provisionAction))
.build();

// when / then
provisionerActionsApiValidator.validate(action);
assertThatNoException().isThrownBy(() -> provisionerActionsApiValidator.validateUserHasPermissionsToProvision(catalogItem));
}

@Test
Expand Down Expand Up @@ -256,37 +200,6 @@ void givenComponentCatalogServiceThrows_whenValidating_thenThrowsRuntimeExceptio
.isInstanceOf(RuntimeException.class);
}

@Test
void givenProjectsInfoServiceThrows_whenValidating_thenThrowsRuntimeException() {
// given
var action = ProvisionActionMother.of(List.of(
ProvisionActionParameterMother.of("project_key", "pkey"),
ProvisionActionParameterMother.of("component_id", "cid"),
ProvisionActionParameterMother.of("catalog_item_id", "catid"),
ProvisionActionParameterMother.of("access_token", "accessToken")
));

// when / then
assertThatThrownBy(() -> provisionerActionsApiValidator.validate(action))
.isInstanceOf(RuntimeException.class);
}

@Test
void givenGroupsRestrictionsEvaluatorThrows_whenValidating_thenThrowsRuntimeException() {
// given
var action = ProvisionActionMother.of(List.of(
ProvisionActionParameterMother.of("project_key", "pkey"),
ProvisionActionParameterMother.of("component_id", "cid"),
ProvisionActionParameterMother.of("catalog_item_id", "catid"),
ProvisionActionParameterMother.of("access_token", "accessToken")
));

when(authenticationProvider.getAccessToken()).thenReturn("bearerToken");

// when / then
assertThatThrownBy(() -> provisionerActionsApiValidator.validate(action))
.isInstanceOf(RuntimeException.class);
}

private ProvisionAction givenMissingParameterName_whenBuildingAction_thenReturnsActionWithoutMissingParameter(String missingParamName) {
// given
Expand Down
Loading
Loading