package org.ovirt.engine.core.aaa.filters; import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.ovirt.engine.core.common.action.SetSesssionSoftLimitCommandParameters; import org.ovirt.engine.core.common.action.VdcActionParametersBase; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.constants.SessionConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RestApiSessionMgmtFilter implements Filter { private static final Logger log = LoggerFactory.getLogger(RestApiSessionMgmtFilter.class); private static final int MINIMAL_SESSION_TTL = 1; private static final String BEARER = "Bearer"; @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { try { HttpServletRequest req = (HttpServletRequest) request; String engineSessionId = (String) request.getAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY); if (engineSessionId == null) { HttpSession session = req.getSession(false); if (session != null) { engineSessionId = (String) session.getAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY); if (engineSessionId != null) { request.setAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY, engineSessionId); } } } if (engineSessionId == null) { throw new ServletException("No engine session"); } int prefer = FiltersHelper.getPrefer(req); if ((prefer & FiltersHelper.PREFER_PERSISTENCE_AUTH) != 0) { HttpSession session = req.getSession(true); session.setAttribute(SessionConstants.HTTP_SESSION_ENGINE_SESSION_ID_KEY, engineSessionId); try { int ttlMinutes = Integer.parseInt(req.getHeader("Session-TTL")); if (ttlMinutes >= MINIMAL_SESSION_TTL) { // For new sessions: if (isNewSession(req)) { // Save Session-TTL on the HTTP session (in seconds). session.setMaxInactiveInterval((int) TimeUnit.MINUTES.toSeconds(ttlMinutes)); // Save Session-TTL in the Engine. setEngineSessionSoftLimit(engineSessionId, ttlMinutes); } } } catch (NumberFormatException ex) { // ignore error } } chain.doFilter(request, response); if (FiltersHelper.isAuthenticated(req)) { String headerValue = req.getHeader(FiltersHelper.Constants.HEADER_AUTHORIZATION); if ((headerValue == null || !headerValue.startsWith(BEARER)) && (prefer & FiltersHelper.PREFER_PERSISTENCE_AUTH) == 0) { InitialContext ctx = new InitialContext(); try { FiltersHelper.getBackend(ctx).runAction( VdcActionType.LogoutSession, new VdcActionParametersBase(engineSessionId) ); HttpSession session = req.getSession(false); if (session != null) { try { session.invalidate(); } catch (IllegalStateException e) { // ignore } } } finally { ctx.close(); } } } } catch (NamingException e) { log.error("REST-API session failed: {}", e.getMessage()); log.debug("Exception", e); throw new ServletException(e); } } /* * A session is considered new if this request has resulted in a log-in. At this point in time we are after the * log-in, but we can know if it took place by the value of 'ovirt_aaa_login_filter_authentication_done' attribute. * LoginFilter sets 'true' for this attribute and when a log-in is performed. */ private boolean isNewSession(HttpServletRequest req) { return req.getAttribute(FiltersHelper.Constants.REQUEST_LOGIN_FILTER_AUTHENTICATION_DONE) != null && (boolean) req.getAttribute(FiltersHelper.Constants.REQUEST_LOGIN_FILTER_AUTHENTICATION_DONE); } private void setEngineSessionSoftLimit(String engineSessionId, int ttlValue) throws IOException, NamingException { InitialContext context = new InitialContext(); try { FiltersHelper.getBackend(context).runAction(VdcActionType.SetSesssionSoftLimit, new SetSesssionSoftLimitCommandParameters(engineSessionId, ttlValue)); } finally { try { context.close(); } catch (NamingException e) { log.error("Error in REST-API session management. 'Context' object could not be manually closed. " + "This is a cleanup error only; it does not disturb application flow", e); } } } @Override public void destroy() { } }