Skip to content

Commit

Permalink
Merge pull request #430 from keeps/alindo-dev-session-expired
Browse files Browse the repository at this point in the history
Exception mapping and frontend preventing access to unauthorized pages via URL
  • Loading branch information
hmiguim authored Nov 25, 2024
2 parents 48f0678 + ccf5ec3 commit c2275a0
Show file tree
Hide file tree
Showing 25 changed files with 715 additions and 559 deletions.
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,68 @@
/**
* 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 || cause instanceof GenericException
|| 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

0 comments on commit c2275a0

Please sign in to comment.