/* (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.nio.charset.Charset; import java.util.Map; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import org.geoserver.security.GeoServerSecurityManager; import org.geoserver.security.HttpDigestUserDetailsServiceWrapper; import org.geoserver.security.config.DigestAuthenticationFilterConfig; import org.geoserver.security.config.SecurityNamedServiceConfig; import org.geoserver.security.impl.DigestAuthUtils; import org.geoserver.security.impl.GeoServerUser; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.authentication.www.DigestAuthenticationEntryPoint; import org.springframework.security.web.authentication.www.DigestAuthenticationFilter; import org.springframework.util.StringUtils; /** * Named Digest Authentication Filter * * @author mcr * */ public class GeoServerDigestAuthenticationFilter extends GeoServerCompositeFilter implements AuthenticationCachingFilter, GeoServerAuthenticationFilter { private DigestAuthenticationEntryPoint aep; @Override public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException { super.initializeFromConfig(config); DigestAuthenticationFilterConfig authConfig = (DigestAuthenticationFilterConfig) config; aep = new DigestAuthenticationEntryPoint(); aep.setKey(config.getName()); aep.setNonceValiditySeconds( authConfig.getNonceValiditySeconds()<=0 ? 300 : authConfig.getNonceValiditySeconds()); aep.setRealmName(GeoServerSecurityManager.REALM); try { aep.afterPropertiesSet(); } catch (Exception e) { throw new IOException(e); } DigestAuthenticationFilter filter = new DigestAuthenticationFilter(); filter.setCreateAuthenticatedToken(true); filter.setPasswordAlreadyEncoded(true); filter.setAuthenticationEntryPoint(aep); HttpDigestUserDetailsServiceWrapper wrapper = new HttpDigestUserDetailsServiceWrapper( getSecurityManager().loadUserGroupService(authConfig.getUserGroupServiceName()), Charset.defaultCharset()); filter.setUserDetailsService(wrapper); filter.afterPropertiesSet(); getNestedFilters().add(filter); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { req.setAttribute(GeoServerSecurityFilter.AUTHENTICATION_ENTRY_POINT_HEADER, aep); Integer validity = aep.getNonceValiditySeconds(); // upper limits in the cache, makes no sense to cache an expired authentication token req.setAttribute(GeoServerCompositeFilter.CACHE_KEY_IDLE_SECS,validity); req.setAttribute(GeoServerCompositeFilter.CACHE_KEY_LIVE_SECS,validity); super.doFilter(req, res, chain); } @Override public AuthenticationEntryPoint getAuthenticationEntryPoint() { return aep; } @Override public String getCacheKey(HttpServletRequest request) { if (request.getSession(false)!=null) // no caching if there is an HTTP session return null; String header = request.getHeader("Authorization"); if ((header != null) && header.startsWith("Digest ")) { String section212response = header.substring(7); String[] headerEntries = DigestAuthUtils.splitIgnoringQuotes(section212response, ','); Map<String,String> headerMap = DigestAuthUtils.splitEachArrayElementAndCreateMap(headerEntries, "=", "\""); String username = headerMap.get("username"); String realm = headerMap.get("realm"); String nonce = headerMap.get("nonce"); String responseDigest = headerMap.get("response"); if (StringUtils.hasLength(username)== false || StringUtils.hasLength(realm)== false || StringUtils.hasLength(nonce)== false || StringUtils.hasLength(responseDigest)== false) return null; if (GeoServerUser.ROOT_USERNAME.equals(username)) return null; StringBuffer buff = new StringBuffer(); buff.append(username).append(":"); buff.append(realm).append(":"); buff.append(nonce).append(":"); buff.append(responseDigest); return buff.toString(); } else { return null; } } /** * @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; } }