diff --git a/build.gradle b/build.gradle index 72fb1876f6..14fefd5522 100644 --- a/build.gradle +++ b/build.gradle @@ -138,7 +138,7 @@ dependencies { compile "io.dropwizard.metrics:metrics-servlets:$dropwizardVersion" compile "io.dropwizard.metrics:metrics-jvm:$dropwizardVersion" compile 'org.apache.commons:commons-lang3:3.8.1' - compile 'org.zalando:nakadi-plugin-api:3.1.2' + compile 'org.zalando:nakadi-plugin-api:3.2.1' compile 'org.echocat.jomon:runtime:1.6.3' // kafka & zookeeper diff --git a/src/main/java/org/zalando/nakadi/controller/StoragesController.java b/src/main/java/org/zalando/nakadi/controller/StoragesController.java index d943e2fd4f..1c8f1a3b90 100644 --- a/src/main/java/org/zalando/nakadi/controller/StoragesController.java +++ b/src/main/java/org/zalando/nakadi/controller/StoragesController.java @@ -17,8 +17,8 @@ import org.zalando.nakadi.exceptions.runtime.NoSuchStorageException; import org.zalando.nakadi.exceptions.runtime.StorageIsUsedException; import org.zalando.nakadi.exceptions.runtime.UnknownStorageTypeException; -import org.zalando.nakadi.plugin.api.PluginException; import org.zalando.nakadi.plugin.api.authz.AuthorizationService; +import org.zalando.nakadi.plugin.api.exceptions.PluginException; import org.zalando.nakadi.service.AdminService; import org.zalando.nakadi.service.StorageService; diff --git a/src/main/java/org/zalando/nakadi/domain/EventType.java b/src/main/java/org/zalando/nakadi/domain/EventType.java index 6f2f18830d..9e71003b24 100644 --- a/src/main/java/org/zalando/nakadi/domain/EventType.java +++ b/src/main/java/org/zalando/nakadi/domain/EventType.java @@ -15,7 +15,6 @@ public EventType(final EventTypeBase eventType, final String version, final Date super(eventType); this.updatedAt = updatedAt; this.createdAt = createdAt; - this.setSchema(new EventTypeSchema(eventType.getSchema(), version, updatedAt)); } diff --git a/src/main/java/org/zalando/nakadi/domain/EventTypeBase.java b/src/main/java/org/zalando/nakadi/domain/EventTypeBase.java index e552ee548e..2d12ce6169 100644 --- a/src/main/java/org/zalando/nakadi/domain/EventTypeBase.java +++ b/src/main/java/org/zalando/nakadi/domain/EventTypeBase.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.google.common.collect.ImmutableList; import org.zalando.nakadi.partitioning.PartitionStrategy; +import org.zalando.nakadi.plugin.api.authz.EventTypeAuthz; +import org.zalando.nakadi.plugin.api.authz.Resource; import javax.annotation.Nullable; import javax.validation.Valid; @@ -15,7 +17,7 @@ import static java.util.Collections.unmodifiableList; -public class EventTypeBase { +public class EventTypeBase implements EventTypeAuthz { private static final List EMPTY_PARTITION_KEY_FIELDS = ImmutableList.of(); private static final List EMPTY_ORDERING_KEY_FIELDS = ImmutableList.of(); @@ -255,4 +257,21 @@ public void setAudience(@Nullable final Audience audience) { public void setAuthorization(final ResourceAuthorization authorization) { this.authorization = authorization; } + + @JsonIgnore + @Override + public String getAuthCompatibilityMode() { + return this.compatibilityMode.toString(); + } + + @JsonIgnore + @Override + public String getAuthCleanupPolicy() { + return this.cleanupPolicy.toString(); + } + + @JsonIgnore + public Resource asBaseResource() { + return new ResourceImpl<>(getName(), ResourceImpl.EVENT_TYPE_RESOURCE, getAuthorization(), this); + } } diff --git a/src/main/java/org/zalando/nakadi/domain/ResourceAuthorization.java b/src/main/java/org/zalando/nakadi/domain/ResourceAuthorization.java index 7e3c817391..5db528ff84 100644 --- a/src/main/java/org/zalando/nakadi/domain/ResourceAuthorization.java +++ b/src/main/java/org/zalando/nakadi/domain/ResourceAuthorization.java @@ -104,13 +104,12 @@ public Optional> getAttributesForOperation( } } - @Override public Map> asMapValue() { return ImmutableMap.of( - "admins", getAdmins(), - "readers", getReaders(), - "writers", getWriters()); + AuthorizationService.Operation.ADMIN.toString(), getAdmins(), + AuthorizationService.Operation.READ.toString(), getReaders(), + AuthorizationService.Operation.WRITE.toString(), getWriters()); } @Override diff --git a/src/main/java/org/zalando/nakadi/domain/ResourceImpl.java b/src/main/java/org/zalando/nakadi/domain/ResourceImpl.java index 36474fe9c6..03ba6b2ee7 100644 --- a/src/main/java/org/zalando/nakadi/domain/ResourceImpl.java +++ b/src/main/java/org/zalando/nakadi/domain/ResourceImpl.java @@ -5,6 +5,7 @@ import org.zalando.nakadi.plugin.api.authz.Resource; import java.util.List; +import java.util.Map; import java.util.Optional; public class ResourceImpl implements Resource { @@ -13,6 +14,7 @@ public class ResourceImpl implements Resource { public static final String ADMIN_RESOURCE = "nakadi"; public static final String EVENT_TYPE_RESOURCE = "event-type"; public static final String SUBSCRIPTION_RESOURCE = "subscription"; + public static final String PERMISSION_RESOURCE = "permission"; private final T resource; private final String name; @@ -40,9 +42,20 @@ public String getType() { @Override public Optional> getAttributesForOperation( final AuthorizationService.Operation operation) { + if (null == authorization) { + return Optional.empty(); + } return authorization.getAttributesForOperation(operation); } + @Override + public Map> getAuthorization() { + if (authorization != null) { + return authorization.asMapValue(); + } + return null; + } + @Override public T get() { return resource; diff --git a/src/main/java/org/zalando/nakadi/domain/SubscriptionAuthorization.java b/src/main/java/org/zalando/nakadi/domain/SubscriptionAuthorization.java index 4c345b879d..c8d1b7472c 100644 --- a/src/main/java/org/zalando/nakadi/domain/SubscriptionAuthorization.java +++ b/src/main/java/org/zalando/nakadi/domain/SubscriptionAuthorization.java @@ -64,8 +64,8 @@ public int hashCode() { @Override public Map> asMapValue() { return ImmutableMap.of( - "admins", getAdmins(), - "readers", getReaders() + AuthorizationService.Operation.ADMIN.toString(), getAdmins(), + AuthorizationService.Operation.READ.toString(), getReaders() ); } diff --git a/src/main/java/org/zalando/nakadi/domain/SubscriptionBase.java b/src/main/java/org/zalando/nakadi/domain/SubscriptionBase.java index 30498dd880..6794505e23 100644 --- a/src/main/java/org/zalando/nakadi/domain/SubscriptionBase.java +++ b/src/main/java/org/zalando/nakadi/domain/SubscriptionBase.java @@ -1,6 +1,7 @@ package org.zalando.nakadi.domain; import com.google.common.collect.ImmutableList; +import org.zalando.nakadi.plugin.api.authz.Resource; import org.zalando.nakadi.view.SubscriptionCursorWithoutToken; import javax.annotation.Nullable; @@ -126,4 +127,8 @@ public boolean equals(final Object o) { public int hashCode() { return Objects.hash(owningApplication, eventTypes, consumerGroup, readFrom, initialCursors); } + + public Resource asBaseResource(final String id) { + return new ResourceImpl<>(id, ResourceImpl.SUBSCRIPTION_RESOURCE, getAuthorization(), this); + } } diff --git a/src/main/java/org/zalando/nakadi/exceptions/runtime/AccessDeniedException.java b/src/main/java/org/zalando/nakadi/exceptions/runtime/AccessDeniedException.java index c494b381f0..5f1baf7869 100644 --- a/src/main/java/org/zalando/nakadi/exceptions/runtime/AccessDeniedException.java +++ b/src/main/java/org/zalando/nakadi/exceptions/runtime/AccessDeniedException.java @@ -12,6 +12,11 @@ public AccessDeniedException(final AuthorizationService.Operation operation, fin this.operation = operation; } + public AccessDeniedException(final Resource resource) { + this.resource = resource; + this.operation = null; + } + public Resource getResource() { return resource; } diff --git a/src/main/java/org/zalando/nakadi/plugin/auth/DefaultAuthorizationService.java b/src/main/java/org/zalando/nakadi/plugin/auth/DefaultAuthorizationService.java index c69d19ddc7..904e6d87b1 100644 --- a/src/main/java/org/zalando/nakadi/plugin/auth/DefaultAuthorizationService.java +++ b/src/main/java/org/zalando/nakadi/plugin/auth/DefaultAuthorizationService.java @@ -1,10 +1,12 @@ package org.zalando.nakadi.plugin.auth; -import org.zalando.nakadi.plugin.api.PluginException; -import org.zalando.nakadi.plugin.api.authz.AuthorizationAttribute; + import org.zalando.nakadi.plugin.api.authz.AuthorizationService; import org.zalando.nakadi.plugin.api.authz.Resource; import org.zalando.nakadi.plugin.api.authz.Subject; +import org.zalando.nakadi.plugin.api.exceptions.AuthorizationInvalidException; +import org.zalando.nakadi.plugin.api.exceptions.OperationOnResourceNotPermittedException; +import org.zalando.nakadi.plugin.api.exceptions.PluginException; import javax.annotation.Nullable; import java.util.List; @@ -13,13 +15,17 @@ public class DefaultAuthorizationService implements AuthorizationService { @Override - public boolean isAuthorized(final Operation operation, final Resource resource) { + public boolean isAuthorized(final Operation operation, final Resource resource) throws PluginException { return true; } @Override - public boolean isAuthorizationAttributeValid(final AuthorizationAttribute authorizationAttribute) { - return true; + public void isAuthorizationForResourceValid(final Resource resource) throws PluginException, + AuthorizationInvalidException, OperationOnResourceNotPermittedException { + } + + public DefaultAuthorizationService() { + super(); } @Override diff --git a/src/main/java/org/zalando/nakadi/service/AdminService.java b/src/main/java/org/zalando/nakadi/service/AdminService.java index 46c34d01be..40f24bcdf9 100644 --- a/src/main/java/org/zalando/nakadi/service/AdminService.java +++ b/src/main/java/org/zalando/nakadi/service/AdminService.java @@ -13,9 +13,11 @@ import org.zalando.nakadi.domain.ResourceImpl; import org.zalando.nakadi.exceptions.runtime.DbWriteOperationsBlockedException; import org.zalando.nakadi.exceptions.runtime.UnableProcessException; -import org.zalando.nakadi.plugin.api.PluginException; +import org.zalando.nakadi.exceptions.runtime.UnprocessableEntityException; import org.zalando.nakadi.plugin.api.authz.AuthorizationService; import org.zalando.nakadi.plugin.api.authz.Resource; +import org.zalando.nakadi.plugin.api.exceptions.AuthorizationInvalidException; +import org.zalando.nakadi.plugin.api.exceptions.PluginException; import org.zalando.nakadi.repository.db.AuthorizationDbRepository; import java.util.List; @@ -27,6 +29,7 @@ import static org.zalando.nakadi.domain.ResourceImpl.ADMIN_RESOURCE; import static org.zalando.nakadi.domain.ResourceImpl.ALL_DATA_ACCESS_RESOURCE; +import static org.zalando.nakadi.domain.ResourceImpl.PERMISSION_RESOURCE; @Service public class AdminService { @@ -115,16 +118,11 @@ private List removeDefaultAdmin(final List permissions) } private void validateAllAdmins(final List admins) throws UnableProcessException, PluginException { - final List invalid = admins.stream().filter(permission -> - !authorizationService.isAuthorizationAttributeValid(permission.getAuthorizationAttribute())) - .collect(Collectors.toList()); - if (!invalid.isEmpty()) { - final String message = invalid.stream() - .map(permission -> String.format("authorization attribute %s:%s is invalid", - permission.getAuthorizationAttribute().getDataType(), - permission.getAuthorizationAttribute().getValue())) - .collect(Collectors.joining(", ")); - throw new UnableProcessException(message); + try { + authorizationService.isAuthorizationForResourceValid(new ResourceImpl<>(PERMISSION_RESOURCE, + PERMISSION_RESOURCE, ResourceAuthorization.fromPermissionsList(admins), null)); + } catch (AuthorizationInvalidException e) { + throw new UnprocessableEntityException(e.getMessage()); } } } diff --git a/src/main/java/org/zalando/nakadi/service/AuthorizationValidator.java b/src/main/java/org/zalando/nakadi/service/AuthorizationValidator.java index 87fd9d7a94..3f41d95a75 100644 --- a/src/main/java/org/zalando/nakadi/service/AuthorizationValidator.java +++ b/src/main/java/org/zalando/nakadi/service/AuthorizationValidator.java @@ -5,19 +5,20 @@ import org.springframework.stereotype.Service; import org.zalando.nakadi.domain.EventType; import org.zalando.nakadi.domain.Subscription; -import org.zalando.nakadi.domain.ValidatableAuthorization; import org.zalando.nakadi.exceptions.runtime.AccessDeniedException; +import org.zalando.nakadi.exceptions.runtime.ForbiddenOperationException; import org.zalando.nakadi.exceptions.runtime.InternalNakadiException; import org.zalando.nakadi.exceptions.runtime.ServiceTemporarilyUnavailableException; import org.zalando.nakadi.exceptions.runtime.UnableProcessException; -import org.zalando.nakadi.plugin.api.PluginException; +import org.zalando.nakadi.exceptions.runtime.UnprocessableEntityException; import org.zalando.nakadi.plugin.api.authz.AuthorizationAttribute; import org.zalando.nakadi.plugin.api.authz.AuthorizationService; import org.zalando.nakadi.plugin.api.authz.Resource; +import org.zalando.nakadi.plugin.api.exceptions.AuthorizationInvalidException; +import org.zalando.nakadi.plugin.api.exceptions.OperationOnResourceNotPermittedException; +import org.zalando.nakadi.plugin.api.exceptions.PluginException; import org.zalando.nakadi.repository.EventTypeRepository; -import javax.annotation.Nullable; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; @@ -44,12 +45,11 @@ public AuthorizationValidator( this.adminService = adminService; } - public void validateAuthorization(@Nullable final ValidatableAuthorization auth) throws UnableProcessException, + public void validateAuthorization(final Resource resource) throws UnableProcessException, ServiceTemporarilyUnavailableException { - if (auth != null) { - final Map> authorization = auth.asMapValue(); - checkAuthAttributesAreValid(authorization); - checkAuthAttributesNoDuplicates(authorization); + checkAuthorisationForResourceAreValid(resource); + if (resource.getAuthorization() != null) { + checkAuthAttributesNoDuplicates(resource.getAuthorization()); } } @@ -86,24 +86,21 @@ private void checkAuthAttributesNoDuplicates(final Map> allAttributes) - throws UnableProcessException, ServiceTemporarilyUnavailableException { + private void checkAuthorisationForResourceAreValid(final Resource resource) + throws UnableProcessException, ServiceTemporarilyUnavailableException, ForbiddenOperationException { + try { - final String errorMessage = allAttributes.values().stream() - .flatMap(Collection::stream) - .filter(attr -> !authorizationService.isAuthorizationAttributeValid(attr)) - .map(attr -> String.format("authorization attribute %s:%s is invalid", - attr.getDataType(), attr.getValue())) - .collect(Collectors.joining(", ")); - - if (!Strings.isNullOrEmpty(errorMessage)) { - throw new UnableProcessException(errorMessage); - } - } catch (final PluginException e) { + authorizationService.isAuthorizationForResourceValid(resource); + } catch (OperationOnResourceNotPermittedException e) { + throw new ForbiddenOperationException(e.getMessage()); + } catch (AuthorizationInvalidException e) { + throw new UnprocessableEntityException(e.getMessage()); + } catch (PluginException e) { throw new ServiceTemporarilyUnavailableException("Error calling authorization plugin", e); } } + public void authorizeEventTypeWrite(final EventType eventType) throws AccessDeniedException, ServiceTemporarilyUnavailableException { if (eventType.getAuthorization() == null) { @@ -148,28 +145,13 @@ public void authorizeStreamRead(final EventType eventType) throws AccessDeniedEx } final Resource resource = eventType.asResource(); - try { - if (!authorizationService.isAuthorized(AuthorizationService.Operation.READ, resource) - && !adminService.hasAllDataAccess(AuthorizationService.Operation.READ)) { - throw new AccessDeniedException(AuthorizationService.Operation.READ, resource); - } - } catch (final PluginException e) { - throw new ServiceTemporarilyUnavailableException("Error calling authorization plugin", e); - } + checkResourceAuthorization(resource); } public void authorizeSubscriptionRead(final Subscription subscription) throws AccessDeniedException { if (null != subscription.getAuthorization()) { final Resource resource = subscription.asResource(); - try { - // In this case operation for read will invoke - if (!authorizationService.isAuthorized(AuthorizationService.Operation.READ, resource) - && !adminService.hasAllDataAccess(AuthorizationService.Operation.READ)) { - throw new AccessDeniedException(AuthorizationService.Operation.READ, resource); - } - } catch (final PluginException e) { - throw new ServiceTemporarilyUnavailableException("Error calling authorization plugin", e); - } + checkResourceAuthorization(resource); } subscription.getEventTypes().forEach( (eventTypeName) -> { @@ -187,6 +169,12 @@ public void authorizeSubscriptionCommit(final Subscription subscription) throws return; } final Resource resource = subscription.asResource(); + checkResourceAuthorization(resource); + + } + + private void checkResourceAuthorization(final Resource resource) + throws ServiceTemporarilyUnavailableException, AccessDeniedException { try { if (!authorizationService.isAuthorized(AuthorizationService.Operation.READ, resource) && !adminService.hasAllDataAccess(AuthorizationService.Operation.READ)) { @@ -204,14 +192,16 @@ public void authorizeSubscriptionAdmin(final Subscription subscription) throws A authorizeResourceAdmin(subscription.asResource()); } - public void validateAuthorization(final ValidatableAuthorization oldValue, final ValidatableAuthorization newValue) + public void validateAuthorization(final Resource oldValue, final Resource newValue) throws UnableProcessException, ServiceTemporarilyUnavailableException { - if (oldValue != null && newValue == null) { + final Map> oldAuth = oldValue.getAuthorization(); + final Map> newAuth = newValue.getAuthorization(); + if (oldAuth != null && newAuth == null) { throw new UnableProcessException( "Changing authorization object to `null` is not possible due to existing one"); } - if (oldValue != null && oldValue.equals(newValue)) { + if (oldAuth != null && oldAuth.equals(newAuth)) { return; } diff --git a/src/main/java/org/zalando/nakadi/service/EventTypeService.java b/src/main/java/org/zalando/nakadi/service/EventTypeService.java index d3d0ac4e92..78aad61044 100644 --- a/src/main/java/org/zalando/nakadi/service/EventTypeService.java +++ b/src/main/java/org/zalando/nakadi/service/EventTypeService.java @@ -158,7 +158,7 @@ public void create(final EventTypeBase eventType) validateCompaction(eventType); enrichment.validate(eventType); partitionResolver.validate(eventType); - authorizationValidator.validateAuthorization(eventType.getAuthorization()); + authorizationValidator.validateAuthorization(eventType.asBaseResource()); eventTypeRepository.saveEventType(eventType); @@ -348,7 +348,7 @@ public void update(final String eventTypeName, eventTypeOptionsValidator.checkRetentionTime(eventTypeBase.getOptions()); authorizationValidator.authorizeEventTypeAdmin(original); } - authorizationValidator.validateAuthorization(original.getAuthorization(), eventTypeBase.getAuthorization()); + authorizationValidator.validateAuthorization(original.asResource(), eventTypeBase.asBaseResource()); validateName(eventTypeName, eventTypeBase); validateCompactionUpdate(original, eventTypeBase); validateSchema(eventTypeBase); diff --git a/src/main/java/org/zalando/nakadi/service/subscription/SubscriptionValidationService.java b/src/main/java/org/zalando/nakadi/service/subscription/SubscriptionValidationService.java index 3d20091df8..f73a69e8ed 100644 --- a/src/main/java/org/zalando/nakadi/service/subscription/SubscriptionValidationService.java +++ b/src/main/java/org/zalando/nakadi/service/subscription/SubscriptionValidationService.java @@ -82,7 +82,7 @@ public void validateSubscription(final SubscriptionBase subscription) validateInitialCursors(subscription, allPartitions); } // Verify that subscription authorization object is valid - authorizationValidator.validateAuthorization(subscription.getAuthorization()); + authorizationValidator.validateAuthorization(subscription.asBaseResource("new-subscription")); } public void validateSubscriptionChange(final Subscription old, final SubscriptionBase newValue) @@ -102,7 +102,7 @@ public void validateSubscriptionChange(final Subscription old, final Subscriptio if (!Objects.equals(newValue.getInitialCursors(), old.getInitialCursors())) { throw new SubscriptionUpdateConflictException("Not allowed to change initial cursors"); } - authorizationValidator.validateAuthorization(old.getAuthorization(), newValue.getAuthorization()); + authorizationValidator.validateAuthorization(old.asResource(), newValue.asBaseResource(old.getId())); } public void validatePartitionsToStream(final Subscription subscription, final List partitions) { @@ -195,7 +195,7 @@ private void checkEventTypesExist(final Map> eventTy .collect(Collectors.toList()); if (!missingEventTypes.isEmpty()) { throw new NoSuchEventTypeException(String.format("Failed to create subscription, event type(s) not " + - "found: '%s'", StringUtils.join(missingEventTypes, "', '"))); + "found: '%s'", StringUtils.join(missingEventTypes, "', '"))); } } } diff --git a/src/test/java/org/zalando/nakadi/service/AdminServiceTest.java b/src/test/java/org/zalando/nakadi/service/AdminServiceTest.java index 4206e67315..cc49e48ec3 100644 --- a/src/test/java/org/zalando/nakadi/service/AdminServiceTest.java +++ b/src/test/java/org/zalando/nakadi/service/AdminServiceTest.java @@ -72,7 +72,7 @@ public AdminServiceTest() { for (final AuthorizationService.Operation operation : AuthorizationService.Operation.values()) { defaultAdminPermissions.add(new Permission("nakadi", operation, defaultAdmin)); } - when(authorizationService.isAuthorizationAttributeValid(any())).thenReturn(true); + doNothing().when(authorizationService).isAuthorizationForResourceValid(any()); when(featureToggleService.isFeatureEnabled(FeatureToggleService.Feature.DISABLE_DB_WRITE_OPERATIONS)) .thenReturn(false); } diff --git a/src/test/java/org/zalando/nakadi/service/AuthorizationValidatorTest.java b/src/test/java/org/zalando/nakadi/service/AuthorizationValidatorTest.java index c2f0d5f077..6bddc43d30 100644 --- a/src/test/java/org/zalando/nakadi/service/AuthorizationValidatorTest.java +++ b/src/test/java/org/zalando/nakadi/service/AuthorizationValidatorTest.java @@ -4,12 +4,18 @@ import org.junit.Test; import org.zalando.nakadi.domain.ResourceAuthorization; import org.zalando.nakadi.domain.ResourceAuthorizationAttribute; +import org.zalando.nakadi.domain.ResourceImpl; import org.zalando.nakadi.exceptions.runtime.AccessDeniedException; +import org.zalando.nakadi.exceptions.runtime.ForbiddenOperationException; import org.zalando.nakadi.exceptions.runtime.ServiceTemporarilyUnavailableException; import org.zalando.nakadi.exceptions.runtime.UnableProcessException; -import org.zalando.nakadi.plugin.api.PluginException; +import org.zalando.nakadi.exceptions.runtime.UnprocessableEntityException; import org.zalando.nakadi.plugin.api.authz.AuthorizationAttribute; import org.zalando.nakadi.plugin.api.authz.AuthorizationService; +import org.zalando.nakadi.plugin.api.authz.Resource; +import org.zalando.nakadi.plugin.api.exceptions.AuthorizationInvalidException; +import org.zalando.nakadi.plugin.api.exceptions.OperationOnResourceNotPermittedException; +import org.zalando.nakadi.plugin.api.exceptions.PluginException; import org.zalando.nakadi.repository.EventTypeRepository; import org.zalando.nakadi.utils.EventTypeTestBuilder; @@ -17,6 +23,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -45,17 +52,14 @@ public void whenInvalidAuthAttributesThenInvalidEventTypeException() { final ResourceAuthorization auth = new ResourceAuthorization( ImmutableList.of(attr1), ImmutableList.of(attr2), ImmutableList.of(attr3, attr4)); - when(authorizationService.isAuthorizationAttributeValid(attr1)).thenReturn(false); - when(authorizationService.isAuthorizationAttributeValid(attr2)).thenReturn(true); - when(authorizationService.isAuthorizationAttributeValid(attr3)).thenReturn(true); - when(authorizationService.isAuthorizationAttributeValid(attr4)).thenReturn(false); - + final Resource resource = new ResourceImpl("myResource1", "event-type", auth, null); + doThrow(new AuthorizationInvalidException("some attributes are not ok")) + .when(authorizationService).isAuthorizationForResourceValid(any()); try { - validator.validateAuthorization(auth); + validator.validateAuthorization(resource); fail("Exception expected to be thrown"); - } catch (final UnableProcessException e) { - assertThat(e.getMessage(), equalTo("authorization attribute type1:value1 is invalid, " + - "authorization attribute type4:value4 is invalid")); + } catch (final UnprocessableEntityException e) { + assertThat(e.getMessage(), equalTo("some attributes are not ok")); } } @@ -67,29 +71,55 @@ public void whenDuplicatesThenInvalidEventTypeException() { ImmutableList.of(attr3, attr2, attr2), ImmutableList.of(attr3, attr4)); - when(authorizationService.isAuthorizationAttributeValid(any())).thenReturn(true); + final Resource resource = new ResourceImpl("myResource1", "event-type", auth, null); try { - validator.validateAuthorization(auth); + validator.validateAuthorization(resource); fail("Exception expected to be thrown"); } catch (final UnableProcessException e) { assertThat(e.getMessage(), equalTo( - "authorization property 'admins' contains duplicated attribute(s): type1:value1, type3:value3; " + - "authorization property 'readers' contains duplicated attribute(s): type2:value2")); + "authorization property 'ADMIN' contains duplicated attribute(s): type1:value1, type3:value3; " + + "authorization property 'READ' contains duplicated attribute(s): type2:value2")); } } - @Test(expected = ServiceTemporarilyUnavailableException.class) - public void whenPluginExceptionInIsAuthorizationAttributeValidThenServiceUnavailableException() { + @Test(expected = ForbiddenOperationException.class) + public void whenOperationOnResourceNotPermittedExceptionThenForbiddenOperationException() { + + final ResourceAuthorization auth = new ResourceAuthorization( + ImmutableList.of(attr1), + ImmutableList.of(attr2), + ImmutableList.of(attr3)); + doThrow(new OperationOnResourceNotPermittedException("blah")) + .when(authorizationService).isAuthorizationForResourceValid(any()); + final Resource resource = new ResourceImpl("myResource1", "event-type", auth, null); + validator.validateAuthorization(resource); + } + + @Test(expected = UnprocessableEntityException.class) + public void whenAuthorizationInvalidExceptionThenUnableProcessException() { final ResourceAuthorization auth = new ResourceAuthorization( ImmutableList.of(attr1), ImmutableList.of(attr2), ImmutableList.of(attr3)); + doThrow(new AuthorizationInvalidException("blah")) + .when(authorizationService).isAuthorizationForResourceValid(any()); + final Resource resource = new ResourceImpl("myResource1", "event-type", auth, null); + validator.validateAuthorization(resource); + } - when(authorizationService.isAuthorizationAttributeValid(any())).thenThrow(new PluginException("blah")); + @Test(expected = ServiceTemporarilyUnavailableException.class) + public void whenPluginExceptionInIsAuthorizationAttributeValidThenServiceUnavailableException() { - validator.validateAuthorization(auth); + final ResourceAuthorization auth = new ResourceAuthorization( + ImmutableList.of(attr1), + ImmutableList.of(attr2), + ImmutableList.of(attr3)); + doThrow(new PluginException("blah")) + .when(authorizationService).isAuthorizationForResourceValid(any()); + final Resource resource = new ResourceImpl("myResource1", "event-type", auth, null); + validator.validateAuthorization(resource); } @Test