package dbProcs;
import com.mongodb.BasicDBObject;
import com.mongodb.CommandResult;
import com.mongodb.DB;
import com.mongodb.DBObject;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.MongoException;
import com.mongodb.MongoSocketException;
import com.mongodb.MongoSocketOpenException;
import com.mongodb.MongoTimeoutException;
import com.mongodb.ServerAddress;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Objects;
import java.util.Properties;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Used to create MongoDb connections
*
* This file is part of the Security Shepherd Project.
*
*
The Security Shepherd project is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
*
The Security Shepherd project is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
*
You should have received a copy of the GNU General Public License along with the Security
* Shepherd project. If not, see .
*
* @author Paul
*/
public class MongoDatabase {
private static final Logger log = LogManager.getLogger(MongoDatabase.class);
/**
* Method to close a MongoDb connection
*
* @param conn The connection to close
*/
public static void closeConnection(MongoClient conn) {
conn.close();
}
/**
* Method to get a MongoDb Challenge collection
*
* @param ApplicationRoot The running context of the application.
* @param path The path to the properties file to use for this connection (filtered for path
* traversal attacks)
* @return A MongoDb Collection
* @throws IOException
*/
public static MongoCredential getMongoChallengeCredentials(String ApplicationRoot, String path)
throws IOException {
// Some over paranoid input validation never hurts.
Properties prop = new Properties();
path = path.replaceAll("\\.", "").replaceAll("/", "");
log.debug("Path = " + path);
MongoCredential credential;
String mongo_props =
new File(
Objects.requireNonNull(
MongoDatabase.class.getResource("/challenges/" + path + ".properties"))
.getFile())
.getAbsolutePath();
log.debug("Level Properties File = " + path + ".properties");
try (InputStream mongo_input = Files.newInputStream(Paths.get(mongo_props))) {
prop.load(mongo_input);
}
String errorBase = "Missing property: ";
String dbname = prop.getProperty("databaseName");
if (dbname == null) {
throw new RuntimeException(errorBase + "databaseName");
}
String username = prop.getProperty("databaseUsername");
if (username == null) {
throw new RuntimeException(errorBase + "databaseUsername");
}
String pw_property = prop.getProperty("databasePassword");
if (pw_property == null) {
throw new RuntimeException(errorBase + "databasePassword");
}
char[] password = pw_property.toCharArray();
credential = MongoCredential.createScramSha1Credential(username, dbname, password);
return credential;
}
/**
* Method to get a MongoDb collection name from property file
*
* @return A MongoDb collection name
*/
public static String getMongoChallengeCollName(String ApplicationRoot, String path) {
Properties prop = new Properties();
// Some over paranoid input validation never hurts.
path = path.replaceAll("\\.", "").replaceAll("/", "");
log.debug("Path = " + path);
String mongo_props =
new File(
Objects.requireNonNull(
Database.class.getResource("/challenges/" + path + ".properties"))
.getFile())
.getAbsolutePath();
log.debug("Properties File: " + mongo_props);
try (InputStream mongo_input = Files.newInputStream(Paths.get(mongo_props))) {
prop.load(mongo_input);
} catch (IOException e) {
log.error("Could not load properties file: " + e.toString());
throw new RuntimeException(e);
}
String dbCollectionName = prop.getProperty("databaseCollection");
if (dbCollectionName == null) {
throw new RuntimeException("Missing property : databaseCollection");
}
return dbCollectionName;
}
/**
* Method to get a MongoDb Connection
*
* @return A MongoDb Connection @throws IOException @throws
*/
public static MongoClient getMongoDbConnection(String ApplicationRoot) {
Properties prop = new Properties();
// Mongo DB URL from mongo.properties
String mongo_props = Constants.MONGO_DB_PROP;
try (InputStream mongo_input = Files.newInputStream(Paths.get(mongo_props))) {
prop.load(mongo_input);
} catch (IOException e) {
log.error("Could not load properties file: " + e.toString());
throw new RuntimeException(e);
}
String errorBase = "Missing property :";
String connectionHost = prop.getProperty("connectionHost");
if (connectionHost == null) {
throw new RuntimeException(errorBase + "connectionHost");
}
String connectionPort = prop.getProperty("connectionPort");
if (connectionPort == null) {
throw new RuntimeException(errorBase + "connectionPort");
}
String connectTimeout = prop.getProperty("connectTimeout");
if (connectTimeout == null) {
throw new RuntimeException(errorBase + "connectTimeout");
}
String socketTimeout = prop.getProperty("socketTimeout");
if (socketTimeout == null) {
throw new RuntimeException(errorBase + "socketTimeout");
}
String serverSelectionTimeout = prop.getProperty("serverSelectionTimeout");
if (serverSelectionTimeout == null) {
throw new RuntimeException(errorBase + "serverSelectionTimeout");
}
MongoClientOptions.Builder optionsBuilder = MongoClientOptions.builder();
optionsBuilder.connectTimeout(Integer.parseInt(connectTimeout));
optionsBuilder.socketTimeout(Integer.parseInt(socketTimeout));
optionsBuilder.serverSelectionTimeout(Integer.parseInt(serverSelectionTimeout));
MongoClientOptions mongoOptions = optionsBuilder.build();
try (MongoClient mongoClient =
new MongoClient(
new ServerAddress(connectionHost, Integer.parseInt(connectionPort)), mongoOptions)) {
log.debug("Mongo Client: " + mongoClient);
return mongoClient;
} catch (NumberFormatException e) {
log.fatal("The port in the properties file is not a number: " + e);
throw new RuntimeException(e);
} catch (MongoSocketOpenException e) {
log.fatal("Mongo Doesn't seem to be running: " + e);
e.printStackTrace();
throw new RuntimeException(e);
} catch (MongoSocketException e) {
log.fatal("Unable to get Mongodb connection (Is it on?): " + e);
throw new RuntimeException(e);
} catch (MongoException e) {
log.fatal("Something went wrong with Mongo: " + e);
throw new RuntimeException(e);
}
}
/**
* Method to get a MongoDb Connection
*
* @param credential to connect to the MongoDB
* @return A MongoDb Connection
*/
public static MongoClient getMongoDbConnection(
String ApplicationRoot, MongoCredential credential) {
Properties prop = new Properties();
MongoClient mongoClient = null;
// Mongo DB URL from mongo.properties
String mongo_props = Constants.MONGO_DB_PROP;
try (InputStream mongo_input = Files.newInputStream(Paths.get(mongo_props))) {
prop.load(mongo_input);
} catch (IOException e) {
log.error("Could not load properties file: " + e.toString());
throw new RuntimeException(e);
}
String errorBase = "Missing property :";
String connectionHost = prop.getProperty("connectionHost");
if (connectionHost == null) {
throw new RuntimeException(errorBase + "connectionHost");
}
String connectionPort = prop.getProperty("connectionPort");
if (connectionPort == null) {
throw new RuntimeException(errorBase + "connectionPort");
}
String connectTimeout = prop.getProperty("connectTimeout");
if (connectTimeout == null) {
throw new RuntimeException(errorBase + "connectTimeout");
}
String socketTimeout = prop.getProperty("socketTimeout");
if (socketTimeout == null) {
throw new RuntimeException(errorBase + "socketTimeout");
}
String serverSelectionTimeout = prop.getProperty("serverSelectionTimeout");
if (serverSelectionTimeout == null) {
throw new RuntimeException(errorBase + "serverSelectionTimeout");
}
MongoClientOptions.Builder optionsBuilder = MongoClientOptions.builder();
optionsBuilder.connectTimeout(Integer.parseInt(connectTimeout));
optionsBuilder.socketTimeout(Integer.parseInt(socketTimeout));
optionsBuilder.serverSelectionTimeout(Integer.parseInt(serverSelectionTimeout));
MongoClientOptions mongoOptions = optionsBuilder.build();
try {
mongoClient =
new MongoClient(
new ServerAddress(connectionHost, Integer.parseInt(connectionPort)),
credential,
mongoOptions);
log.debug("Connection Host: " + connectionHost);
log.debug("Connection Port: " + Integer.parseInt(connectionPort));
log.debug("Connection Creds: " + Collections.singletonList(credential));
} catch (NumberFormatException e) {
log.fatal("The port in the properties file is not a number: " + e);
throw new RuntimeException(e);
} catch (MongoSocketException | MongoTimeoutException e) {
log.fatal("Unable to get Mongodb connection (Is it on?): " + e);
throw new RuntimeException(e);
} catch (MongoException e) {
log.fatal("Something went wrong with Mongo: " + e);
e.printStackTrace();
throw new RuntimeException(e);
} catch (Exception e) {
log.fatal("Something went wrong: " + e);
e.printStackTrace();
throw new RuntimeException(e);
}
log.debug("Mongo Client: " + mongoClient);
return mongoClient;
}
/**
* Method to get a MongoDb Database
*
* @param mongoClient mongoDb connection
* @return A MongoDb Database
*/
public static DB getMongoDatabase(MongoClient mongoClient) {
DB mongoDb = null;
Properties prop = new Properties();
// Mongo DB URL from mongo.properties
String mongo_props = Constants.MONGO_DB_PROP;
try (InputStream mongo_input = Files.newInputStream(Paths.get(mongo_props))) {
prop.load(mongo_input);
} catch (IOException e) {
log.error("Could not load properties file: " + e.toString());
throw new RuntimeException(e);
}
String dbname = prop.getProperty("databaseName");
if (dbname == null) {
throw new RuntimeException("Missing property : databaseName");
}
try {
mongoDb = mongoClient.getDB(dbname);
} catch (MongoSocketException | MongoTimeoutException e) {
log.fatal("Unable to get Mongodb connection (Is it on?): " + e);
} catch (MongoException e) {
log.fatal("Something went wrong with Mongo: " + e);
e.printStackTrace();
} catch (Exception e) {
log.fatal("Something went wrong: " + e);
e.printStackTrace();
}
return mongoDb;
}
/**
* Method to execute a mongo database JS file in a Mongo Database
*
* @param file the file to run
* @param mongoClient to get connection to db
*/
public static void executeMongoScript(File file, MongoClient mongoClient) throws IOException {
String data = FileUtils.readFileToString(file, Charset.defaultCharset());
DB db = MongoDatabase.getMongoDatabase(mongoClient);
DBObject script = new BasicDBObject();
script.put("eval", String.format(data));
CommandResult result = db.command(script);
log.debug("Mongo Result: " + result);
}
}