Skip to content

Commit

Permalink
feat(engine) populate AuthorizationException consistently
Browse files Browse the repository at this point in the history
- adds a list of MissingAuthorization objects to an AuthorizationException
- a user has to possess any of the authorizations in that list to proceed
- makes exception properties consistent for cases in which 1 and in which
  n permissions are checked

related to CAM-4261
  • Loading branch information
filiphr authored and ThorbenLindhauer committed Jul 27, 2015
1 parent cd63065 commit 08d7c73
Show file tree
Hide file tree
Showing 13 changed files with 534 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@
*/
package org.camunda.bpm.engine.rest.dto;

import java.util.List;

import org.camunda.bpm.engine.AuthorizationException;

/**
* <p>Dto for {@link AuthorizationException}</p>
*
*
* <p>The exception contains a list of Missing authorizations. The List is a
* disjunction i.e. a user should have any of the authorization for the engine
* to continue the execution beyond the point where it failed.</p>
*
* @author Daniel Meyer
*
*/
Expand All @@ -26,6 +32,7 @@ public class AuthorizationExceptionDto extends ExceptionDto {
protected String resourceName;
protected String resourceId;
protected String permissionName;
protected List<MissingAuthorizationDto> missingAuthorizations;

// transformer /////////////////////////////

Expand All @@ -36,6 +43,7 @@ public static AuthorizationExceptionDto fromException(AuthorizationException e)
dto.setType(AuthorizationException.class.getSimpleName());

dto.setUserId(e.getUserId());
dto.setMissingAuthorizations(MissingAuthorizationDto.fromInfo(e.getMissingAuthorizations()));
dto.setPermissionName(e.getViolatedPermissionName());
dto.setResourceId(e.getResourceId());
dto.setResourceName(e.getResourceType());
Expand All @@ -44,22 +52,65 @@ public static AuthorizationExceptionDto fromException(AuthorizationException e)
}

// getter / setters ////////////////////////

/**
* @return the name of the resource if there
* is only one {@link MissingAuthorizationDto}, {@code null} otherwise
*
* @deprecated Use {@link #getMissingAuthorizations()} to get the name of the resource
* of the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public String getResourceName() {
return resourceName;
}

/**
* @deprecated Use {@link #setMissingAuthorizations(List)}} to set the
* the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}

/**
* @return the id of the resource if there
* is only one {@link MissingAuthorizationDto}, {@code null} otherwise
*
* @deprecated Use {@link #getMissingAuthorizations()} to get the id of the resource
* of the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public String getResourceId() {
return resourceId;
}

/**
* @deprecated Use {@link #setMissingAuthorizations(List)}} to set the
* the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}

/**
* @return the name of the violated permission if there
* is only one {@link MissingAuthorizationDto}, {@code null} otherwise
*
* @deprecated Use {@link #getMissingAuthorizations()} to get the name of the violated permission
* of the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public String getPermissionName() {
return permissionName;
}

/**
* @deprecated Use {@link #setMissingAuthorizations(List)}} to set the
* the {@link MissingAuthorizationDto}(s). This method will be removed in future version.
*/
@Deprecated
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
Expand All @@ -68,6 +119,15 @@ public String getUserId() {
}
public void setUserId(String userId) {
this.userId = userId;
}
/**
* @return Disjunctive list of {@link MissingAuthorizationDto} from
* which a user needs to have at least one for the authorization to pass
*/
public List<MissingAuthorizationDto> getMissingAuthorizations() {
return missingAuthorizations;
}
public void setMissingAuthorizations(List<MissingAuthorizationDto> info) {
this.missingAuthorizations = info;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.camunda.bpm.engine.rest.dto;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.camunda.bpm.engine.authorization.MissingAuthorization;

/**
* * <p>Dto for {@link MissingAuthorization}</p>
* @author Filip Hrisafov
*
*/
public class MissingAuthorizationDto {

private String permissionName;
private String resourceName;
protected String resourceId;

// transformer /////////////////////////////

public static MissingAuthorizationDto fromInfo(MissingAuthorization info) {
MissingAuthorizationDto dto = new MissingAuthorizationDto();

dto.setPermissionName(info.getViolatedPermissionName());
dto.setResourceId(info.getResourceId());
dto.setResourceName(info.getResourceType());

return dto;
}

public static List<MissingAuthorizationDto> fromInfo(Collection<MissingAuthorization> infos) {
List<MissingAuthorizationDto> dtos = new ArrayList<MissingAuthorizationDto>();
for (MissingAuthorization info : infos) {
dtos.add(fromInfo(info));
}
return dtos;
}

// getter / setters ////////////////////////
public String getPermissionName() {
return permissionName;
}

public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}

public String getResourceName() {
return resourceName;
}

public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}

