Implement full handshake and login over DMAP2.0
This commit is contained in:
parent
e311064c48
commit
a9eab7cfb9
@ -77,7 +77,9 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
String input = null;
|
String input = null;
|
||||||
String message = null;
|
String message = null;
|
||||||
|
|
||||||
if (!(input = this.dmapIn.readLine()).startsWith("ok DMAP2.0"))
|
input = dmapIn.readLine();
|
||||||
|
logger.info("Received message from server: " + input);
|
||||||
|
if (!input.startsWith("ok DMAP2.0"))
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
||||||
startSecure();
|
startSecure();
|
||||||
@ -110,7 +112,9 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
String componentId;
|
String componentId;
|
||||||
PublicKey serverPublicKey;
|
PublicKey serverPublicKey;
|
||||||
this.dmapOut.println("startsecure");
|
this.dmapOut.println("startsecure");
|
||||||
|
logger.info("Sent command 'startsecure'");
|
||||||
input = this.dmapIn.readLine();
|
input = this.dmapIn.readLine();
|
||||||
|
logger.info("Server's response: " + input);
|
||||||
if (input.startsWith("ok") && (input.split("\\s+").length == 2)) {
|
if (input.startsWith("ok") && (input.split("\\s+").length == 2)) {
|
||||||
// Get the component-id from the server
|
// Get the component-id from the server
|
||||||
componentId = input.split("\\s+")[1];
|
componentId = input.split("\\s+")[1];
|
||||||
@ -127,12 +131,14 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
logger.info("Server's Public Key: " + serverPublicKey);
|
logger.info("Server's Public Key: " + serverPublicKey);
|
||||||
String clientChallenge = generateChallengeMessage(serverPublicKey);
|
String clientChallenge = generateChallengeMessage(serverPublicKey);
|
||||||
// Send clientChallenge to server
|
// Send clientChallenge to server
|
||||||
|
logger.info("Send clientchallenge to Server: " + clientChallenge);
|
||||||
this.dmapOut.println(clientChallenge);
|
this.dmapOut.println(clientChallenge);
|
||||||
// Receive AES encrypted message saying "ok <client-challenge>"
|
// Receive AES encrypted message saying "ok <client-challenge>"
|
||||||
String response = this.dmapIn.readLine();
|
String response = this.dmapIn.readLine();
|
||||||
// Compare received client challenge with generated client challenge
|
// Compare received client challenge with generated client challenge
|
||||||
verifyChallenge(response);
|
verifyChallenge(response);
|
||||||
// Answer with AES encrypted "ok" if matching and use AES cipher for subsequent communication
|
// Answer with AES encrypted "ok" if matching and use AES cipher for subsequent communication
|
||||||
|
logger.info("Send ciphered 'ok' to Server: " + getAesCiphertext("ok"));
|
||||||
this.dmapOut.println(getAesCiphertext("ok"));
|
this.dmapOut.println(getAesCiphertext("ok"));
|
||||||
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | FailedVerificationException e) {
|
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | FailedVerificationException e) {
|
||||||
logger.severe(e.getMessage());
|
logger.severe(e.getMessage());
|
||||||
@ -146,6 +152,7 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a plaintext message, encrypts and encodes it and returns the encoded ciphertext ready for sending.
|
* Takes a plaintext message, encrypts and encodes it and returns the encoded ciphertext ready for sending.
|
||||||
|
*
|
||||||
* @param message Plaintext message
|
* @param message Plaintext message
|
||||||
* @return B64 encoded and AES encrypted ciphertext
|
* @return B64 encoded and AES encrypted ciphertext
|
||||||
*/
|
*/
|
||||||
@ -156,6 +163,7 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes an AES encrypted message, decrypts and decodes it and returns the plaintext.
|
* Takes an AES encrypted message, decrypts and decodes it and returns the plaintext.
|
||||||
|
*
|
||||||
* @param message B64 encoded and AES encrypted message
|
* @param message B64 encoded and AES encrypted message
|
||||||
* @return B64 decoded and AES decrypted plaintext
|
* @return B64 decoded and AES decrypted plaintext
|
||||||
*/
|
*/
|
||||||
@ -178,11 +186,12 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
// Decode <client-challenge>
|
// Decode <client-challenge>
|
||||||
if (plainText.split("\\s+").length != 2)
|
if (plainText.split("\\s+").length != 2)
|
||||||
shutdown();
|
shutdown();
|
||||||
String clientChallenge = new String(Base64.getDecoder().decode(plainText.split("\\s+")[1]));
|
byte[] clientChallenge = Base64.getDecoder().decode(plainText.split("\\s+")[1]);
|
||||||
// Compare received challenge with sent
|
// Compare received challenge with sent
|
||||||
|
|
||||||
if (!clientChallenge.equals(new String(this.challenge)))
|
if (!Arrays.equals(clientChallenge, this.challenge))
|
||||||
throw new FailedVerificationException("Server's clientChallenge " + clientChallenge + " does not match sent clientChallenge " + new String(this.challenge));
|
throw new FailedVerificationException("Server's clientChallenge " + new String(clientChallenge) +
|
||||||
|
" does not match sent clientChallenge " + new String(this.challenge));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecretKeySpec generateSecretKey() {
|
private SecretKeySpec generateSecretKey() {
|
||||||
@ -205,7 +214,7 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
return new IvParameterSpec(iv);
|
return new IvParameterSpec(iv);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAesCipher(SecretKeySpec secretKey, IvParameterSpec iv) {
|
private void setAesCiphers(SecretKeySpec secretKey, IvParameterSpec iv) {
|
||||||
try {
|
try {
|
||||||
this.aesEncryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
this.aesEncryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
this.aesDecryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
this.aesDecryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
@ -240,13 +249,13 @@ public class MessageClient implements IMessageClient, Runnable {
|
|||||||
assert secretKeySpec != null;
|
assert secretKeySpec != null;
|
||||||
IvParameterSpec iv = generateIv();
|
IvParameterSpec iv = generateIv();
|
||||||
// Save AES cipher for subsequent communication
|
// Save AES cipher for subsequent communication
|
||||||
setAesCipher(secretKeySpec, iv);
|
setAesCiphers(secretKeySpec, iv);
|
||||||
// Encode parameters to base64
|
// Encode parameters to base64
|
||||||
String clearTextChallengeEncoded = Base64.getEncoder().encodeToString(clearTextChallenge);
|
String clearTextChallengeEncoded = Base64.getEncoder().encodeToString(clearTextChallenge);
|
||||||
String secretKeyEncoded = Base64.getEncoder().encodeToString(secretKeySpec.getEncoded());
|
String secretKeyEncoded = Base64.getEncoder().encodeToString(secretKeySpec.getEncoded());
|
||||||
String ivEncoded = Base64.getEncoder().encodeToString(iv.getIV());
|
String ivEncoded = Base64.getEncoder().encodeToString(iv.getIV());
|
||||||
// Concatenate command and parameters (challenge, secretKey and IV)
|
// Concatenate command and parameters (challenge, secretKey and IV)
|
||||||
String concatenated = "ok" + clearTextChallengeEncoded + secretKeyEncoded + ivEncoded;
|
String concatenated = "ok " + clearTextChallengeEncoded + " " + secretKeyEncoded + " " + ivEncoded;
|
||||||
// Encrypt "<base64Encoded>"
|
// Encrypt "<base64Encoded>"
|
||||||
Cipher cipher;
|
Cipher cipher;
|
||||||
byte[] cipherTextChallenge;
|
byte[] cipherTextChallenge;
|
||||||
|
|||||||
@ -4,15 +4,33 @@ import dslab.Email;
|
|||||||
import dslab.Message;
|
import dslab.Message;
|
||||||
import dslab.exception.MessageNotFoundException;
|
import dslab.exception.MessageNotFoundException;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.IvParameterSpec;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.security.*;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Base64;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class DMAPConnection implements Runnable {
|
public class DMAPConnection implements Runnable {
|
||||||
Logger logger = Logger.getLogger(DMAPConnection.class.getName());
|
Logger logger = Logger.getLogger(DMAPConnection.class.getName());
|
||||||
|
private final String componentId;
|
||||||
private final Socket socket;
|
private final Socket socket;
|
||||||
private PrintWriter out;
|
private PrintWriter out;
|
||||||
private BufferedReader in;
|
private BufferedReader in;
|
||||||
@ -20,10 +38,15 @@ public class DMAPConnection implements Runnable {
|
|||||||
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
|
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
|
||||||
private final ConcurrentHashMap<String, String> userStorage;
|
private final ConcurrentHashMap<String, String> userStorage;
|
||||||
|
|
||||||
public DMAPConnection(Socket connection, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage) {
|
private Cipher aesEncryptCipher;
|
||||||
|
private Cipher aesDecryptCipher;
|
||||||
|
|
||||||
|
public DMAPConnection(Socket connection, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage, String componentId) {
|
||||||
|
this.componentId = componentId;
|
||||||
this.socket = connection;
|
this.socket = connection;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.userStorage = userStorage;
|
this.userStorage = userStorage;
|
||||||
|
logger.setLevel(Level.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -32,8 +55,9 @@ public class DMAPConnection implements Runnable {
|
|||||||
try {
|
try {
|
||||||
this.out = new PrintWriter(socket.getOutputStream(), true);
|
this.out = new PrintWriter(socket.getOutputStream(), true);
|
||||||
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
out.println("ok DMAP");
|
out.println("ok DMAP2.0");
|
||||||
loginLoop();
|
startSecure();
|
||||||
|
login();
|
||||||
|
|
||||||
String userInput;
|
String userInput;
|
||||||
while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) {
|
while (!Thread.currentThread().isInterrupted() && (userInput = in.readLine()) != null) {
|
||||||
@ -42,8 +66,7 @@ public class DMAPConnection implements Runnable {
|
|||||||
shutdown();
|
shutdown();
|
||||||
} else if ("logout".equals(userInput)) {
|
} else if ("logout".equals(userInput)) {
|
||||||
out.println("ok");
|
out.println("ok");
|
||||||
currentUser = null;
|
shutdown();
|
||||||
loginLoop();
|
|
||||||
} else if ("list".equals(userInput)) {
|
} else if ("list".equals(userInput)) {
|
||||||
listMessages();
|
listMessages();
|
||||||
} else if ("delete".equals(userInput.split("\\s+")[0])) {
|
} else if ("delete".equals(userInput.split("\\s+")[0])) {
|
||||||
@ -81,14 +104,135 @@ public class DMAPConnection implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginLoop() {
|
/**
|
||||||
|
* Handles the startsecure command issued by the MessageClient.
|
||||||
|
*/
|
||||||
|
private void startSecure() {
|
||||||
|
String userInput;
|
||||||
|
|
||||||
|
try {
|
||||||
|
userInput = in.readLine(); // Should always be "startsecure"
|
||||||
|
// Send componentId
|
||||||
|
out.println("ok " + componentId);
|
||||||
|
// Receive client challenge, secret key and iv
|
||||||
|
userInput = in.readLine();
|
||||||
|
logger.info("Received clientchallenge from Client: " + userInput);
|
||||||
|
String[] rsaPlaintext = getRsaPlaintext(userInput).split("\\s+");
|
||||||
|
logger.info("Plaintext of clientchallenge: " + Arrays.toString(rsaPlaintext));
|
||||||
|
// Initialize AES cipher(s) (encryption and decryption)
|
||||||
|
setAesCiphers(rsaPlaintext[2], rsaPlaintext[3]);
|
||||||
|
// Encrypt client challenge with AES and send to MessageClient
|
||||||
|
out.println(encryptClientChallenge(rsaPlaintext[1]));
|
||||||
|
// Decrypt AES encrypted "ok" from MessageClient
|
||||||
|
userInput = getAesPlaintext(in.readLine());
|
||||||
|
if (!userInput.equals("ok")) {
|
||||||
|
logger.severe("Received " + userInput + "from MessageClient. Did not match 'ok'");
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
} catch (InterruptedIOException ioe) {
|
||||||
|
logger.info("Received interrupt from parent. Shutting down...");
|
||||||
|
shutdown();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
logger.finer("Received interrupt. Exiting " + this.toString());
|
||||||
|
shutdown();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.severe("Failed to get IO-Stream");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
|
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | BadPaddingException |
|
||||||
|
InvalidKeySpecException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
|
||||||
|
logger.severe("Error during encryption/decryption. Aborting...");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a plaintext message, encrypts and encodes it and returns the encoded ciphertext ready for sending.
|
||||||
|
*
|
||||||
|
* @param message Plaintext message
|
||||||
|
* @return B64 encoded and AES encrypted ciphertext
|
||||||
|
*/
|
||||||
|
private String getAesCiphertext(String message) throws IllegalBlockSizeException, BadPaddingException {
|
||||||
|
byte[] cipherText = aesEncryptCipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return Base64.getEncoder().encodeToString(cipherText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an AES encrypted message, decrypts and decodes it and returns the plaintext.
|
||||||
|
*
|
||||||
|
* @param message B64 encoded and AES encrypted message
|
||||||
|
* @return B64 decoded and AES decrypted plaintext
|
||||||
|
*/
|
||||||
|
private String getAesPlaintext(String message) throws BadPaddingException, IllegalBlockSizeException {
|
||||||
|
byte[] cipherText = Base64.getDecoder().decode(message.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return new String(aesDecryptCipher.doFinal(cipherText));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the client challenge with the AES cipher.
|
||||||
|
*
|
||||||
|
* @param clientChallenge Base64 encoded client challenge. Supplied by the MessageClient.
|
||||||
|
* @return Return the AES encrypted and encoded clientChallenge ready for sending.
|
||||||
|
*/
|
||||||
|
private String encryptClientChallenge(String clientChallenge) throws BadPaddingException, IllegalBlockSizeException {
|
||||||
|
String completeClientChallenge = "ok " + clientChallenge;
|
||||||
|
return Base64.getEncoder().encodeToString(aesEncryptCipher.doFinal(completeClientChallenge.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes an RSA encrypted message and constructs AES ciphers.
|
||||||
|
*
|
||||||
|
* @param message Has the form "ok <client-challenge> <secret-key> <iv>".
|
||||||
|
* @return Returns the decrypted and (partially) decoded challenge
|
||||||
|
*/
|
||||||
|
private String getRsaPlaintext(String message) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException,
|
||||||
|
NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
byte[] rsaEncrypted = Base64.getDecoder().decode(message);
|
||||||
|
byte[] keyBytes = Files.readAllBytes(Paths.get("keys", "server", componentId + ".der"));
|
||||||
|
logger.info("Read bytes from path " + Paths.get("keys", "server", componentId + ".der") + ": " + Arrays.toString(keyBytes));
|
||||||
|
// Create X509 spec object from key
|
||||||
|
// TODO Use readKey function provided by LVA-Team
|
||||||
|
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
|
||||||
|
// Create generator for RSA scheme
|
||||||
|
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||||
|
// Make generator generate private key from X509 spec
|
||||||
|
PrivateKey serverPrivateKey = kf.generatePrivate(spec);
|
||||||
|
Cipher cipher;
|
||||||
|
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, serverPrivateKey);
|
||||||
|
byte[] cipherTextChallenge = cipher.doFinal(rsaEncrypted);
|
||||||
|
return new String(cipherTextChallenge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets global AES ciphers for encryption and decryption.
|
||||||
|
*
|
||||||
|
* @param secretKey Base64 encoded secret key. Supplied by the MessageClient.
|
||||||
|
* @param iv Base64 encoded IV. Supplied by the MessageClient.
|
||||||
|
*/
|
||||||
|
private void setAesCiphers(String secretKey, String iv) throws InvalidAlgorithmParameterException,
|
||||||
|
InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException {
|
||||||
|
SecretKeySpec decodedSecretKey = new SecretKeySpec(Base64.getDecoder().decode(secretKey), "AES");
|
||||||
|
IvParameterSpec decodedIv = new IvParameterSpec(Base64.getDecoder().decode(iv));
|
||||||
|
this.aesEncryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
|
this.aesDecryptCipher = Cipher.getInstance("AES/CTR/NoPadding");
|
||||||
|
|
||||||
|
this.aesEncryptCipher.init(Cipher.ENCRYPT_MODE, decodedSecretKey, decodedIv);
|
||||||
|
this.aesDecryptCipher.init(Cipher.DECRYPT_MODE, decodedSecretKey, decodedIv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the login command issued by the MessageClient which is already encrypted.
|
||||||
|
*/
|
||||||
|
private void login() {
|
||||||
String userInput;
|
String userInput;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
userInput = in.readLine();
|
userInput = getAesPlaintext(in.readLine());
|
||||||
if ("quit".equals(userInput.split("\\s+")[0])) {
|
if ("quit".equals(userInput.split("\\s+")[0])) {
|
||||||
out.println("ok bye");
|
out.println(getAesCiphertext("ok bye"));
|
||||||
shutdown();
|
shutdown();
|
||||||
} else if ("login".equals(userInput.split("\\s+")[0])) {
|
} else if ("login".equals(userInput.split("\\s+")[0])) {
|
||||||
String[] args = userInput.split("\\s+");
|
String[] args = userInput.split("\\s+");
|
||||||
@ -103,7 +247,7 @@ public class DMAPConnection implements Runnable {
|
|||||||
// Set current user if login successful
|
// Set current user if login successful
|
||||||
currentUser = email;
|
currentUser = email;
|
||||||
logger.info("User successfully logged in: " + currentUser.toString());
|
logger.info("User successfully logged in: " + currentUser.toString());
|
||||||
out.println("ok");
|
out.println(getAesCiphertext("ok"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,6 +271,10 @@ public class DMAPConnection implements Runnable {
|
|||||||
logger.severe("Failed to get IO-Stream");
|
logger.severe("Failed to get IO-Stream");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
shutdown();
|
shutdown();
|
||||||
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
|
logger.severe("Error while encrypting/decrypting. Aborting...");
|
||||||
|
e.printStackTrace();
|
||||||
|
shutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +307,7 @@ public class DMAPConnection implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteMessage (String id) throws MessageNotFoundException {
|
public void deleteMessage(String id) throws MessageNotFoundException {
|
||||||
int i;
|
int i;
|
||||||
try {
|
try {
|
||||||
i = Integer.parseInt(id);
|
i = Integer.parseInt(id);
|
||||||
|
|||||||
@ -14,9 +14,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class DMAPListener extends Thread {
|
public class DMAPListener extends Thread {
|
||||||
|
private final String componentId;
|
||||||
private final ServerSocket serverSocket;
|
private final ServerSocket serverSocket;
|
||||||
private final Logger logger = Logger.getLogger(DMAPListener.class.getName());
|
private final Logger logger = Logger.getLogger(DMAPListener.class.getName());
|
||||||
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
|
private final ConcurrentHashMap<Email, LinkedList<Message>> storage;
|
||||||
@ -24,10 +26,12 @@ public class DMAPListener extends Thread {
|
|||||||
private final ArrayList<DMAPConnection> clients = new ArrayList<>();
|
private final ArrayList<DMAPConnection> clients = new ArrayList<>();
|
||||||
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
public DMAPListener(ServerSocket serverSocket, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage) {
|
public DMAPListener(ServerSocket serverSocket, ConcurrentHashMap<Email, LinkedList<Message>> storage, ConcurrentHashMap<String, String> userStorage, String componentId) {
|
||||||
|
this.componentId = componentId;
|
||||||
this.serverSocket = serverSocket;
|
this.serverSocket = serverSocket;
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
this.userStorage = userStorage;
|
this.userStorage = userStorage;
|
||||||
|
logger.setLevel(Level.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -37,7 +41,7 @@ public class DMAPListener extends Thread {
|
|||||||
try {
|
try {
|
||||||
Socket s = serverSocket.accept();
|
Socket s = serverSocket.accept();
|
||||||
logger.fine("Processing incoming socket " + s.toString());
|
logger.fine("Processing incoming socket " + s.toString());
|
||||||
DMAPConnection dmapConnection = new DMAPConnection(s, storage, userStorage);
|
DMAPConnection dmapConnection = new DMAPConnection(s, storage, userStorage, componentId);
|
||||||
clients.add(dmapConnection);
|
clients.add(dmapConnection);
|
||||||
executorService.submit(dmapConnection);
|
executorService.submit(dmapConnection);
|
||||||
} catch (InterruptedIOException | SocketException e) {
|
} catch (InterruptedIOException | SocketException e) {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import java.io.PrintStream;
|
|||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import at.ac.tuwien.dsg.orvell.Shell;
|
import at.ac.tuwien.dsg.orvell.Shell;
|
||||||
@ -18,6 +19,7 @@ import dslab.util.Config;
|
|||||||
|
|
||||||
public class MailboxServer implements IMailboxServer, Runnable {
|
public class MailboxServer implements IMailboxServer, Runnable {
|
||||||
private static final Logger logger = Logger.getLogger(MailboxServer.class.getName());
|
private static final Logger logger = Logger.getLogger(MailboxServer.class.getName());
|
||||||
|
private final String componentId;
|
||||||
private final String domain;
|
private final String domain;
|
||||||
private ServerSocket dmtpServerSocket;
|
private ServerSocket dmtpServerSocket;
|
||||||
private ServerSocket dmapServerSocket;
|
private ServerSocket dmapServerSocket;
|
||||||
@ -42,6 +44,7 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
*/
|
*/
|
||||||
public MailboxServer(String componentId, Config config, InputStream in, PrintStream out) {
|
public MailboxServer(String componentId, Config config, InputStream in, PrintStream out) {
|
||||||
this.domain = config.getString("domain");
|
this.domain = config.getString("domain");
|
||||||
|
this.componentId = componentId;
|
||||||
Config userConfig = new Config(config.getString("users.config"));
|
Config userConfig = new Config(config.getString("users.config"));
|
||||||
|
|
||||||
// Load users from config into userStorage for authentication
|
// Load users from config into userStorage for authentication
|
||||||
@ -61,6 +64,7 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
this.shell.setPrompt("Mailboxserver> ");
|
this.shell.setPrompt("Mailboxserver> ");
|
||||||
this.dmtpServerPort = config.getInt("dmtp.tcp.port");
|
this.dmtpServerPort = config.getInt("dmtp.tcp.port");
|
||||||
this.dmapServerPort = config.getInt("dmap.tcp.port");
|
this.dmapServerPort = config.getInt("dmap.tcp.port");
|
||||||
|
logger.setLevel(Level.ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -76,7 +80,7 @@ public class MailboxServer implements IMailboxServer, Runnable {
|
|||||||
}
|
}
|
||||||
this.dmtpListener = new DMTPListener(this.dmtpServerSocket, this.messageStorage, this.userStorage, this.domain);
|
this.dmtpListener = new DMTPListener(this.dmtpServerSocket, this.messageStorage, this.userStorage, this.domain);
|
||||||
this.dmtpListener.start();
|
this.dmtpListener.start();
|
||||||
this.dmapListener = new DMAPListener(this.dmapServerSocket, this.messageStorage, this.userStorage);
|
this.dmapListener = new DMAPListener(this.dmapServerSocket, this.messageStorage, this.userStorage, this.componentId);
|
||||||
this.dmapListener.start();
|
this.dmapListener.start();
|
||||||
this.shell.run();
|
this.shell.run();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user