/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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 org.apereo.portal.url; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.security.IAuthorizationPrincipal; import org.apereo.portal.security.IAuthorizationService; import org.apereo.portal.security.IPermission; import org.apereo.portal.security.IPerson; import org.apereo.portal.security.IPersonManager; import org.apereo.portal.security.ISecurityContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; public class MaxInactiveInterceptor extends HandlerInterceptorAdapter { // IPerson attribute key to flag if this value has already been set private static final String SESSION_MAX_INACTIVE_SET_ATTR = "MAX_INACTIVE_SET"; protected final Log log = LogFactory.getLog(getClass()); private IPersonManager personManager; private IAuthorizationService authorizationService; @Autowired public void setPersonManager(IPersonManager personManager) { this.personManager = personManager; } @Autowired public void setAuthorizationService(IAuthorizationService authorizationService) { this.authorizationService = authorizationService; } @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { final HttpSession session = request.getSession(false); if (session == null) { return true; } // Now see if authentication was successful... final IPerson person = this.personManager.getPerson((HttpServletRequest) request); if (person == null) { return true; } // Check if the session max inactive value has already been set Boolean isAlreadySet = (Boolean) person.getAttribute(this.SESSION_MAX_INACTIVE_SET_ATTR); if (isAlreadySet != null && isAlreadySet.equals(Boolean.TRUE)) { if (log.isDebugEnabled()) { log.debug( "Session.setMaxInactiveInterval() has already been determined for user '" + person.getAttribute(IPerson.USERNAME) + "'"); } return true; } final ISecurityContext securityContext = person.getSecurityContext(); if (securityContext != null && securityContext.isAuthenticated()) { // We have an authenticated user... let's see if any MAX_INACTIVE settings apply... IAuthorizationPrincipal principal = authorizationService.newPrincipal( (String) person.getAttribute(IPerson.USERNAME), IPerson.class); Integer rulingGrant = null; Integer rulingDeny = null; IPermission[] permissions = authorizationService.getAllPermissionsForPrincipal( principal, IPermission.PORTAL_SYSTEM, "MAX_INACTIVE", null); assert (permissions != null); if (permissions.length == 0) { // No max inactive permission set for this user if (log.isInfoEnabled()) { log.info( "No MAX_INACTIVE permissions apply to user '" + person.getAttribute(IPerson.USERNAME) + "'"); } person.setAttribute(this.SESSION_MAX_INACTIVE_SET_ATTR, Boolean.TRUE); return true; } for (IPermission p : permissions) { // First be sure the record applies currently... long now = System.currentTimeMillis(); if (p.getEffective() != null && p.getEffective().getTime() > now) { // It's *TOO EARLY* for this record... move on. continue; } if (p.getExpires() != null && p.getExpires().getTime() < now) { // It's *TOO LATE* for this record... move on. continue; } if (p.getType().equals(IPermission.PERMISSION_TYPE_GRANT)) { try { Integer grantEntry = Integer.valueOf(p.getTarget()); if (rulingGrant == null || grantEntry.intValue() < 0 /* Any negative number trumps all */ || rulingGrant.intValue() < grantEntry.intValue()) { rulingGrant = grantEntry; } } catch (NumberFormatException nfe) { log.warn( "Invalid MAX_INACTIVE permission grant '" + p.getTarget() + "'; target must be an integer value."); } } else if (p.getType().equals(IPermission.PERMISSION_TYPE_DENY)) { try { Integer denyEntry = Integer.valueOf(p.getTarget()); if (rulingDeny == null || rulingDeny.intValue() > denyEntry.intValue()) { rulingDeny = denyEntry; } } catch (NumberFormatException nfe) { log.warn( "Invalid MAX_INACTIVE permission deny '" + p.getTarget() + "'; target must be an integer value."); } } else { log.warn("Unknown permission type: " + p.getType()); } } if (rulingDeny != null && rulingDeny.intValue() < 0) { // Negative MaxInactiveInterval values mean the session never // times out, so a negative DENY is somewhat nonsensical... just // clear it. log.warn( "A MAX_INACTIVE DENY entry improperly specified a negative target: " + rulingDeny.intValue()); rulingDeny = null; } if (rulingGrant != null || rulingDeny != null) { // We only want to intervene if there's some actual value // specified... otherwise we'll just let the container settings //govern. int maxInactive = rulingGrant != null ? rulingGrant.intValue() : 0; // If rulingGrant is null, rulingDeny won't be... if (rulingDeny != null) { // Applying DENY entries is tricky b/c GRANT entries may be negative... int limit = rulingDeny.intValue(); if (maxInactive >= 0) { maxInactive = limit < maxInactive ? limit : maxInactive; } else { // The best grant was negative (unlimited), so go with limit... maxInactive = limit; } } // Apply the specified setting... session.setMaxInactiveInterval(maxInactive); person.setAttribute(this.SESSION_MAX_INACTIVE_SET_ATTR, Boolean.TRUE); if (log.isInfoEnabled()) { log.info( "Setting maxInactive to '" + maxInactive + "' for user '" + person.getAttribute(IPerson.USERNAME) + "'"); } } } return true; } }