cs348/Project_3/Project3.java
2018-11-20 12:34:23 -05:00

675 lines
26 KiB
Java

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.sql.*;
import java.util.Scanner;
public class Project3 {
private static Connection con;
private static Scanner in;
private static PrintWriter out;
private static int loggedInUserId = -1;
public static void main(String[] args) {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
String u = "mocull";
String p = "lyaN8EVc";
con = DriverManager.getConnection("jdbc:oracle:thin:@claros.cs.purdue.edu:1524:strep", u, p);
} catch (SQLException e) {
e.printStackTrace();
}
try {
in = new Scanner(new FileReader(args[0]));
in.useDelimiter(System.getProperty("line.separator"));
out = new PrintWriter(args[1], "UTF-8");
int commandCounter = 0;
String command = "";
String result = "";
while (in.hasNext()) {
command = in.next();
commandCounter++;
out.println(commandCounter + ": " + command);
System.out.println(commandCounter + ": " + command);
try {
result = process(command);
} catch (Exception err) {
System.out.println("ERROR ON COMMAND " + commandCounter + ":");
err.printStackTrace();
result = "An error occurred, check the logs (stdout) for more information.";
}
out.println(result);
out.println("");
System.out.println(result);
System.out.println("");
}
out.close();
} catch (FileNotFoundException err) {
System.out.println("Input or output file not found.");
} catch (UnsupportedEncodingException err) {
System.out.println("Input or output file are not UTF-8 encoded.");
}
}
public static String autokeyEncrypt(String plaintext, String key) {
//System.out.println(plaintext + " + " + key);
key = key.toUpperCase();
String plaintextUpper = plaintext.toUpperCase();
String kPrime = key + plaintext;
kPrime = kPrime.toUpperCase().substring(0, plaintext.length());
char[] ciphertextChars = kPrime.toCharArray();
final int toLowerOffset = 'a' - 'A';
int j = 0;
for (int i = 0; i < ciphertextChars.length; i++) {
while (kPrime.charAt(j) < 'A' || kPrime.charAt(j) > 'Z') {
j++;
}
//System.out.println("j=" + j + " : " + kPrime.charAt(j));
char plainChar = plaintextUpper.charAt(i);
if (plainChar >= 'A' && plainChar <= 'Z'
&& kPrime.charAt(j) >= 'A' && kPrime.charAt(j) <= 'Z') {
ciphertextChars[i] = (char) (((kPrime.charAt(j) - 'A') + (plainChar - 'A')) % 26 + 'A');
j++;
} else {
// Special character.
ciphertextChars[i] = plaintextUpper.charAt(i);
}
}
// Convert to capitals after the shift.
for (int i = 0; i < ciphertextChars.length; i++) {
char plainChar = plaintext.charAt(i);
boolean plainIsUpper = plainChar >= 'A' && plainChar <= 'Z';
boolean plainIsLower = plainChar >= 'a' && plainChar <= 'z';
boolean plainIsAlpha = plainIsLower || plainIsUpper;
boolean cipherIsUpper = ciphertextChars[i] >= 'A' && ciphertextChars[i] <= 'Z';
boolean cipherIsLower = ciphertextChars[i] >= 'a' && ciphertextChars[i] <= 'z';
if (plainIsAlpha) {
if (plainIsUpper && cipherIsLower) {
ciphertextChars[i] -= toLowerOffset;
} else if (plainIsLower && cipherIsUpper) {
ciphertextChars[i] += toLowerOffset;
}
}
}
//System.out.println(" -> " + String.valueOf(ciphertextChars));
return String.valueOf(ciphertextChars);
}
public static String autokeyDecrypt(String ciphertext, String key) {
//System.out.println(ciphertext + " + " + key);
key = key.toUpperCase();
String ciphertextUpper = ciphertext.toUpperCase();
String kPrime = key;
char[] plaintextChars = ciphertext.toCharArray();
final int toLowerOffset = 'a' - 'A';
int j = 0;
for (int i = 0; i < ciphertext.length(); i++) {
while (kPrime.charAt(j) < 'A' || kPrime.charAt(j) > 'Z') {
j++;
}
if (ciphertextUpper.charAt(i) >= 'A' && ciphertextUpper.charAt(i) <= 'Z'
&& kPrime.charAt(j) >= 'A' && kPrime.charAt(j) <= 'Z') {
int shift = ((ciphertextUpper.charAt(i) - 'A') - (kPrime.charAt(j) - 'A'));
if (shift < 0) {
shift += 26;
}
shift = shift % 26 + 'A';
plaintextChars[i] = (char) (shift);
kPrime += (char) (shift);
j++;
} else {
// Special character.
plaintextChars[i] = ciphertextUpper.charAt(i);
}
}
// Convert to capitals after the shift.
for (int i = 0; i < plaintextChars.length; i++) {
char caseChar = ciphertext.charAt(i);
boolean caseIsUpper = caseChar >= 'A' && caseChar <= 'Z';
boolean caseIsLower = caseChar >= 'a' && caseChar <= 'z';
boolean caseIsAlpha = caseIsLower || caseIsUpper;
boolean cipherIsUpper = plaintextChars[i] >= 'A' && plaintextChars[i] <= 'Z';
boolean cipherIsLower = plaintextChars[i] >= 'a' && plaintextChars[i] <= 'z';
if (caseIsAlpha) {
if (caseIsUpper && cipherIsLower) {
plaintextChars[i] -= toLowerOffset;
} else if (caseIsLower && cipherIsUpper) {
plaintextChars[i] += toLowerOffset;
}
}
}
//System.out.println(" -> " + String.valueOf(plaintextChars));
return String.valueOf(plaintextChars);
}
public static String process(String command) throws Exception {
String[] items = command.split(" ");
if (items[0].equalsIgnoreCase("LOGIN")) {
return login(items[1], items[2]);
} else if (items[0].equalsIgnoreCase("CREATE")) {
if (items[1].equalsIgnoreCase("ROLE")) {
return createRole(items[2], items[3]);
} else if (items[1].equalsIgnoreCase("USER")) {
return createUser(items[2], items[3]);
}
} else if (items[0].equalsIgnoreCase("GRANT")) {
if (items[1].equalsIgnoreCase("ROLE")) {
return grantRole(items[2], items[3]);
} else if (items[1].equalsIgnoreCase("PRIVILEGE")) {
return grantPrivilege(items[2], items[4], items[6]);
}
} else if (items[0].equalsIgnoreCase("REVOKE")) {
return revokePrivilege(items[2], items[4], items[6]);
} else if (items[0].equalsIgnoreCase("INSERT")) {
String[] leftOfValues = command.split("VALUES")[0].trim().split(" ");
String[] rightOfEncrypt = command.split("ENCRYPT")[1].trim().split(" ");
String values = command.split("VALUES ")[1].trim().split(" ENCRYPT")[0];
return insert(leftOfValues[2], values, Integer.parseInt(rightOfEncrypt[0]), rightOfEncrypt[1]);
} else if (items[0].equalsIgnoreCase("SELECT")) {
return select(items[1], items[3]);
} else if (items[0].equalsIgnoreCase("QUIT")) {
return quit();
}
throw new Exception("Unknown command.");
}
private static boolean isAdmin() {
return loggedInUserId == 1;
}
private static boolean hasPermission(String tableName, String privName) {
if (isAdmin()) {
return true;
}
int privid = -1;
String stmt = "SELECT privid FROM Privileges WHERE privname=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, privName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
privid = rs.getInt("privid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
// SELECT P.roleid, privid, tablename FROM (SELECT roleid FROM UsersRoles WHERE userid=2) R, RolesPrivileges P WHERE P.roleid=R.roleid AND privid=1 AND tablename='Products';
stmt = "SELECT P.roleid, privid, tablename FROM (SELECT roleid FROM UsersRoles WHERE userid=?) R, RolesPrivileges P WHERE P.roleid=R.roleid AND privid=? AND tablename=?";
boolean success = false;
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, loggedInUserId);
ps.setInt(2, privid);
ps.setString(3, tableName);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
success = true;
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return success;
}
private static String login(String username, String password) {
String stmt = "SELECT R.userid, R.roleid FROM (SELECT userid FROM Users WHERE username=? AND password=?) U, UsersRoles R WHERE U.userid = R.userid";
String exitResponse = "Invalid login";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, username);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
loggedInUserId = rs.getInt("userid");
exitResponse = "Login successful";
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
exitResponse = "Invalid login";
}
return exitResponse;
}
private static String createRole(String roleName, String encryptionKey) {
String exitResponse = "Authorization failure";
if (isAdmin()) {
try {
String stmt = "SELECT MAX(roleid) AS roleid FROM Roles";
int maxId = -1;
try {
PreparedStatement ps = con.prepareStatement(stmt);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
maxId = rs.getInt("roleid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (maxId > 0) {
int nextId = maxId + 1;
stmt = "INSERT INTO Roles VALUES(?, ?, ?)";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, nextId);
ps.setString(2, roleName);
ps.setString(3, encryptionKey);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "Role created successfully";
} else {
throw new Exception("Incorrect number of roles updated.");
}
} catch(SQLException e) {
e.printStackTrace();
}
} else {
throw new Exception("Failed to retrieve maximum role ID.");
}
return exitResponse;
} catch (Exception err) {
err.printStackTrace();
}
}
return exitResponse;
}
private static String createUser(String username, String password) {
String exitResponse = "Authorization failure";
if (isAdmin()) {
try {
String stmt = "SELECT MAX(userid) AS userid FROM Users";
int maxId = -1;
try {
PreparedStatement ps = con.prepareStatement(stmt);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
maxId = rs.getInt("userid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (maxId > 0) {
int nextId = maxId + 1;
stmt = "INSERT INTO Users VALUES(?, ?, ?)";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, nextId);
ps.setString(2, username);
ps.setString(3, password);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "User created successfully";
} else {
throw new Exception("Incorrect number of users updated.");
}
} catch(SQLException e) {
e.printStackTrace();
}
} else {
throw new Exception("Failed to retrieve maximum user ID.");
}
return exitResponse;
} catch (Exception err) {
err.printStackTrace();
}
}
return exitResponse;
}
private static String grantRole(String username, String roleName) {
String exitResponse = "Authorization failure";
if (isAdmin()) {
try {
int userid = -1;
int roleid = -1;
String stmt = "SELECT userid FROM Users WHERE username=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, username);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
userid = rs.getInt("userid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = "SELECT roleid FROM Roles WHERE rolename=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, roleName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
roleid = rs.getInt("roleid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (userid > 0 && roleid > 0) {
stmt = "INSERT INTO UsersRoles VALUES(?, ?)";
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, userid);
ps.setInt(2, roleid);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "Role assigned successfully";
} else {
throw new Exception("Incorrect number of user roles updated.");
}
} else {
throw new Exception("Failed to retrieve user or role ID.");
}
return exitResponse;
} catch (Exception err) {
err.printStackTrace();
}
}
return exitResponse;
}
private static String grantPrivilege(String privName, String roleName, String tableName) {
String exitResponse = "Authorization failure";
if (isAdmin()) {
try {
int privid = -1;
int roleid = -1;
String stmt = "SELECT privid FROM Privileges WHERE privname=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, privName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
privid = rs.getInt("privid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = "SELECT roleid FROM Roles WHERE rolename=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, roleName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
roleid = rs.getInt("roleid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (privid > 0 && roleid > 0) {
stmt = "INSERT INTO RolesPrivileges VALUES(?, ?, ?)";
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, roleid);
ps.setInt(2, privid);
ps.setString(3, tableName);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "Privilege granted successfully";
} else {
throw new Exception("Incorrect number of role privileges updated.");
}
} else {
throw new Exception("Failed to retrieve privilege or role ID.");
}
return exitResponse;
} catch (Exception err) {
err.printStackTrace();
}
}
return exitResponse;
}
private static String revokePrivilege(String privName, String roleName, String tableName) {
String exitResponse = "Authorization failure";
if (isAdmin()) {
try {
int privid = -1;
int roleid = -1;
String stmt = "SELECT privid FROM Privileges WHERE privname=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, privName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
privid = rs.getInt("privid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = "SELECT roleid FROM Roles WHERE rolename=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, roleName);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
roleid = rs.getInt("roleid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (privid > 0 && roleid > 0) {
stmt = "DELETE FROM RolesPrivileges WHERE roleid=? AND privid=? AND tablename=?";
PreparedStatement ps = con.prepareStatement(stmt);
ps.setInt(1, roleid);
ps.setInt(2, privid);
ps.setString(3, tableName);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "Privilege revoked successfully";
} else {
throw new Exception("Incorrect number of role privileges updated.");
}
} else {
throw new Exception("Failed to retrieve privilege or role ID.");
}
return exitResponse;
} catch (Exception err) {
err.printStackTrace();
}
}
return exitResponse;
}
private static String insert(String tableName, String valueList, int columnNo, String ownerRole) {
String exitResponse = "Authorization failure";
// https://regex101.com/r/C370lO/1
String valueStrings[] = valueList.substring(2, valueList.length() - 2).split("([\\(\\),\\']+\\s[\\(\\),\\']+)|([\\(\\),\\']+)");
try {
if (hasPermission(tableName, "INSERT")) {
// We need the roleId regardless.
String encryptionKey = "";
int roleId = -1;
String stmt = "SELECT encryptionKey, roleid FROM Roles WHERE rolename=?";
try {
PreparedStatement ps = con.prepareStatement(stmt);
ps.setString(1, ownerRole);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
encryptionKey = rs.getString("encryptionKey");
roleId = rs.getInt("roleid");
}
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (columnNo > 0) {
valueStrings[columnNo - 1] = autokeyEncrypt(valueStrings[columnNo - 1], encryptionKey);
}
// Not as safe, but we will use it for now.
String sqlValues = "'" + String.join("', '", valueStrings) + "', '" + columnNo + "', '" + roleId + "'";
stmt = "INSERT INTO " + tableName + " VALUES(" + sqlValues + ")";
try {
PreparedStatement ps = con.prepareStatement(stmt);
//ps.setString(1, tableName);
int updates = ps.executeUpdate();
if (updates == 1) {
exitResponse = "Row inserted successfully";
} else {
throw new Exception("Incorrect number of rows updated.");
}
} catch (SQLException e) {
e.printStackTrace();
}
return exitResponse;
} else {
return exitResponse;
}
} catch (Exception e) {
e.printStackTrace();
return exitResponse;
}
}
private static String select(String criteria, String tableName) {
String exitResponse = "Authorization failure";
try {
if (hasPermission(tableName, "SELECT")) {
String stmt = "SELECT " + criteria + " FROM " + tableName;
try {
PreparedStatement ps = con.prepareStatement(stmt);
ResultSet rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int cols = rsmd.getColumnCount() - 1; // Truncate secret columns.
exitResponse = "";
for (int i = 1; i < cols; i++) {
exitResponse += rsmd.getColumnLabel(i);
if (i != cols - 1) {
exitResponse += ", ";
}
}
exitResponse += "\n";
while (rs.next()) {
int encryptedColumn = rs.getInt("encryptedColumn");
int ownerRole = rs.getInt("ownerRole");
String encrpytionKey = null;
stmt = "SELECT encryptionKey FROM (SELECT roleid FROM UsersRoles WHERE userid=? AND roleid=?) U, Roles R WHERE R.roleid=U.roleid";
try {
PreparedStatement psRole = con.prepareStatement(stmt);
psRole.setInt(1, loggedInUserId);
psRole.setInt(2, ownerRole);
ResultSet rsRole = psRole.executeQuery();
while (rsRole.next()) {
encrpytionKey = rsRole.getString("encryptionKey");
}
rsRole.close();
psRole.close();
} catch (SQLException e) {
e.printStackTrace();
}
for (int i = 1; i < cols; i++) {
String colValue = rs.getString(i);
if (i == encryptedColumn && encrpytionKey != null) {
colValue = autokeyDecrypt(colValue, encrpytionKey);
}
exitResponse += colValue;
if (i != cols - 1) {
exitResponse += ", ";
}
}
exitResponse += "\n";
}
exitResponse = exitResponse.substring(0, exitResponse.length() - 1); // Cut off the last \n.
rs.close();
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
return exitResponse;
} else {
return exitResponse;
}
} catch (Exception e) {
e.printStackTrace();
return exitResponse;
}
}
private static String quit() {
out.close();
System.exit(0);
return "";
}
}