Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception mapping and frontend preventing access to unauthorized pages via URL #430

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
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 @@ -36,6 +36,7 @@

<source path="client"/>
<source path="api" />
<source path="exceptions"/>
<!-- https://github.com/resty-gwt/resty-gwt/issues/296 -->
<!-- in order to use auto-detection on strings you need to set in your XZY-gwt.xml -->
<set-property name="restygwt.autodetect.plainText" value="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.glassfish.jersey.servlet.ServletProperties;
import org.springframework.context.annotation.Configuration;

import com.databasepreservation.common.api.exceptions.RestExceptionMapper;
import com.databasepreservation.common.api.utils.CacheFilterFactory;
import com.databasepreservation.common.api.v1.ActivityLogResource;
import com.databasepreservation.common.api.v1.AuthenticationResource;
Expand Down Expand Up @@ -66,7 +65,6 @@ public RestApplicationNoSwagger() {
register(JacksonFeature.class);
register(MoxyXmlFeature.class);
register(MultiPartFeature.class);
register(RestExceptionMapper.class);
register(CacheFilterFactory.class);

register(ActivityLogResource.class);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/dbptk-ui
*/
package com.databasepreservation.common.api.exceptions;

import com.databasepreservation.common.exceptions.AuthorizationException;
import com.databasepreservation.common.exceptions.SavedSearchException;
import com.google.gwt.http.client.Response;
import org.roda.core.data.exceptions.*;

import java.io.Serial;

/**
* @author António Lindo <[email protected]>
*/

public class RESTException extends RuntimeException {
@Serial
private static final long serialVersionUID = 4667937307148805083L;

private Throwable cause;

public RESTException() {
}

public RESTException(Throwable cause) {
super();
this.cause = cause;
}

private static String getCauseMessage(Throwable e) {
StringBuilder message = new StringBuilder();
Throwable cause = e;

while (cause != null) {
message.append(" caused by ").append(cause.getClass().getSimpleName()).append(": ");
if (cause.getMessage() != null) {
message.append(cause.getMessage());
}
cause = cause.getCause();
}
return message.toString();
}

@Override
public synchronized Throwable getCause() {
return cause;
}

public int getStatus() {
if (cause instanceof AuthorizationDeniedException || cause instanceof AuthorizationException) {
return Response.SC_UNAUTHORIZED;
} else if (cause instanceof NotFoundException) {
return Response.SC_NOT_FOUND;
} else if (cause instanceof AlreadyExistsException) {
return Response.SC_CONFLICT;
} else if (cause instanceof SavedSearchException) {
return Response.SC_BAD_REQUEST;
} else if (cause instanceof GenericException) {
return Response.SC_BAD_REQUEST;
} else if (cause instanceof RequestNotValidException) {
return Response.SC_BAD_REQUEST;
}
return Response.SC_INTERNAL_SERVER_ERROR;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.databasepreservation.common.api.exceptions;

import java.io.IOException;
import java.util.UUID;

import com.databasepreservation.common.api.exceptions.model.ErrorResponseMessage;
import com.databasepreservation.common.exceptions.AuthorizationException;
import com.databasepreservation.common.exceptions.ViewerException;
import org.roda.core.data.exceptions.AlreadyExistsException;
import org.roda.core.data.exceptions.AuthenticationDeniedException;
import org.roda.core.data.exceptions.AuthorizationDeniedException;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.NotFoundException;
import org.roda.core.data.exceptions.RequestNotValidException;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(value = {RESTException.class})
protected ResponseEntity<Object> handleRestException(RuntimeException ex, WebRequest request) {
String message = "Internal server error";
String details = "";
Object objectDetails = null;
HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
UUID errorID = UUID.randomUUID();
if (ex.getCause() instanceof AuthorizationDeniedException || ex.getCause() instanceof AuthorizationException) {
message = "Forbidden";
details = ex.getCause().getMessage();
httpStatus = HttpStatus.FORBIDDEN;
} else if (ex.getCause() instanceof AuthenticationDeniedException) {
message = "Unauthorized access";
details = ex.getCause().getMessage();
httpStatus = HttpStatus.UNAUTHORIZED;
} else if (ex.getCause() instanceof NotFoundException) {
message = "Resource not found";
details = ex.getCause().getMessage();
httpStatus = HttpStatus.NOT_FOUND;
} else if (ex.getCause() instanceof AlreadyExistsException) {
message = "Resource already exists";
details = ex.getCause().getMessage();
httpStatus = HttpStatus.CONFLICT;
} else if (ex.getCause() instanceof GenericException || ex.getCause() instanceof RequestNotValidException
|| ex.getCause() instanceof IOException || ex.getCause() instanceof ViewerException) {
message = "Request was not valid";
details = ex.getCause().getMessage();
httpStatus = HttpStatus.BAD_REQUEST;
}

String warn = "ERROR_ID: " + errorID + " - " + ex.getClass().getSimpleName() + ": " + ex.getCause().getMessage();
LoggerFactory.getLogger(RestResponseEntityExceptionHandler.class).warn(warn);

ErrorResponseMessage body = new ErrorResponseMessage(httpStatus.value(), errorID.toString(), message, details,
((ServletWebRequest) request).getRequest().getRequestURI(), objectDetails);

HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);

return handleExceptionInternal(ex, body, responseHeaders, httpStatus, request);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.databasepreservation.common.api.exceptions.model;

import java.io.Serial;
import java.io.Serializable;
import java.time.Instant;
import java.time.temporal.ChronoUnit;

import com.fasterxml.jackson.annotation.JsonInclude;

public class ErrorResponseMessage implements Serializable {

@Serial
private static final long serialVersionUID = -2206131216992713872L;

private final int status;
private final String errorId;
private final String message;
private final String details;
private final Instant timestamp;
private final String instance;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object objectDetails;

public ErrorResponseMessage(int status, String errorId, String message, String details, String instance) {
this.status = status;
this.errorId = errorId;
this.message = message;
this.details = details;
this.timestamp = Instant.now().truncatedTo(ChronoUnit.MILLIS);
this.instance = instance;
}

public ErrorResponseMessage(int status, String errorId, String message, String details, String instance, Object objectDetails) {
this.status = status;
this.errorId = errorId;
this.message = message;
this.details = details;
this.timestamp = Instant.now().truncatedTo(ChronoUnit.MILLIS);
this.instance = instance;
this.objectDetails = objectDetails;
}

public int getStatus() {
return status;
}

public String getErrorId() {
return errorId;
}

public String getMessage() {
return message;
}

public String getDetails() {
return details;
}

public Instant getTimestamp() {
return timestamp;
}

public String getInstance() {
return instance;
}

public Object getObjectDetails() {
return objectDetails;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/
package com.databasepreservation.common.api.utils;

import com.databasepreservation.common.client.tools.ViewerCelllUtils;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
Expand All @@ -18,8 +17,9 @@
import com.databasepreservation.common.utils.FilenameUtils;
import org.apache.commons.lang3.StringUtils;

import com.databasepreservation.common.api.exceptions.RESTException;
import com.databasepreservation.common.client.tools.ViewerCelllUtils;
import com.databasepreservation.common.client.ViewerConstants;
import com.databasepreservation.common.client.exceptions.RESTException;
import com.databasepreservation.common.client.models.status.collection.ColumnStatus;
import com.databasepreservation.common.client.models.status.collection.NestedColumnStatus;
import com.databasepreservation.common.client.models.status.collection.TableStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.databasepreservation.common.api.exceptions.RESTException;
import com.databasepreservation.common.exceptions.AuthorizationException;
import com.databasepreservation.common.client.ViewerConstants;
import com.databasepreservation.common.client.exceptions.RESTException;
import com.databasepreservation.common.client.index.FindRequest;
import com.databasepreservation.common.client.index.IndexResult;
import com.databasepreservation.common.client.models.activity.logs.ActivityLogEntry;
Expand Down Expand Up @@ -47,18 +48,17 @@ public class ActivityLogResource implements ActivityLogService {
@Override
public IndexResult<ActivityLogEntry> find(FindRequest findRequest, String locale) {
ControllerAssistant controllerAssistant = new ControllerAssistant() {};

LogEntryState state = LogEntryState.SUCCESS;
User user = controllerAssistant.checkRoles(request);

User user = new User();
long count = 0;

LogEntryState state = LogEntryState.SUCCESS;
try {
user = controllerAssistant.checkRoles(request);

final IndexResult<ActivityLogEntry> result = ViewerFactory.getSolrManager().find(ActivityLogEntry.class,
findRequest.filter, findRequest.sorter, findRequest.sublist, findRequest.facets);
count = result.getTotalCount();
return I18nUtility.translate(result, ActivityLogEntry.class, locale);
} catch (GenericException | RequestNotValidException e) {
} catch (GenericException | RequestNotValidException | AuthorizationException e) {
state = LogEntryState.FAILURE;
throw new RESTException(e);
} finally {
Expand All @@ -73,16 +73,16 @@ public IndexResult<ActivityLogEntry> find(FindRequest findRequest, String locale
@Override
public ActivityLogWrapper retrieve(String logUUID) {
ControllerAssistant controllerAssistant = new ControllerAssistant() {};

User user = new User();
LogEntryState state = LogEntryState.SUCCESS;
User user = controllerAssistant.checkRoles(request);

try {
user = controllerAssistant.checkRoles(request);
final ActivityLogEntry retrieve = ViewerFactory.getSolrManager().retrieve(ActivityLogEntry.class, logUUID);
final ActivityLogStrategy strategy = ViewerFactory.getActivityLogStrategyFactory()
.getStrategy(retrieve.getActionComponent(), retrieve.getActionMethod());
return strategy.apply(new ActivityLogWrapper(retrieve));
} catch (GenericException | NotFoundException e) {
} catch (GenericException | NotFoundException | AuthorizationException e) {
state = LogEntryState.FAILURE;
throw new RESTException(e);
} finally {
Expand Down
Loading
Loading