public String getResourceId() {
return resourceId;
}

public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;

import javax.ws.rs.core.Response.Status;

Expand All @@ -20,6 +21,7 @@ public abstract class AbstractExceptionHandlerTest extends AbstractRestServiceTe
private static final String PROCESS_ENGINE_EXCEPTION_URL = EXCEPTION_RESOURCE_URL + "/processEngineException";
private static final String REST_EXCEPTION_URL = EXCEPTION_RESOURCE_URL + "/restException";
private static final String AUTH_EXCEPTION_URL = EXCEPTION_RESOURCE_URL + "/authorizationException";
private static final String AUTH_EXCEPTION_MULTIPLE_URL = EXCEPTION_RESOURCE_URL + "/authorizationExceptionMultiple";


@Test
Expand Down Expand Up @@ -54,6 +56,7 @@ public void testProcessEngineExceptionHandler() {

@Test
public void testAuthorizationExceptionHandler() {
// TODO remove "resourceName", "resourceId", "permissionName" once the deprecated methods from AuthorizationException are removed
given().header(ACCEPT_WILDCARD_HEADER)
.expect().contentType(ContentType.JSON)
.statusCode(Status.FORBIDDEN.getStatusCode())
Expand All @@ -63,6 +66,29 @@ public void testAuthorizationExceptionHandler() {
.body("resourceName", equalTo("someResourceName"))
.body("resourceId", equalTo("someResourceId"))
.body("permissionName", equalTo("somePermission"))
.body("missingAuthorizations.resourceName", hasItems("someResourceName"))
.body("missingAuthorizations.resourceId", hasItems("someResourceId"))
.body("missingAuthorizations.permissionName", hasItems("somePermission"))
.when().get(AUTH_EXCEPTION_URL);
}

@Test
public void testAuthorizationExceptionWithMultipleMissingAuthorizationsHandler() {
// TODO remove "resourceName", "resourceId", "permissionName" once the deprecated methods from AuthorizationException are removed
given().header(ACCEPT_WILDCARD_HEADER)
.expect().contentType(ContentType.JSON)
.statusCode(Status.FORBIDDEN.getStatusCode())
.body("type", equalTo(AuthorizationException.class.getSimpleName()))
.body("message", equalTo("The user with id 'someUser' does not have one of the following permissions: 'somePermission1' permission on resource "
+ "'someResourceId1' of type 'someResourceName1' or 'somePermission2' permission on resource "
+ "'someResourceId2' of type 'someResourceName2'"))
.body("userId", equalTo("someUser"))
.body("resourceName", equalTo(null))
.body("resourceId", equalTo(null))
.body("permissionName", equalTo(null))
.body("missingAuthorizations.resourceName", hasItems("someResourceName1", "someResourceName2"))
.body("missingAuthorizations.resourceId", hasItems("someResourceId1", "someResourceId2"))
.body("missingAuthorizations.permissionName", hasItems("somePermission1", "somePermission2"))
.when().get(AUTH_EXCEPTION_MULTIPLE_URL);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@

import org.camunda.bpm.engine.AuthorizationException;
import org.camunda.bpm.engine.ProcessEngineException;
import org.camunda.bpm.engine.authorization.MissingAuthorization;
import org.camunda.bpm.engine.rest.exception.RestException;

import java.util.ArrayList;
import java.util.List;

/**
* Does not declare produced media types.
* @author Thorben Lindhauer
Expand All @@ -21,22 +25,34 @@ public class UnannotatedResource {
public String throwAnException() throws Exception {
throw new Exception("expected exception");
}

@GET
@Path("/processEngineException")
public String throwProcessEngineException() throws Exception {
throw new ProcessEngineException("expected exception");
}

@GET
@Path("/restException")
public String throwRestException() throws Exception {
throw new RestException(Status.BAD_REQUEST, "expected exception");
}

@GET
@Path("/authorizationException")
public String throwAuthorizationException() throws Exception {
throw new AuthorizationException("someUser", "somePermission", "someResourceName", "someResourceId");
}

@GET
@Path("/authorizationExceptionMultiple")
public String throwAuthorizationExceptionMultiple() throws Exception {
List<MissingAuthorization> missingAuthorizations = new ArrayList<MissingAuthorization>();

missingAuthorizations.add(
new MissingAuthorization("somePermission1", "someResourceName1", "someResourceId1"));
missingAuthorizations.add(
new MissingAuthorization("somePermission2", "someResourceName2", "someResourceId2"));
throw new AuthorizationException("someUser", missingAuthorizations);
}
}

0 comments on commit 08d7c73

Please sign in to comment.