/* (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.jdbc; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import java.util.logging.Logger; import org.geoserver.platform.resource.Resource; import org.geoserver.security.GeoServerRoleService; import org.geoserver.security.GeoServerRoleStore; import org.geoserver.security.config.SecurityNamedServiceConfig; import org.geoserver.security.config.SecurityRoleServiceConfig; import org.geoserver.security.event.RoleLoadedEvent; import org.geoserver.security.event.RoleLoadedListener; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.security.impl.Util; import org.geoserver.security.jdbc.config.JDBCSecurityServiceConfig; import org.springframework.util.StringUtils; /** * JDBC implementation of {@link GeoServerRoleService} * * @author christian * */ public class JDBCRoleService extends AbstractJDBCService implements GeoServerRoleService { final static String DEFAULT_DML_FILE="rolesdml.xml"; final static String DEFAULT_DDL_FILE="rolesddl.xml"; /** logger */ static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.security.jdbc"); protected Set<RoleLoadedListener> listeners = Collections.synchronizedSet(new HashSet<RoleLoadedListener>()); protected String adminRoleName, groupAdminRoleName; public JDBCRoleService() { } @Override public GeoServerRole getAdminRole() { if (StringUtils.hasLength(adminRoleName)==false) return null; try { return getRoleByName(adminRoleName); } catch (IOException e) { throw new RuntimeException(e); } } @Override public GeoServerRole getGroupAdminRole() { if (StringUtils.hasLength(groupAdminRoleName)==false) return null; try { return getRoleByName(groupAdminRoleName); } catch (IOException e) { throw new RuntimeException(e); } } @Override public boolean canCreateStore() { return true; } @Override public GeoServerRoleStore createStore() throws IOException { JDBCRoleStore store = new JDBCRoleStore(); store.initializeFromService(this); return store; } /** * Uses {@link #initializeDSFromConfig(SecurityNamedServiceConfig)} * and {@link #checkORCreateJDBCPropertyFile(String, File, String)} * * @see org.geoserver.security.GeoServerRoleService#initializeFromConfig(org.geoserver.security.config.SecurityNamedServiceConfig) */ @Override public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException { this.name=config.getName(); initializeDSFromConfig(config); if (config instanceof JDBCSecurityServiceConfig) { JDBCSecurityServiceConfig jdbcConfig = (JDBCSecurityServiceConfig) config; String fileNameDML =jdbcConfig.getPropertyFileNameDML(); Resource file = checkORCreateJDBCPropertyFile(fileNameDML,getConfigRoot(),DEFAULT_DML_FILE); dmlProps = Util.loadUniversal(file.in()); String fileNameDDL =jdbcConfig.getPropertyFileNameDDL(); if (fileNameDDL!=null && fileNameDDL.length()> 0 ) { file = checkORCreateJDBCPropertyFile(fileNameDDL, getConfigRoot(), DEFAULT_DDL_FILE); ddlProps = Util.loadUniversal(file.in()); createTablesIfRequired((JDBCSecurityServiceConfig)config); } } this.adminRoleName=((SecurityRoleServiceConfig)config).getAdminRoleName(); this.groupAdminRoleName=((SecurityRoleServiceConfig)config).getGroupAdminRoleName(); } /** * @see org.geoserver.security.jdbc.AbstractJDBCService#getOrderedNamesForCreate() */ protected String[] getOrderedNamesForCreate() { return new String[] { "roles.create","roleprops.create","userroles.create","userroles.indexcreate", "grouproles.create","grouproles.indexcreate" }; } /** * @see org.geoserver.security.jdbc.AbstractJDBCService#getOrderedNamesForDrop() */ protected String[] getOrderedNamesForDrop() { return new String[] { "grouproles.drop","userroles.drop","roleprops.drop","roles.drop" }; } /** * @see org.geoserver.security.GeoServerRoleService#getRoleByName(java.lang.String) */ public GeoServerRole getRoleByName(String role) throws IOException { Connection con=null; PreparedStatement ps = null,ps2=null; ResultSet rs = null,rs2=null; GeoServerRole roleObject = null; try { con = getConnection(); ps = getDMLStatement("roles.keyed",con); ps.setString(1, role); rs = ps.executeQuery(); if (rs.next()) { roleObject = createRoleObject(role); ps2 = getDMLStatement("roleprops.selectForRole",con); ps2.setString(1, role); rs2 = ps2.executeQuery(); while (rs2.next()) { String propName = rs2.getString(1); Object propValue = rs2.getObject(2); if (propName != null) { roleObject.getProperties().put(propName, propValue==null ? "" : propValue ); } } } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(null, ps2, rs2); closeFinally(con, ps, rs); } return roleObject; } /** * @see org.geoserver.security.GeoServerRoleService#getRoles() */ public SortedSet<GeoServerRole> getRoles() throws IOException { Connection con=null; PreparedStatement ps = null; ResultSet rs = null; Map<String,GeoServerRole> map = new HashMap<String,GeoServerRole>(); try { con = getConnection(); ps = getDMLStatement("roles.all",con); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); GeoServerRole roleObject = createRoleObject(rolename); map.put(rolename, roleObject); } ps.close(); rs.close(); ps = getDMLStatement("roleprops.all",con); rs = ps.executeQuery(); while (rs.next()) { String roleName = rs.getString(1); String propName = rs.getString(2); Object propValue = rs.getString(3); GeoServerRole roleObject = map.get(roleName); if (roleObject!=null) { roleObject.getProperties().put(propName, propValue==null ? "" : propValue); } } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(con, ps, rs); } SortedSet<GeoServerRole> roles = new TreeSet<GeoServerRole>(); roles.addAll(map.values()); return Collections.unmodifiableSortedSet(roles); } /** * @see org.geoserver.security.GeoServerRoleService#getParentMappings() */ public Map<String,String> getParentMappings() throws IOException { Connection con=null; PreparedStatement ps = null; ResultSet rs = null; Map<String,String> map = new HashMap<String,String>(); try { con = getConnection(); ps = getDMLStatement("roles.all",con); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); String parentname = rs.getString(2); map.put(rolename, parentname); } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(con, ps, rs); } return Collections.unmodifiableMap(map); } /** * @see org.geoserver.security.GeoServerRoleService#createRoleObject(java.lang.String) */ public GeoServerRole createRoleObject(String role) { return new GeoServerRole(role); } /** * @see org.geoserver.security.GeoServerRoleService#getRolesForUser(java.lang.String) */ public SortedSet<GeoServerRole> getRolesForUser(String username) throws IOException { Connection con=null; PreparedStatement ps = null,ps2 = null; ResultSet rs = null,rs2=null; Map<String,GeoServerRole> map = new HashMap<String,GeoServerRole>(); try { con = getConnection(); ps = getDMLStatement("userroles.rolesForUser",con); ps.setString(1, username); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); GeoServerRole roleObject = createRoleObject(rolename); map.put(rolename,roleObject); } rs.close(); ps.close(); ps = getDMLStatement("roleprops.selectForUser",con); ps.setString(1, username); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); String propName = rs.getString(2); Object propValue = rs.getObject(3); GeoServerRole roleObject = map.get(rolename); if (roleObject!=null) { roleObject.getProperties().put(propName, propValue==null ? "" : propValue); } } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(null, ps2, rs2); closeFinally(con, ps, rs); } TreeSet<GeoServerRole>roles= new TreeSet<GeoServerRole>(); roles.addAll(map.values()); return Collections.unmodifiableSortedSet(roles); } /** * @see org.geoserver.security.GeoServerRoleService#getRolesForGroup(java.lang.String) */ public SortedSet<GeoServerRole> getRolesForGroup(String groupname) throws IOException { Connection con=null; PreparedStatement ps = null,ps2 = null; ResultSet rs = null,rs2=null; Map<String,GeoServerRole> map = new HashMap<String,GeoServerRole>(); try { con = getConnection(); ps = getDMLStatement("grouproles.rolesForGroup",con); ps.setString(1, groupname); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); GeoServerRole roleObject = createRoleObject(rolename); map.put(rolename,roleObject); } rs.close(); ps.close(); ps = getDMLStatement("roleprops.selectForGroup",con); ps.setString(1, groupname); rs = ps.executeQuery(); while (rs.next()) { String rolename = rs.getString(1); String propName = rs.getString(2); Object propValue = rs.getObject(3); GeoServerRole roleObject = map.get(rolename); if (roleObject!=null) { roleObject.getProperties().put(propName, propValue==null ? "" : propValue); } } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(null, ps2, rs2); closeFinally(con, ps, rs); } TreeSet<GeoServerRole>roles= new TreeSet<GeoServerRole>(); roles.addAll(map.values()); return Collections.unmodifiableSortedSet(roles); } /** * @see org.geoserver.security.GeoServerRoleService#load() */ public void load() throws IOException { // do nothing } /** * @see org.geoserver.security.GeoServerRoleService#getParentRole(org.geoserver.security.impl.GeoServerRole) */ public GeoServerRole getParentRole(GeoServerRole role) throws IOException { Connection con=null; PreparedStatement ps = null,ps2=null; ResultSet rs = null,rs2=null; GeoServerRole roleObject = null; try { con = getConnection(); ps = getDMLStatement("roles.keyed",con); ps.setString(1, role.getAuthority()); rs = ps.executeQuery(); if (rs.next()) { String parent = rs.getString(1); if (parent!=null) { // do we have a parent ? roleObject = createRoleObject(parent); ps2 = getDMLStatement("roleprops.selectForRole",con); ps2.setString(1, parent); rs2 = ps2.executeQuery(); while (rs2.next()) { String propName = rs2.getString(1); Object propValue = rs2.getObject(2); roleObject.getProperties().put(propName, propValue==null ? "" : propValue); } } } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(null, ps2, rs2); closeFinally(con, ps, rs); } return roleObject; } /** * @see org.geoserver.security.GeoServerRoleService#registerRoleLoadedListener(RoleLoadedListener) */ public void registerRoleLoadedListener(RoleLoadedListener listener) { listeners.add(listener); } /** * @see org.geoserver.security.GeoServerRoleService#unregisterRoleLoadedListener(RoleLoadedListener) */ public void unregisterRoleLoadedListener(RoleLoadedListener listener) { listeners.remove(listener); } /** * Fire {@link RoleLoadedEvent} for all listeners */ protected void fireRoleChangedEvent() { RoleLoadedEvent event = new RoleLoadedEvent(this); for (RoleLoadedListener listener : listeners) { listener.rolesChanged(event); } } /** * @see org.geoserver.security.GeoServerRoleService#getGroupNamesForRole(org.geoserver.security.impl.GeoServerRole) */ public SortedSet<String> getGroupNamesForRole(GeoServerRole role) throws IOException { Connection con=null; PreparedStatement ps = null; ResultSet rs = null; SortedSet<String> result = new TreeSet<String>(); try { con = getConnection(); ps = getDMLStatement("grouproles.groupsForRole",con); ps.setString(1, role.getAuthority()); rs = ps.executeQuery(); while (rs.next()) { String groupname = rs.getString(1); result.add(groupname); } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(con, ps, rs); } return Collections.unmodifiableSortedSet(result); } /** * @see org.geoserver.security.GeoServerRoleService#getUserNamesForRole(org.geoserver.security.impl.GeoServerRole) */ public SortedSet<String> getUserNamesForRole(GeoServerRole role) throws IOException{ Connection con=null; PreparedStatement ps = null; ResultSet rs = null; SortedSet<String> result = new TreeSet<String>(); try { con = getConnection(); ps = getDMLStatement("userroles.usersForRole",con); ps.setString(1, role.getAuthority()); rs = ps.executeQuery(); while (rs.next()) { String username = rs.getString(1); result.add(username); } } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(con, ps, rs); } return Collections.unmodifiableSortedSet(result); } /* (non-Javadoc) * @see org.geoserver.security.GeoServerRoleService#getRoleCount() */ public int getRoleCount() throws IOException{ Connection con=null; PreparedStatement ps = null; ResultSet rs = null; int count; try { con = getConnection(); ps = getDMLStatement("roles.count",con); rs = ps.executeQuery(); rs.next(); count=rs.getInt(1); } catch (SQLException ex) { throw new IOException(ex); } finally { closeFinally(con, ps, rs); } return count; } /** * @see org.geoserver.security.GeoServerRoleService#personalizeRoleParams(java.lang.String, java.util.Properties, java.lang.String, java.util.Properties) * * Default implementation: if a user property name equals a role propertyname, * take the value from to user property and use it for the role property. * */ public Properties personalizeRoleParams (String roleName,Properties roleParams, String userName,Properties userProps) throws IOException { Properties props = null; // this is true if the set is modified --> common // property names exist props = new Properties(); boolean personalized=false; for (Object key: roleParams.keySet()) { if (userProps.containsKey(key)) { props.put(key, userProps.get(key)); personalized=true; } else props.put(key,roleParams.get(key)); } return personalized ? props : null; } /** * The root configuration for the role service. */ public Resource getConfigRoot() throws IOException { return getSecurityManager().get("security/role").get(getName()); } }