/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.security.filter;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.security.config.SecurityNamedServiceConfig;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.security.impl.GeoServerUser;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
/**
* Abstract base class for pre-authentication filters
*
* @author christian
*
*/
public abstract class GeoServerPreAuthenticationFilter extends GeoServerSecurityFilter
implements AuthenticationCachingFilter, GeoServerAuthenticationFilter {
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails>
authenticationDetailsSource = new WebAuthenticationDetailsSource();
protected AuthenticationEntryPoint aep;
@Override
public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
super.initializeFromConfig(config);
aep=new Http403ForbiddenEntryPoint();
}
/**
* Try to authenticate if there is no authenticated principal
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String cacheKey=authenticateFromCache(this, (HttpServletRequest) request);
if (SecurityContextHolder.getContext().getAuthentication()==null) {
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response);
Authentication postAuthentication = SecurityContextHolder.getContext().getAuthentication();
if (postAuthentication != null && cacheKey!=null) {
if (cacheAuthentication(postAuthentication,(HttpServletRequest)request)) {
getSecurityManager().getAuthenticationCache().put(getName(), cacheKey,postAuthentication);
}
}
}
request.setAttribute(GeoServerSecurityFilter.AUTHENTICATION_ENTRY_POINT_HEADER, aep);
chain.doFilter(request, response);
}
/**
* subclasses should return the principal,
* <code>null</code> if no principal was authenticated
*
* @param request
*
*/
abstract protected String getPreAuthenticatedPrincipal(HttpServletRequest request);
/**
* subclasses should return the roles for the principal
* obtained by {@link #getPreAuthenticatedPrincipal(HttpServletRequest)}
*
* @param request
* @param principal
*
*/
abstract protected Collection<GeoServerRole> getRoles(HttpServletRequest request, String principal) throws IOException;
/**
* Try to authenticate and adds {@link GeoServerRole#AUTHENTICATED_ROLE}
* Takes care of the special user named {@link GeoServerUser#ROOT_USERNAME}
*
* @param request
* @param response
*/
protected void doAuthenticate(HttpServletRequest request, HttpServletResponse response) {
String principal = getPreAuthenticatedPrincipal(request);
if (principal==null || principal.trim().length()==0) {
return;
}
LOGGER.log(Level.FINE,"preAuthenticatedPrincipal = " + principal + ", trying to authenticate");
PreAuthenticatedAuthenticationToken result = null;
if (GeoServerUser.ROOT_USERNAME.equals(principal)) {
result = new PreAuthenticatedAuthenticationToken(principal, null, Collections.singleton(GeoServerRole.ADMIN_ROLE));
} else {
Collection<GeoServerRole> roles=null;
try {
roles = getRoles(request, principal);
} catch (IOException e) {
throw new RuntimeException(e);
}
if (roles.contains(GeoServerRole.AUTHENTICATED_ROLE)==false)
roles.add(GeoServerRole.AUTHENTICATED_ROLE);
result = new PreAuthenticatedAuthenticationToken(principal, null, roles);
}
result.setDetails(authenticationDetailsSource.buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(result);
}
public AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> getAuthenticationDetailsSource() {
return authenticationDetailsSource;
}
public void setAuthenticationDetailsSource(
AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource) {
this.authenticationDetailsSource = authenticationDetailsSource;
}
@Override
public AuthenticationEntryPoint getAuthenticationEntryPoint() {
return aep;
}
protected boolean cacheAuthentication(Authentication auth,HttpServletRequest request) {
// only cache if no HTTP session is available
return request.getSession(false) == null;
}
@Override
public String getCacheKey(HttpServletRequest request) {
if (request.getSession(false)!=null) // no caching if there is an HTTP session
return null;
String retval = getPreAuthenticatedPrincipal(request);
if (GeoServerUser.ROOT_USERNAME.equals(retval))
return null;
return retval;
}
/**
* @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForHtml()
*/
@Override
public boolean applicableForHtml() {
return true;
}
/**
* @see org.geoserver.security.filter.GeoServerAuthenticationFilter#applicableForServices()
*/
@Override
public boolean applicableForServices() {
return true;
}
}