/*
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig 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:
*
* 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.searchisko.api.filter;
import org.jasig.cas.client.jaas.AssertionPrincipal;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Servlet filter performs a programmatic JAAS login using the Servlet 3.0 HttpServletRequest#login() facility.
* This component should be compatible with any servlet container that supports the Servlet 3.0/JEE6 specification.
* <p>
* The filter executes when it receives a CAS ticket and expects the
* {@link org.jasig.cas.client.jaas.CasLoginModule} JAAS module to perform the CAS
* ticket validation in order to produce an {@link org.jasig.cas.client.jaas.AssertionPrincipal} from which
* the CAS assertion is obtained and inserted into the session to enable SSO.
* <p>
* If a <code>service</code> init-param is specified for this filter, it supersedes
* the service defined for the {@link org.jasig.cas.client.jaas.CasLoginModule}.
*
* @author Daniel Fisher
* @author Marvin S. Addison
* @since 3.3
*/
public final class CasServlet3AuthenticationFilter extends AbstractCasFilter {
//TODO: Upgrade CAS client to 3.3 and use org.jasig.cas.client.jaas.Servlet3AuthenticationFilter instead of this copy
protected final Logger logger = Logger.getLogger(CasServlet3AuthenticationFilter.class.getName());
/**
* Specify whether the filter should redirect the user agent after a
* successful validation to remove the ticket parameter from the query
* string.
* @see org.jasig.cas.client.validation.AbstractTicketValidationFilter#redirectAfterValidation
*/
private boolean redirectAfterValidation = true;
@Override
protected void initInternal(FilterConfig filterConfig) throws ServletException {
setRedirectAfterValidation(parseBoolean(getPropertyFromInitParams(filterConfig, "redirectAfterValidation", "true")));
log.trace("Setting redirectAfterValidation parameter: " + this.redirectAfterValidation);
super.initInternal(filterConfig);
}
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession();
final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
if (session != null && session.getAttribute(CONST_CAS_ASSERTION) == null && ticket != null) {
try {
final String service = constructServiceUrl(request, response);
logger.log(Level.FINE, "Attempting CAS ticket validation with service={0} and ticket={1}", new Object[] {service, ticket});
request.login(service, ticket);
if (request.getUserPrincipal() instanceof AssertionPrincipal) {
final AssertionPrincipal principal = (AssertionPrincipal) request.getUserPrincipal();
logger.log(Level.FINE, "Installing CAS assertion into session.");
request.getSession().setAttribute(CONST_CAS_ASSERTION, principal.getAssertion());
if (this.redirectAfterValidation) {
logger.log(Level.FINE, "Redirecting after successful ticket validation.");
response.sendRedirect(constructServiceUrl(request, response));
return;
}
} else {
logger.log(Level.FINE, "Aborting -- principal is not of type AssertionPrincipal");
throw new GeneralSecurityException("JAAS authentication did not produce CAS AssertionPrincipal.");
}
} catch (final ServletException e) {
logger.log(Level.FINE, "JAAS authentication failed.");
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
} catch (final GeneralSecurityException e) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
}
} else if (session != null && request.getUserPrincipal() == null) {
// There is evidence that in some cases the principal can disappear
// in JBoss despite a valid session.
// This block forces consistency between principal and assertion.
logger.info("User principal not found. Removing CAS assertion from session to force re-authentication.");
session.removeAttribute(CONST_CAS_ASSERTION);
}
chain.doFilter(request, response);
}
public boolean isRedirectAfterValidation() {
return redirectAfterValidation;
}
public void setRedirectAfterValidation(boolean redirectAfterValidation) {
this.redirectAfterValidation = redirectAfterValidation;
}
}