/* (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;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;
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.platform.GeoServerExtensions;
import org.geoserver.security.config.SecurityNamedServiceConfig;
import org.geoserver.security.filter.AuthenticationCachingFilter;
import org.geoserver.security.filter.GeoServerAuthenticationFilter;
import org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter;
import org.geoserver.security.filter.GeoServerSecurityFilter;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.security.impl.GeoServerUser;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.Http403ForbiddenEntryPoint;
import org.springframework.util.StringUtils;
/**
* Filter extending {@link GeoServerSecurityFilter}.
*
* The encoded user name is passed as an URL parameter named {@link #authKeyParamName}.
*
* The real user name is retrieved by querying an {@link AuthenticationKeyMapper} object stored
* in {@link #authKeyMapperName}
*
* This filter needs a {@link GeoServerUserGroupService} for authentication
*
* @author christian
*
*/
public class GeoServerAuthenticationKeyFilter extends GeoServerSecurityFilter
implements AuthenticationCachingFilter, GeoServerAuthenticationFilter
{
private String authKeyMapperName,authKeyParamName;
private AuthenticationKeyMapper mapper;
private String userGroupServiceName;
protected AuthenticationEntryPoint aep;
@Override
public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
super.initializeFromConfig(config);
aep=new Http403ForbiddenEntryPoint();
AuthenticationKeyFilterConfig authConfig =
(AuthenticationKeyFilterConfig) config;
setAuthKeyParamName(authConfig.getAuthKeyParamName());
setUserGroupServiceName(authConfig.getUserGroupServiceName());
setAuthKeyMapperName(authConfig.getAuthKeyMapperName());
mapper=(AuthenticationKeyMapper) GeoServerExtensions.bean(authKeyMapperName);
mapper.setUserGroupServiceName(userGroupServiceName);
mapper.setSecurityManager(getSecurityManager());
mapper.configureMapper(authConfig.getMapperParameters());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// String authKey = getAuthKey((HttpServletRequest) request);
// if (authKey==null) { // nothing to do
// chain.doFilter(request, response);
// return;
// }
String cacheKey=authenticateFromCache(this, (HttpServletRequest) request);
if (SecurityContextHolder.getContext().getAuthentication()==null) {
doAuthenticate((HttpServletRequest) request, (HttpServletResponse) response, cacheKey);
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);
}
public String getAuthKeyMapperName() {
return authKeyMapperName;
}
public void setAuthKeyMapperName(String authKeyMapperName) {
this.authKeyMapperName = authKeyMapperName;
}
public String getAuthKeyParamName() {
return authKeyParamName;
}
public void setAuthKeyParamName(String authKeyParamName) {
this.authKeyParamName = authKeyParamName;
}
public String getUserGroupServiceName() {
return userGroupServiceName;
}
public void setUserGroupServiceName(String userGroupServiceName) {
this.userGroupServiceName = userGroupServiceName;
}
/**
* Try to authenticate and adds {@link GeoServerRole#AUTHENTICATED_ROLE}
* Does NOT authenticate {@link GeoServerUser#ROOT_USERNAME}
*
* @param request
* @param response
* @param authkey
*/
protected void doAuthenticate(HttpServletRequest request,
HttpServletResponse response,String authKey) throws IOException{
if (authKey==null)
return;
GeoServerUser user = mapper.getUser(authKey);
if (user==null) {
return;
}
// no support for root login
if (GeoServerUser.ROOT_USERNAME.equals(user.getUsername())) {
LOGGER.warning("Authentication key login does accept the root user");
return;
}
LOGGER.log(Level.FINE,"found user: = " + user.getUsername() + ", trying to authenticate");
Collection<GeoServerRole> roles= new ArrayList<GeoServerRole>();
for (GrantedAuthority auth: user.getAuthorities()) {
roles.add((GeoServerRole)auth);
}
if (roles.contains(GeoServerRole.AUTHENTICATED_ROLE)==false)
roles.add(GeoServerRole.AUTHENTICATED_ROLE);
KeyAuthenticationToken result = new KeyAuthenticationToken(authKey, authKeyParamName,user, roles);
SecurityContextHolder.getContext().setAuthentication(result);
}
public String getAuthKey(HttpServletRequest req) {
String authKey=getAuthKeyParamValue(req);
if (StringUtils.hasLength(authKey)==false)
return null;
return authKey;
}
/**
* Extracts authkey value from the request.
*
* @param req
*
*/
private String getAuthKeyParamValue(HttpServletRequest req) {
String keyParamName = getAuthKeyParamName();
for (Enumeration<String> a = req.getParameterNames(); a.hasMoreElements();) {
String paramName = a.nextElement();
if (keyParamName.equalsIgnoreCase(paramName)) {
return req.getParameter(paramName);
}
}
return null;
}
/**
* The cache key is the authentication key (global identifier)
*/
@Override
public String getCacheKey(HttpServletRequest req) {
return getAuthKey(req);
}
/**
* @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;
}
protected boolean cacheAuthentication(Authentication auth,HttpServletRequest request) {
// only cache if no HTTP session is available
if ( request.getSession(false) != null)
return false;
return true;
}
public AuthenticationKeyMapper getMapper() {
return mapper;
}
}