/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.onelogin; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; 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.PreAuthenticatedUserNameRoleSource; import org.geoserver.security.config.RoleSource; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.security.impl.GeoServerUser; import org.geoserver.security.impl.RoleCalculator; import org.geotools.util.logging.Logging; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.saml.SAMLCredential; import org.springframework.security.saml.userdetails.SAMLUserDetailsService; import org.springframework.util.StringUtils; /** * Assigns {@link GeoServerRole} to user after successful authentication * * @author Xandros */ public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService { static final Logger LOGGER = Logging.getLogger(SAMLUserDetailsServiceImpl.class); private RoleSource roleSource; private String rolesHeaderAttribute; private String userGroupServiceName; private String roleServiceName; private GeoServerRoleConverter converter; private GeoServerSecurityManager securityManager; private HttpServletRequest request; /** * Used to identify local account of user referenced by data in the SAML assertion and return UserDetails object describing the user roles */ @Override public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException { String principal = credential.getNameID().getValue(); Collection<GeoServerRole> roles = null; if (GeoServerUser.ROOT_USERNAME.equals(principal)) { roles = Collections.singleton(GeoServerRole.ADMIN_ROLE); } else { try { roles = getRoles(principal); } catch (IOException e) { throw new RuntimeException(e); } if (roles.contains(GeoServerRole.AUTHENTICATED_ROLE) == false) roles.add(GeoServerRole.AUTHENTICATED_ROLE); } return new User(principal, "", true, true, true, true, roles); } protected Collection<GeoServerRole> getRoles(String principal) throws IOException { if (PreAuthenticatedUserNameRoleSource.RoleService.equals(roleSource)) return getRolesFromRoleService(principal); if (PreAuthenticatedUserNameRoleSource.UserGroupService.equals(roleSource)) return getRolesFromUserGroupService(principal); if (PreAuthenticatedUserNameRoleSource.Header.equals(roleSource)) return getRolesFromHttpAttribute(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 principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromRoleService(String principal) throws IOException { boolean useActiveService = roleServiceName == null || roleServiceName.trim().length() == 0; GeoServerRoleService service = useActiveService ? securityManager.getActiveRoleService() : securityManager.loadRoleService(roleServiceName); 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 principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromUserGroupService(String principal) throws IOException { Collection<GeoServerRole> roles = new ArrayList<GeoServerRole>(); GeoServerUserGroupService service = securityManager .loadUserGroupService(userGroupServiceName); UserDetails details = null; try { details = service.loadUserByUsername(principal); } catch (UsernameNotFoundException ex) { LOGGER.log(Level.WARNING, "User " + principal + " not found in " + userGroupServiceName); } 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 principal * * @throws IOException */ protected Collection<GeoServerRole> getRolesFromHttpAttribute(String principal) throws IOException { Collection<GeoServerRole> roles = new ArrayList<GeoServerRole>(); if (request != null) { String rolesString = request.getHeader(rolesHeaderAttribute); if (rolesString == null || rolesString.trim().length() == 0) { LOGGER.log(Level.WARNING, "No roles in header attribute: " + rolesHeaderAttribute); return roles; } roles.addAll(converter.convertRolesFromString(rolesString, principal)); LOGGER.log(Level.FINE, "for principal " + principal + " found roles " + StringUtils.collectionToCommaDelimitedString(roles) + " in header " + rolesHeaderAttribute); } return roles; } public void setRoleSource(RoleSource roleSource) { this.roleSource = roleSource; } public void setRolesHeaderAttribute(String rolesHeaderAttribute) { this.rolesHeaderAttribute = rolesHeaderAttribute; } public void setUserGroupServiceName(String userGroupServiceName) { this.userGroupServiceName = userGroupServiceName; } public void setRoleServiceName(String roleServiceName) { this.roleServiceName = roleServiceName; } public void setConverter(GeoServerRoleConverter converter) { this.converter = converter; } public void setSecurityManager(GeoServerSecurityManager securityManager) { this.securityManager = securityManager; } public void setRequest(HttpServletRequest request) { this.request = request; } }