From 9e019aa7dea905b2c839217864bd681fa169a3e0 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Mon, 16 Jul 2012 17:57:20 +0100 Subject: [PATCH] return back http error code instead of java stacktrace when no tenant identifier is provided in request. --- .../api/data/ApiGlobalErrorResponse.java | 12 +++++ ...nvalidTenantIdentifierExceptionMapper.java | 28 ++++++++++++ .../TenantAwareBasicAuthenticationFilter.java | 45 ++++++++++++------- 3 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/errorhandling/InvalidTenantIdentifierExceptionMapper.java diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ApiGlobalErrorResponse.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ApiGlobalErrorResponse.java index ca5096026..f4dbd8e83 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ApiGlobalErrorResponse.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/ApiGlobalErrorResponse.java @@ -52,6 +52,18 @@ public class ApiGlobalErrorResponse { return globalErrorResponse; } + + public static ApiGlobalErrorResponse invalidTenantIdentifier() { + + ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); + globalErrorResponse.setHttpStatusCode("401"); + globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request."); + globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes"); + globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier"); + globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request."); + + return globalErrorResponse; + } public static ApiGlobalErrorResponse unAuthorized() { ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/errorhandling/InvalidTenantIdentifierExceptionMapper.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/errorhandling/InvalidTenantIdentifierExceptionMapper.java new file mode 100644 index 000000000..1d0df4197 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/errorhandling/InvalidTenantIdentifierExceptionMapper.java @@ -0,0 +1,28 @@ +package org.mifosng.platform.api.errorhandling; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import org.mifosng.platform.api.data.ApiGlobalErrorResponse; +import org.mifosng.platform.infrastructure.InvalidTenantIdentiferException; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * An {@link ExceptionMapper} to map {@link InvalidTenantIdentiferException} thrown by platform during authentication into a HTTP API friendly format. + * + * The {@link InvalidTenantIdentiferException} is thrown by spring security on platform when a request contains an invalid tenant identifier. + */ +@Provider +@Component +@Scope("singleton") +public class InvalidTenantIdentifierExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(final InvalidTenantIdentiferException e) { + return Response.status(Status.UNAUTHORIZED).entity(ApiGlobalErrorResponse.invalidTenantIdentifier()).type(MediaType.APPLICATION_JSON).build(); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/TenantAwareBasicAuthenticationFilter.java b/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/TenantAwareBasicAuthenticationFilter.java index a466e59be..6560b0776 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/TenantAwareBasicAuthenticationFilter.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/infrastructure/TenantAwareBasicAuthenticationFilter.java @@ -7,11 +7,12 @@ import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedCredentialsNotFoundException; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; /** @@ -31,25 +32,37 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; - if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { - // ignore to allow 'preflight' requests from AJAX applications in different domain - } else { + try { - final String tenantId = request.getHeader(tenantRequestHeader); - - if (tenantId == null && exceptionIfHeaderMissing) { - throw new PreAuthenticatedCredentialsNotFoundException(tenantRequestHeader + " header not found in request."); + if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { + // ignore to allow 'preflight' requests from AJAX applications in different domain + } else { + + final String tenantId = request.getHeader(tenantRequestHeader); + + if (tenantId == null && exceptionIfHeaderMissing) { + throw new InvalidTenantIdentiferException(tenantRequestHeader + " header not found in request."); + } + + // check tenants database for tenantId + MifosPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantId); + + ThreadLocalContextUtil.setTenant(tenant); } - - // check tenants database for tenantId - MifosPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantId); - - ThreadLocalContextUtil.setTenant(tenant); - } - super.doFilter(req, res, chain); + super.doFilter(req, res, chain); + } catch (InvalidTenantIdentiferException e) { + // deal with exception at low level + SecurityContextHolder.getContext().setAuthentication(null); + + response.addHeader("WWW-Authenticate", "Basic realm=\"" + "Mifos Platform API" + "\""); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, tenantRequestHeader + " header not found in request."); + } finally { + + } } } \ No newline at end of file