monasca-api/java/src/main/java/monasca/api/infrastructure/servlet/PreAuthenticationFilter.java

135 lines
4.5 KiB
Java

/*
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
*
* 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 monasca.api.infrastructure.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.ws.rs.core.MediaType;
import org.eclipse.jetty.server.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import monasca.api.resource.exception.Exceptions;
import monasca.api.resource.exception.Exceptions.FaultType;
/**
* Authenticates requests using header information from the CsMiddleware. Provides the X-TENANT-ID
* servlet attribute as a request header. Intended to be added to a servlet filter chain after the
* CsMiddleware TokenAuth filter.
*/
public class PreAuthenticationFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(PreAuthenticationFilter.class);
static class ErrorCapturingServletResponseWrapper extends HttpServletResponseWrapper {
private int statusCode;
private String errorMessage;
private Exception exception;
public ErrorCapturingServletResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public void sendError(int statusCode) throws IOException {
this.statusCode = statusCode;
}
@Override
public void sendError(int statusCode, String msg) throws IOException {
this.statusCode = statusCode;
errorMessage = msg;
}
void sendError(int statusCode, String msg, Exception exception) throws IOException {
sendError(statusCode, msg);
this.exception = exception;
}
}
@Override
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletResponse res = (HttpServletResponse) response;
ErrorCapturingServletResponseWrapper responseWrapper =
new ErrorCapturingServletResponseWrapper(res);
boolean caughtException = false;
ServletOutputStream out = null;
try {
out = res.getOutputStream();
chain.doFilter(request, responseWrapper);
if (responseWrapper.statusCode != 401 && responseWrapper.statusCode != 500)
return;
} catch (Exception e) {
LOG.error("Error while executing pre authentication filter", e);
caughtException = true;
}
try {
res.setContentType(MediaType.APPLICATION_JSON);
if (caughtException) {
res.setStatus(Response.SC_INTERNAL_SERVER_ERROR);
}
else {
res.setStatus(responseWrapper.statusCode);
FaultType faultType;
if (responseWrapper.statusCode == 500) {
faultType = FaultType.SERVER_ERROR;
}
else {
faultType = FaultType.UNAUTHORIZED;
}
String output = Exceptions.buildLoggedErrorMessage(faultType, responseWrapper.errorMessage,
null, responseWrapper.exception);
out.print(output);
}
} catch (IllegalArgumentException e) {
// CSMiddleware is throwing this error for invalid tokens.
// This problem appears to be fixed in other versions, but they are not approved yet.
try {
String output =
Exceptions.buildLoggedErrorMessage(FaultType.UNAUTHORIZED, "invalid authToken", null,
responseWrapper.exception);
out.print(output);
} catch (Exception x) {
LOG.error("Error while writing failed authentication HTTP response", x);
}
} catch (Exception e) {
LOG.error("Error while writing failed authentication HTTP response", e);
} finally {
if (out != null)
try {
out.close();
} catch (IOException ignore) {
}
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
}