package eu.geoknow.generator.users;
import java.sql.*;
import org.apache.log4j.Logger;
public class VirtuosoUserManager implements UserManager {
private static final Logger log = Logger.getLogger(VirtuosoUserManager.class);
private static final String jdbcDriver = "virtuoso.jdbc4.Driver";
private String connectionString;
private String user;
private String password;
private Connection connection;
/**
* This class manages the User creation in virtuoso for authentication and graph access control
*
* @param connectionString
* Connection string to Virtuoso
* @param user
* Virtuoso user
* @param password
* Virtuoso password
*/
public VirtuosoUserManager(String connectionString, String user, String password) {
this.connectionString = connectionString;
this.user = user;
this.password = password;
}
@Override
public void createUser(String name, String password) throws Exception {
if (checkUserExists(name, null))
throw new Exception("User " + name + " already exists");
executeUpdate(getConnection(), "DB.DBA.USER_CREATE('" + name + "', '" + password + "')"); //NB! this function doesn't throw exception if user already exists
// executeUpdate(getConnection(), "USER_SET_OPTION('" + name +
// "', 'DAV_ENABLE', 1)");
grantRole(name, "SPARQL_UPDATE");
}
@Override
public void dropUser(String name) throws ClassNotFoundException, SQLException {
executeUpdate(getConnection(), "USER_DROP('" + name + "', 1)");
}
private void grantRole(String user, String role) throws ClassNotFoundException, SQLException {
executeUpdate(getConnection(), "GRANT " + role + " TO \"" + user + "\""); //NB! this function throws exception if the role is already granted
}
@Override
public void setDefaultRdfPermissions(String user, GraphPermissions permissions)
throws ClassNotFoundException, SQLException
{
int virtuosoPerm = convertRdfStorePermissions(permissions);
executeUpdate(getConnection(), "DB.DBA.RDF_DEFAULT_USER_PERMS_SET ('" + user + "', " + virtuosoPerm + ")");
}
@Override
public void setPublicRdfPermissions(GraphPermissions permissions) throws Exception {
setDefaultRdfPermissions("nobody", permissions);
}
@Override
public void setRdfGraphPermissions(String user, String graph, GraphPermissions permissions)
throws ClassNotFoundException, SQLException
{
int virtuosoPerm = convertRdfStorePermissions(permissions);
executeUpdate(getConnection(), "DB.DBA.RDF_GRAPH_USER_PERMS_SET ('" + graph + "', '" + user + "', " + virtuosoPerm + ")");
}
@Override
public void deleteRdfGraphPermissions(String user, String graph) throws ClassNotFoundException,
SQLException {
executeUpdate(getConnection(), "DB.DBA.RDF_GRAPH_USER_PERMS_DEL ('" + graph + "', '" + user
+ "')");
}
@Override
public void setDefaultGraphPermissions(String graph, GraphPermissions permissions)
throws ClassNotFoundException, SQLException
{
int virtuosoPerm = convertRdfStorePermissions(permissions);
executeUpdate(getConnection(), "DB.DBA.RDF_GRAPH_USER_PERMS_SET ('" + graph + "', 'nobody', " + virtuosoPerm + ")");
}
/**
* This function grant L_O_LOOK in virtuoso which was required to solve the error: Virtuoso 42000
* Error SR186: No permission to execute dpipe DB.DBA.L_O_LOOK with user ID 106, group ID 106
*
* @param user
* @throws ClassNotFoundException
* @throws SQLException
*/
public void grantLOLook(String user) throws ClassNotFoundException, SQLException {
executeUpdate(getConnection(), "GRANT EXECUTE ON DB.DBA.L_O_LOOK TO \"" + user + "\"");
}
@Override
public boolean checkUserExists(String username, String email) throws Exception {
//todo is there any simpler way to check if the user exists? some function?
String query = "select * from DB.DBA.SYS_USERS where U_NAME='" + username + "'";
Connection conn = getConnection();
Statement stmt = conn.createStatement();
try {
ResultSet resultSet = stmt.executeQuery(query);
return resultSet.next();
} finally {
stmt.close();
}
}
@Override
public void changePassword(String username, String oldPassword, String newPassword) throws Exception {
executeUpdate(getConnection(), "USER_CHANGE_PASSWORD('" + username + "', '" + oldPassword + "', '" + newPassword + "')");
}
@Override
public void setPassword(String username, String newPassword) throws Exception {
executeUpdate(getConnection(), "user_set_password('" + username + "', '" + newPassword + "')");
}
@Override
public void setup() {
try {
grantRole("SPARQL", "SPARQL_UPDATE");
grantLOLook("SPARQL");
} catch (Exception e) {
// role is already granted
log.warn("SPARQL has already SPARQL_UPDATE rol");
// e.printStackTrace();
}
}
private Connection getConnection() throws ClassNotFoundException, SQLException {
if (connection == null || connection.isClosed()) {
Class.forName(jdbcDriver);
connection = DriverManager.getConnection(connectionString, user, password);
}
return connection;
}
public void close() throws SQLException {
if (connection != null)
connection.close();
}
private void executeUpdate(Connection conn, String query) throws SQLException {
log.info("EXECUTE: " + query);
Statement stmt = conn.createStatement();
try {
stmt.executeUpdate(query);
} finally {
stmt.close();
}
}
private int convertRdfStorePermissions(GraphPermissions permissions) {
switch (permissions) {
case NO: return 0;
case READ: return 1;
case WRITE: return 3;
case LIST_GRAPH_GROUP: return 8;
default: throw new IllegalArgumentException("Invalid RDF store permissions " + permissions.name());
}
}
}