/* (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.GeoServerUserGroupService;
import org.geoserver.security.GeoServerUserGroupStore;
import org.geoserver.security.impl.GeoServerUser;
import org.geoserver.security.impl.GeoServerUserGroup;
import org.geoserver.security.password.GeoServerPasswordEncoder;
import org.geoserver.security.validation.PasswordPolicyException;
import org.geoserver.security.validation.PasswordValidatorImpl;
/**
* JDBC Implementation of {@link GeoServerUserGroupStore}
*
* @author christian
*
*/
public class JDBCUserGroupStore extends JDBCUserGroupService implements GeoServerUserGroupStore {
public JDBCUserGroupStore() throws IOException {
super();
}
protected boolean modified;
protected Connection connection;
protected JDBCUserGroupService jdbcService;
/**
* 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;
}
}
/**
* @see org.geoserver.security.GeoServerUserGroupStore#initializeFromServer(org.geoserver.security.GeoServerUserGroupService)
*/
public void initializeFromService(GeoServerUserGroupService service) throws IOException {
jdbcService= (JDBCUserGroupService) service;
setSecurityManager(service.getSecurityManager());
this.name=jdbcService.getName();
this.passwordEncoderName=service.getPasswordEncoderName();
this.passwordValidatorName=service.getPasswordValidatorName();
this.datasource=jdbcService.datasource;
this.ddlProps=jdbcService.ddlProps;
this.dmlProps=jdbcService.dmlProps;
try {
getConnection().commit();
} catch (SQLException e) {
throw new IOException();
}
}
/**
*
* Executes {@link Connection#rollback() }and
* frees the connection object
* @see org.geoserver.security.jdbc.JDBCUserGroupService#load()
*/
public void load() throws IOException {
// Simply roll back the transaction
try {
getConnection().rollback();
releaseConnection();
} catch (SQLException ex) {
throw new IOException(ex);
}
setModified(false);
//fireUserGroupChangedEvent();
}
/**
* Helper method for inserting user properties
*
* @param user
* @param con
* @throws SQLException
* @throws IOException
*/
protected void addUserProperties(GeoServerUser user, Connection con) throws SQLException,IOException {
if (user.getProperties().size()==0) return; // nothing to do
PreparedStatement ps = getDMLStatement("userprops.insert", con);
try {
for (Object key : user.getProperties().keySet()) {
Object propertyVal = user.getProperties().get(key);
ps.setString(1,user.getUsername());
ps.setString(2,key.toString());
ps.setObject(3,propertyVal);
ps.execute();
}
} finally {
closeFinally(null, ps, null);
}
}
/**
* validates and encodes the password. Do nothing
* for a not changed password of an existing user
*
* @param user
* @throws IOException
*/
protected void preparePassword(GeoServerUser user) throws IOException,PasswordPolicyException {
char []passwordArray = user.getPassword() != null ? user.getPassword().toCharArray() : null;
if (PasswordValidatorImpl.passwordStartsWithEncoderPrefix(passwordArray)!=null)
return; // do nothing, password already encoded
// we have a plain text password
// validate it
getSecurityManager().loadPasswordValidator(getPasswordValidatorName()).
validatePassword(passwordArray);
// validation ok, initializer encoder and set encoded password
GeoServerPasswordEncoder enc =
getSecurityManager().loadPasswordEncoder(getPasswordEncoderName());
enc.initializeFor(this);
user.setPassword(enc.encodePassword(user.getPassword(), null));
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#addUser(org.geoserver.security.impl.GeoserverUser)
*/
public void addUser(GeoServerUser user) throws IOException, PasswordPolicyException {
preparePassword(user);
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("users.insert", con);
ps.setString(1,user.getUsername());
if (user.getPassword() != null) {
ps.setString(2,user.getPassword());
}
else {
ps.setNull(2, Types.VARCHAR);
}
ps.setString(3,convertToString(user.isEnabled()));
ps.execute();
addUserProperties(user, con);
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#updateUser(org.geoserver.security.impl.GeoserverUser)
*/
public void updateUser(GeoServerUser user) throws IOException,PasswordPolicyException {
preparePassword(user);
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("users.update", con);
ps.setString(1,user.getPassword());
ps.setString(2,convertToString(user.isEnabled()));
ps.setString(3,user.getUsername());
ps.execute();
ps.close();
ps = getDMLStatement("userprops.deleteForUser",con);
ps.setString(1,user.getUsername());
ps.execute();
addUserProperties(user, con);
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#removeUser(org.geoserver.security.impl.GeoserverUser)
*/
public boolean removeUser(GeoServerUser user) throws IOException {
Connection con = null;
PreparedStatement ps = null;
boolean retval = false;
try {
con = getConnection();
ps = getDMLStatement("users.delete", con);
ps.setString(1,user.getUsername());
ps.execute();
retval= ps.getUpdateCount()>0;
ps.close();
ps = getDMLStatement("userprops.deleteForUser",con);
ps.setString(1,user.getUsername());
ps.execute();
ps.close();
ps = getDMLStatement("groupmembers.deleteUser", con);
ps.setString(1,user.getUsername());
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
return retval;
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#addGroup(org.geoserver.security.impl.GeoserverUserGroup)
*/
public void addGroup(GeoServerUserGroup group) throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("groups.insert", con);
ps.setString(1,group.getGroupname());
ps.setString(2,convertToString(group.isEnabled()));
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#updateGroup(org.geoserver.security.impl.GeoserverUserGroup)
*/
public void updateGroup(GeoServerUserGroup group) throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("groups.update", con);
ps.setString(1,convertToString(group.isEnabled()));
ps.setString(2,group.getGroupname());
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#removeGroup(org.geoserver.security.impl.GeoserverUserGroup)
*/
public boolean removeGroup(GeoServerUserGroup group) throws IOException {
Connection con = null;
PreparedStatement ps = null;
boolean retval=false;
try {
con = getConnection();
ps = getDMLStatement("groups.delete", con);
ps.setString(1,group.getGroupname());
ps.execute();
retval = ps.getUpdateCount()>0;
ps.close();
ps = getDMLStatement("groupmembers.deleteGroup", con);
ps.setString(1,group.getGroupname());
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.GeoServerUserGroupStore#store()
*/
public void store() throws IOException {
// Simply commit the transaction
try {
getConnection().commit();
releaseConnection();
} catch (SQLException ex) {
throw new IOException(ex);
}
setModified(false);
//fireUserGroupChangedEvent();
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#associateUserToGroup(org.geoserver.security.impl.GeoserverUser, org.geoserver.security.impl.GeoserverUserGroup)
*/
public void associateUserToGroup(GeoServerUser user, GeoServerUserGroup group)
throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("groupmembers.insert", con);
ps.setString(1,group.getGroupname());
ps.setString(2,user.getUsername());
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/* (non-Javadoc)
* @see org.geoserver.security.GeoserverUserGroupStore#disAssociateUserFromGroup(org.geoserver.security.impl.GeoserverUser, org.geoserver.security.impl.GeoserverUserGroup)
*/
public void disAssociateUserFromGroup(GeoServerUser user, GeoServerUserGroup group)
throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("groupmembers.delete", con);
ps.setString(1,group.getGroupname());
ps.setString(2,user.getUsername());
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.GeoserverUserGroupStore#clear()
*/
public void clear() throws IOException {
Connection con = null;
PreparedStatement ps = null;
try {
con = getConnection();
ps = getDMLStatement("groupmembers.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("groups.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("userprops.deleteAll", con);
ps.execute();
ps.close();
ps = getDMLStatement("users.deleteAll", con);
ps.execute();
} catch (SQLException ex) {
throw new IOException(ex);
} finally {
closeFinally(con, ps, null);
}
setModified(true);
}
/**
* Delegates to the {@link GeoServerUserGroupService} backend
*/
@Override
public GeoServerUser createUserObject(String username,String password, boolean isEnabled) throws IOException{
return jdbcService.createUserObject(username, password, isEnabled);
}
}