/* (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.SQLException;
import java.sql.Types;
import org.geoserver.security.GeoServerRoleService;
import org.geoserver.security.GeoServerRoleStore;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.security.impl.RoleHierarchyHelper;
/**
* JDBC Implementation of {@link GeoServerRoleStore}
*
* @author christian
*
*/
public class JDBCRoleStore extends JDBCRoleService implements GeoServerRoleStore {
protected boolean modified;
protected Connection connection;
/**
* The identical connection is used until {@link #store()} or
* {@link #load()} is called. Within a transaction it is not possible
* to use different connections.
*
* @see org.geoserver.security.jdbc.AbstractJDBCService#getConnection()
*/
@Override
public Connection getConnection() throws SQLException{
if (connection == null)
connection = super.getConnection();
return connection;
}
@Override
protected void closeConnection(Connection con) throws SQLException{
// do nothing
}
/**
* To be called at the the end of a transaction,
* frees the current {@link Connection}
*
* @throws SQLException
*/
protected void releaseConnection() throws SQLException{
if (connection!=null) {
connection.close();
connection=null;
}
}
/**
* Executes {@link Connection#rollback()} and
* frees the connection object
*
* @see org.geoserver.security.jdbc.JDBCRoleService#load()
*/
public void load() throws IOException {
// Simply roll back the transaction
try {
getConnection().rollback();
releaseConnection();
} catch (SQLException ex) {
throw new IOException(ex);
}
setModified(false);
}
protected void addRoleProperties(GeoServerRole role, Connection con) throws SQLException,IOException {
if (role.getProperties().size()==0) return; // nothing to do
PreparedStatement ps = getDMLStatement("roleprops.insert", con);
try {
for (Object key : role.getProperties().keySet()) {
Object propertyVal = role.getProperties().get(key);
ps.setString(1,role.getAuthority());
ps.setString(2,key.toString());
ps.setObject(3,propertyVal);
ps.execute();
}
} finally {
closeFinally(null, ps, null);
}
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#addRole(org.geoserver.security.impl.GeoserverRole)
*/
public void addRole(GeoServerRole role) throws IOException{
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("roles.insert", con);
ps.setString(1,role.getAuthority());
//ps.setNull(2, Types.VARCHAR);
ps.execute();
addRoleProperties(role, con);
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#updateRole(org.geoserver.security.impl.GeoserverRole)
*/
public void updateRole(GeoServerRole role) throws IOException {
// No attributes for update
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("roles.update", con);
ps.setString(1,role.getAuthority());
ps.execute();
ps.close();
ps = getDMLStatement("roleprops.deleteForRole",con);
ps.setString(1,role.getAuthority());
ps.execute();
addRoleProperties(role, con);
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true); // we do as if there was an update
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#removeRole(org.geoserver.security.impl.GeoserverRole)
*/
public boolean removeRole(GeoServerRole role) throws IOException {
Connection con = null;
PreparedStatement ps = null;
boolean retval = false;
try {
con = getConnection();
ps = getDMLStatement("roles.delete", con);
ps.setString(1,role.getAuthority());
ps.execute();
retval= ps.getUpdateCount()>0;
ps.close();
ps = getDMLStatement("userroles.deleteRole",con);
ps.setString(1,role.getAuthority());
ps.execute();
ps.close();
ps = getDMLStatement("grouproles.deleteRole",con);
ps.setString(1,role.getAuthority());
ps.execute();
ps.close();
ps = getDMLStatement("roleprops.deleteForRole", con);
ps.setString(1,role.getAuthority());
ps.execute();
ps.close();
ps = getDMLStatement("roles.deleteParent", con);
ps.setString(1,role.getAuthority());
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
return retval;
}
/**
* Executes {@link Connection#commit()} and frees
* the connection
* @see org.geoserver.security.GeoServerRoleStore#store()
*/
public void store() throws IOException {
// Simply commit the transaction
try {
getConnection().commit();
releaseConnection();
} catch (SQLException ex) {
throw new IOException(ex);
}
setModified(false);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#associateRoleToUser(org.geoserver.security.impl.GeoserverRole, java.lang.String)
*/
public void associateRoleToUser(GeoServerRole role, String username) throws IOException{
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("userroles.insert", con);
ps.setString(1,role.getAuthority());
ps.setString(2,username);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#disAssociateRoleFromUser(org.geoserver.security.impl.GeoserverRole, java.lang.String)
*/
public void disAssociateRoleFromUser(GeoServerRole role, String username) throws IOException{
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("userroles.delete", con);
ps.setString(1,role.getAuthority());
ps.setString(2,username);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#associateRoleToGroup(org.geoserver.security.impl.GeoserverRole, java.lang.String)
*/
public void associateRoleToGroup(GeoServerRole role, String groupname) throws IOException{
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("grouproles.insert", con);
ps.setString(1,role.getAuthority());
ps.setString(2,groupname);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#disAssociateRoleFromGroup(org.geoserver.security.impl.GeoserverRole, java.lang.String)
*/
public void disAssociateRoleFromGroup(GeoServerRole role, String groupname) throws IOException{
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("grouproles.delete", con);
ps.setString(1,role.getAuthority());
ps.setString(2,groupname);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
public boolean isModified() {
return modified;
}
public void setModified(boolean modified) {
this.modified=modified;
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#setParentRole(org.geoserver.security.impl.GeoserverRole, org.geoserver.security.impl.GeoserverRole)
*/
public void setParentRole(GeoServerRole role, GeoServerRole parentRole)
throws IOException {
RoleHierarchyHelper helper = new RoleHierarchyHelper(getParentMappings());
if (helper.isValidParent(role.getAuthority(),
parentRole==null ? null : parentRole.getAuthority())==false)
throw new IOException(parentRole.getAuthority() +
" is not a valid parent for " + role.getAuthority());
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("roles.parentUpdate", con);
if (parentRole == null)
ps.setNull(1, Types.VARCHAR);
else
ps.setString(1,parentRole.getAuthority());
ps.setString(2,role.getAuthority());
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#clear()
*/
public void clear() throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("grouproles.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("userroles.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("roleprops.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("roles.deleteAll", con);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverRoleStore#initializeFromService(org.geoserver.security.GeoserverRoleService)
*/
public void initializeFromService(GeoServerRoleService service) throws IOException {
JDBCRoleService jdbcService= (JDBCRoleService) service;
this.name=service.getName();
this.adminRoleName=jdbcService.adminRoleName;
this.groupAdminRoleName=jdbcService.groupAdminRoleName;
this.datasource=jdbcService.datasource;
this.ddlProps=jdbcService.ddlProps;
this.dmlProps=jdbcService.dmlProps;
this.securityManager=service.getSecurityManager();
try {
getConnection().commit();
} catch (SQLException e) {
throw new IOException(e);
}
}
}