/**
* 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;
}
}