/*
*
* * RHQ Management Platform
* * Copyright (C) 2005-2012 Red Hat, Inc.
* * All rights reserved.
* *
* * This program is free software; you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* * the Free Software Foundation version 2 of the License.
* *
* * This program is distributed in the hope that it will be useful,
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* * GNU General Public License for more details.
* *
* * You should have received a copy of the GNU General Public License
* * along with this program; if not, write to the Free Software
* * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
package org.rhq.enterprise.server.rest;
import java.io.IOException;
import java.io.OutputStream;
import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.EJBContext;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import javax.naming.OperationNotSupportedException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.StreamingOutput;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.domain.auth.Subject;
import org.rhq.enterprise.server.auth.SessionException;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;
/**
* @author John Sanda
*/
public class ReportsInterceptor {
private final Log log = LogFactory.getLog(ReportsInterceptor.class);
@Resource
private EJBContext ejbContext;
@EJB
private SubjectManagerLocal subjectManager;
@AroundInvoke
public Object setCaller(final InvocationContext ctx) throws Exception {
AbstractRestBean target = (AbstractRestBean) ctx.getTarget();
boolean fromRest = false;
// If we are "forwarded" from the "normal" rest-api, we have a principal, that we can use
java.security.Principal p = ejbContext.getCallerPrincipal();
if (p!=null) {
target.caller = subjectManager.getSubjectByName(p.getName());
fromRest = true;
}
// If no caller was set from the "normal" api, we need to check if it is
// available in cookies, as in this case we were invoked
// from the Coregui reports function
if (target.caller==null) {
HttpServletRequest request = getRequest(ctx.getParameters());
if (request == null) {
// TODO should we throw a different exception?
String msg = "No " + HttpServletRequest.class.getName() + " parameter was found for " + getMethodName(ctx) +
". An " + HttpServletRequest.class.getName() +
" parameter must be specified in order to support authentication";
log.error(msg);
throw new OperationNotSupportedException(msg);
}
Subject subject = getSubject(request);
if (subject == null) {
throw new IllegalAccessException("Failed to validate request: could not access subject for request URL " +
request.getRequestURL());
}
target.caller = subject;
}
// Invoke the target method
Object result = ctx.proceed();
if (result instanceof StreamingOutput) {
return new LoggingStreamingOutput((StreamingOutput) result, getMethodName(ctx));
}
// TODO invalidate session?
return result;
}
private String getMethodName(InvocationContext ctx) {
return ctx.getTarget().getClass().getName() + "." + ctx.getMethod().getName();
}
private HttpServletRequest getRequest(Object[] params) {
for (Object param : params) {
if (param instanceof HttpServletRequest) {
return (HttpServletRequest) param;
}
}
return null;
}
private Subject getSubject(HttpServletRequest request) {
Cookie rhqSession = getCookie(request, "RHQ-Session");
if (rhqSession == null) {
return null;
}
String sessionId = rhqSession.getValue();
SubjectManagerLocal subjectMgr = LookupUtil.getSubjectManager();
try {
return subjectMgr.getSubjectBySessionId(Integer.parseInt(sessionId));
} catch (NumberFormatException e) {
log.warn(sessionId + " is not a valid session id.", e);
return null;
} catch (SessionException e) {
log.warn("Could not get subject for session id " + sessionId, e);
return null;
} catch (Exception e) {
log.error("An unexpected exception occurred while trying to access subject for session id " + sessionId,
e);
return null;
}
}
private Cookie getCookie(HttpServletRequest request, String name) {
if (request.getCookies()==null)
return null;
for (Cookie cookie : request.getCookies()) {
if (cookie.getName().equals(name)) {
return cookie;
}
}
return null;
}
private class LoggingStreamingOutput implements StreamingOutput {
String methodName;
StreamingOutput delegate;
public LoggingStreamingOutput(StreamingOutput delegate, String methodName) {
this.delegate = delegate;
this.methodName = methodName;
}
@Override
public void write(OutputStream output) throws IOException, WebApplicationException {
long start = System.currentTimeMillis();
try {
delegate.write(output);
} catch (IOException e) {
log.error("An exception occurred while executing " + methodName, e);
throw e;
} catch (RuntimeException e) {
log.error("An exception occurred while executing " + methodName, e);
throw e;
}
long end = System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug(methodName + " finished streaming report in " + (end - start) + " ms");
}
}
}
}