/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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
*
* 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 org.apache.jetspeed.security.impl;
import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedAction;
import javax.security.auth.Subject;
import javax.servlet.http.HttpSession;
import org.apache.jetspeed.PortalReservedParameters;
import org.apache.jetspeed.administration.PortalAuthenticationConfiguration;
import org.apache.jetspeed.pipeline.PipelineException;
import org.apache.jetspeed.pipeline.valve.AbstractValve;
import org.apache.jetspeed.pipeline.valve.SecurityValve;
import org.apache.jetspeed.pipeline.valve.ValveContext;
import org.apache.jetspeed.request.RequestContext;
import org.apache.jetspeed.security.JSSubject;
/**
* <p>
* AbstractSecurityValve
* </p>
* <p>
*
* </p>
* @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
* @version $Id: AbstractSecurityValve.java 544402 2007-06-05 06:20:00Z taylor $
*
*/
public abstract class AbstractSecurityValve extends AbstractValve implements SecurityValve
{
protected PortalAuthenticationConfiguration authenticationConfiguration = null;
/**
*
* <p>
* getSubject
* </p>
* Should build and return a <code>javax.security.Subject</code>
* @param request
* @return Subject
*/
protected abstract Subject getSubject(RequestContext request) throws Exception;
/**
*
* <p>
* getUserPrincipal
* </p>
* Should build and return a <code>java.security.Principal</code> that represents the user name
* the Subject returned from <code>getSubject()</code>
* @param request
* @return Principal
* @throws Exception
*/
protected abstract Principal getUserPrincipal(RequestContext request) throws Exception;
/**
*
* <p>
* getSubjectFromSession
* </p>
*
* @param request
* @return javax.security.Subject or <code>null</code> if there is no servlet session attribute defined
* for the key <code>org.apache.jetspeed.PortalReservedParameters.SESSION_KEY_SUBJECT</code>.
*/
protected final Subject getSubjectFromSession(RequestContext request) throws Exception
{
return (Subject) request.getRequest().getSession().getAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT);
}
/**
* <p>
* invoke
* </p>
*
* <p>
* Uses <code>getSubject()</code> to call <code>ValveContext.invokeNext()</code> via
* <code>JSSubjectdoAsPrivileged()</code>. This method also takes care of setting the value of
* the <code>RequestContext.subject</code> property and the session attribute
* <code>org.apache.jetspeed.PortalReservedParameters.SESSION_KEY_SUBJECT</code>
* </p>
*
* @see org.apache.jetspeed.pipeline.valve.Valve#invoke(org.apache.jetspeed.request.RequestContext, org.apache.jetspeed.pipeline.valve.ValveContext)
* @param request
* @param context
* @throws PipelineException if the is an error encountered during any security operations.
*/
public void invoke( RequestContext request, ValveContext context ) throws PipelineException
{
if (isSessionExpired(request))
{
return; // short circuit processing and redirect
}
// initialize/validate security subject
Subject subject;
try
{
subject = getSubject(request);
}
catch (Exception e1)
{
throw new PipelineException(e1.getMessage(), e1);
}
request.getRequest().getSession().setAttribute(PortalReservedParameters.SESSION_KEY_SUBJECT, subject);
// set request context subject
request.setSubject(subject);
// Pass control to the next Valve in the Pipeline and execute under
// the current subject
final ValveContext vc = context;
final RequestContext rc = request;
PipelineException pe = (PipelineException) JSSubject.doAsPrivileged(subject, new PrivilegedAction()
{
public Object run()
{
try
{
vc.invokeNext(rc);
return null;
}
catch (PipelineException e)
{
return e;
}
}
}, null);
if(pe != null)
{
throw pe;
}
}
/**
* Check for hard limit session expiration time out
*
* @param request
* @return
* @throws PipelineException
*/
protected boolean isSessionExpired(RequestContext request) throws PipelineException
{
if (authenticationConfiguration != null && authenticationConfiguration.isMaxSessionHardLimitEnabled())
{
HttpSession session = request.getRequest().getSession();
long sessionCreationTime = session.getCreationTime();
long currentTime = System.currentTimeMillis();
if ((currentTime - sessionCreationTime) > authenticationConfiguration.getMsMaxSessionHardLimit())
{
session.invalidate();
String redirector = request.getRequest().getContextPath() + authenticationConfiguration.getTimeoutRedirectLocation();
// System.out.println("logging user out " + redirector + ", " + (currentTime - sessionCreationTime) + ", " + this.msMaxSessionHardLimit);
try
{
request.getResponse().sendRedirect(redirector);
}
catch (IOException e)
{
throw new PipelineException(e);
}
return true;
}
else
{
// System.out.println("Not logging user out: " + (currentTime - sessionCreationTime) + ", " + this.msMaxSessionHardLimit);
}
}
return false;
}
}