/* (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.ArrayList; import java.util.Collection; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.security.GeoServerRoleConverter; import org.geoserver.security.GeoServerRoleService; import org.geoserver.security.GeoServerSecurityManager; import org.geoserver.security.GeoServerUserGroupService; import org.geoserver.security.config.PreAuthenticatedUserNameFilterConfig; import org.geoserver.security.config.PreAuthenticatedUserNameFilterConfig.PreAuthenticatedUserNameRoleSource; import org.geoserver.security.config.RoleSource; import org.geoserver.security.config.SecurityNamedServiceConfig; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.security.impl.GeoServerUser; import org.geoserver.security.impl.RoleCalculator; import org.springframework.security.core.GrantedAuthority; import org.springframework.util.StringUtils; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * J2EE Authentication Filter * * @author mcr * */ public abstract class GeoServerPreAuthenticatedUserNameFilter extends GeoServerPreAuthenticationFilter { private RoleSource roleSource; private String rolesHeaderAttribute; private String userGroupServiceName; private String roleConverterName; private String roleServiceName; private GeoServerRoleConverter converter; protected final static String UserNameAlreadyRetrieved = "org.geoserver.security.filter.usernameAlreadyRetrieved"; protected final static String UserName = "org.geoserver.security.filter.username"; public RoleSource getRoleSource() { return roleSource; } public void setRoleSource(RoleSource roleSource) { this.roleSource = roleSource; } public String getRolesHeaderAttribute() { return rolesHeaderAttribute; } public void setRolesHeaderAttribute(String rolesHeaderAttribute) { this.rolesHeaderAttribute = rolesHeaderAttribute; } public String getUserGroupServiceName() { return userGroupServiceName; } public void setUserGroupServiceName(String userGroupServiceName) { this.userGroupServiceName = userGroupServiceName; } public String getRoleConverterName() { return roleConverterName; } public void setRoleConverterName(String roleConverterName) { this.roleConverterName = roleConverterName; } public String getRoleServiceName() { return roleServiceName; } public void setRoleServiceName(String roleServiceName) { this.roleServiceName = roleServiceName; } @Override public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException { super.initializeFromConfig(config); PreAuthenticatedUserNameFilterConfig authConfig = (PreAuthenticatedUserNameFilterConfig) config; roleSource=authConfig.getRoleSource(); rolesHeaderAttribute=authConfig.getRolesHeaderAttribute(); userGroupServiceName=authConfig.getUserGroupServiceName(); roleConverterName=authConfig.getRoleConverterName(); roleServiceName=authConfig.getRoleServiceName(); // TODO, Justin, is this ok ? if (PreAuthenticatedUserNameRoleSource.Header.equals(getRoleSource())) { String converterName = authConfig.getRoleConverterName(); if (converterName==null || converterName.length()==0) setConverter(GeoServerExtensions.bean(GeoServerRoleConverter.class)); else setConverter((GeoServerRoleConverter) GeoServerExtensions.bean(converterName)); } } @Override protected String getPreAuthenticatedPrincipal(HttpServletRequest request) { // avoid retrieving the user name more than once if (request.getAttribute(UserNameAlreadyRetrieved)!=null) return (String) request.getAttribute(UserName); String principal = getPreAuthenticatedPrincipalName(request); if (principal!=null && principal.trim().length()==0) principal=null; try { if (principal!=null && PreAuthenticatedUserNameRoleSource.UserGroupService.equals(getRoleSource())) { GeoServerUserGroupService service = getSecurityManager().loadUserGroupService(getUserGroupServiceName()); GeoServerUser u = service.getUserByUsername(principal); if (u!=null && u.isEnabled()==false) { principal=null; handleDisabledUser(u, request); } } } catch (IOException ex) { throw new RuntimeException(ex); } request.setAttribute(UserNameAlreadyRetrieved, Boolean.TRUE); if (principal!=null) request.setAttribute(UserName,principal); return principal; } protected void handleDisabledUser(GeoServerUser u,HttpServletRequest request) { // do nothing } @Override protected Collection<GeoServerRole> getRoles(HttpServletRequest request, String principal) throws IOException{ if (PreAuthenticatedUserNameRoleSource.RoleService.equals(getRoleSource())) return getRolesFromRoleService(request, principal); if (PreAuthenticatedUserNameRoleSource.UserGroupService.equals(getRoleSource())) return getRolesFromUserGroupService(request, principal); if (PreAuthenticatedUserNameRoleSource.Header.equals(getRoleSource())) return getRolesFromHttpAttribute(request, principal); throw new RuntimeException("Never should reach this point"); } /** * Calculates roles from a {@link GeoServerRoleService} * The default service is {@link GeoServerSecurityManager#getActiveRoleService()} * * The result contains all inherited roles, but no personalized roles * * @param request * @param principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromRoleService(HttpServletRequest request, String principal) throws IOException{ boolean useActiveService = getRoleServiceName()==null || getRoleServiceName().trim().length()==0; GeoServerRoleService service = useActiveService ? getSecurityManager().getActiveRoleService() : getSecurityManager().loadRoleService(getRoleServiceName()); RoleCalculator calc = new RoleCalculator(service); return calc.calculateRoles(principal); } /** * Calculates roles using a {@link GeoServerUserGroupService} * if the principal is not found, an empty collection is returned * * @param request * @param principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromUserGroupService(HttpServletRequest request, String principal) throws IOException{ Collection<GeoServerRole> roles = new ArrayList<GeoServerRole>(); GeoServerUserGroupService service = getSecurityManager().loadUserGroupService(getUserGroupServiceName()); UserDetails details=null; try { details = service.loadUserByUsername(principal); } catch (UsernameNotFoundException ex) { LOGGER.log(Level.WARNING,"User "+ principal + " not found in " + getUserGroupServiceName()); } if (details!=null) { for (GrantedAuthority auth : details.getAuthorities()) roles.add((GeoServerRole)auth); } return roles; } /** * Calculates roles using the String found in the http header attribute * if no role string is found, anempty collection is returned * * The result contains personalized roles * * @param request * @param principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromHttpAttribute(HttpServletRequest request, String principal) throws IOException{ Collection<GeoServerRole> roles = new ArrayList<GeoServerRole>(); String rolesString =request.getHeader(getRolesHeaderAttribute()); if (rolesString ==null || rolesString.trim().length()==0) { LOGGER.log(Level.WARNING,"No roles in header attribute: " + getRolesHeaderAttribute()); return roles; } roles.addAll(getConverter().convertRolesFromString(rolesString, principal)); LOGGER.log(Level.FINE,"for principal " + principal + " found roles " + StringUtils.collectionToCommaDelimitedString(roles) + " in header " + getRolesHeaderAttribute()); return roles; } @Override public String getCacheKey(HttpServletRequest request) { // caching does not make sense if everything is in the header if (PreAuthenticatedUserNameRoleSource.Header.equals(getRoleSource())) return null; return super.getCacheKey(request); } public GeoServerRoleConverter getConverter() { return converter; } public void setConverter(GeoServerRoleConverter converter) { this.converter = converter; } abstract protected String getPreAuthenticatedPrincipalName(HttpServletRequest request); }