Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Secure Email Server ECE 3553 – Final Project By: Chi-Ti Shih Dulanjan Katuwawela Fu-Sheng Hung Hadi Garib Omer Idrees Due Date: 10th December 2004 -1- Project Plan 1. Introduction 1.1. Project Overview While keeping in mind the vast avenues available for secure login applications, this group has proceeded to develop a secure email server, with basic intents of client side applications as well, within the confines of java scripting. Despite numerous constraints, mentioned during the course of this documentation, the task at hand was executed with 3 basic milestones in mind. These were: 1.1.1. Complete project plan, design & analysis document. 1.1.2. Transform plan from paper to software, by designing the system planned 1.1.3. Software testing, ensuring a well-tested final product. As per any major project, a basic structure was established in order to determine individual tasks. This group saw the following number assignments per task: Server Side Development – 2 Client Side Development – 2 Secure interfacing – 1 However, owing to the time constraints that exist within the scope of this project, all 5 members of this team would interact with each other, providing as much viable input as needed towards the overall accomplishment of this project. The generalized folder path definition can be translated via Figure 1.1: Succinctly, despite the man-power constraints faced by this team, a successful attempt at a secure email application has been procured by SES. However, owing to the aforementioned limitations, it is noted that at this point of time the only viable constraint for this particular application is the fact that both the server and client are assumed to be on the same system. As per the fields utilized on the server-side, this email server has its limitations. Tersely, a long term solution for this erroneous field data would be entering error checking for the defined boundaries within the server side – however, to make this project as feasible as possible, it is assumed that errorchecking constitutes a vital component of the client-side operations. -2- Design (Interface) Planning and Management Estimation Basic Coding Quality Assurance Final Review Submit Final Version of the Program Testing Figure 1.1: Project Activities The major limitations faced by Team SES can be surmised as follows: Assumptions, Dependencies, and Constraints The most important constraint is that the client and the server will be running on the same machine. In-depth testing would be required in order to validate the integration of all functions, as per server and client applications. As per any query-generated updates, they would depend on time-feasibility. Risk Management The biggest risks for the project are schedule and personnel. Based on the size and complexity of the product, the project is on a tight schedule with insufficient personnel. To manage these risks, team members will be playing multiple roles. -3- 2. Project Organizations 2.1. Process Model Prior to initiating software development, SES made a secure assumption that the targeted software was a client-demand, and therefore, any definitions required, were provided prior to development, by the client himself. Owing to constraints defined during the course of this document, a model best suited for the development of a project of this scale was sought for – in this scenario, the waterfall model of software development was deemed best-fit. The advantage of the staged delivery model lies in the fact that throughout the course of the development, a step-by-step working towards the final goal is ever-present in front of the designers. This allows a clear understanding, thus augmenting query-based-solutions at a faster rate. Delivery Testing Develop Design Planning Fig 1.2: Waterfall Development Model -4- Bug Testing Bug Reporting Error patching Fig 1.3: Testing Method -5- Case Diagrams Fig 1.4: Login Case Diagram -6- Fig 1.5: Add User Case Diagram -7- Fig 1.6: Delete User Case Diagram -8- Fig 1.7: Read Email Case Diagram -9- Fig 1.8: Delete Case Diagram - 10 - Fig 1.9: Send Email Case Diagram - 11 - Fig 1.10: Show User Case Diagram - 12 - Fig 1.11: Get Inbox Case Diagram - 13 - Fig 1.12: Logout Case Diagram - 14 - Process Diagram Validate login information [else] [success] Show inbox Show email Delete email [else] logout Compose Show error send [success] Delete email Reply email Show conformation Show error [else] [success] show reply form Show conformation Fig 1.13: Process Diagram - 15 - The Solution: Analyzed While the client side provides the aesthetic value of the solution at hand, the main function handling is process via the server side. Thus, SES has taken particular interest as far as analyzing the server side is concerned. In order that the GUI, output thread, and input thread all run simultaneously, it is essential that the server constitutes of three varying classes. These have been singled out and explained in depth through the course of this document. A general overview of these individual classes is as follows: Server.java handles the GUI construction; in order to provide a greater aesthetic value to the feature, the swing class has been utilized. All text as such is displayed in JTextArea’s with the manual response field being formed by the JTextField. In order to ensure continuous monitoring of activities being requested by the Client, a traffic monitor has been designed – thus keeping track of network activity, and hence providing the administrator with an in depth activity report. Once the GUI is constructed, Server.java calls ServerListener.java and SendandRecieve.java in order to pursue execution of user commands. ServerListener.java is responsible for creating the ServerSocket. The Java ServerSocket class allows us to write the servers in Java. Each ServerSocket listens on a particular port on the local host. The ServerSocket is hard coded to run on port 2003 and allow up to 50 clients to establish a connection. The ServerSocket listens for incoming connections and attempts a connection on that port using the accept() method. Accept () waits for a client to establish a connection and returns a Socket object over which the client and server will communicate. Once the client accepts the connection a new SendandRecieve class is created to deal with all incoming and outgoing messages associated with that port. All communication is done plain text over a regular socket. If a client closes a connection, the ServerSocket returns to a dormant state and waits for the next client to establish a connection. SendandRecieve.java is responsible for the sending and receiving all text to and from the server. When text is sent or received, it is prefixed by a designated header. The incoming text is then routed to the appropriate function according to the header of the text stream. The followup standard email tasks as presented in Appendix III of this document (by means of screenshots), are carried out by this class. - 16 - Key Function Descriptions mandCom Function USER_CREATE NEW_MESSAGE LOGIN BOOK_ADDRESS_GET MESSAGES_ALL_DELETE USER_CLIENT_DELETE LIST_MESSAGES_REFRESH Creates a new user Creates a new message Validates username and password Returns address book Delete all saved messages Delete client record Refresh screen Table1.1: Client to Server Commands Command Name SUCCESSFUL_LOGIN_ADMIN SUCCESSFUL_LOGIN_CLIENT USER_UNKNOWN BOOK_ADDRESS REPLY_MESSAGE LIST_MESSAGE tionFunc Indicates admin priveleges Indicates normal priveleges Invalid login attempt Address book returned Respond to message Returns inbox Table1.2: Server to Client Commands - 17 - Appendix I: Code Listing (Client Side) /** * ECE 3553 Final Project * SES Team 2004 */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.net.*; import java.io.*; import java.util.*; public class Client extends JFrame implements ActionListener { String userType = ""; String host = "localhost"; int port = 2003; //from Mozella’s character set ConnectServer connection; CardLayout cardLayout1 = new CardLayout(); JPanel mainPanel = new JPanel(); JPanel jPanel1 = new JPanel(); JPanel jPanel2 = new JPanel(); JPanel jPanel3 = new JPanel(); JPanel jPanel4 = new JPanel(); JPanel jPanel5 = new JPanel(); JLabel jLabel1 = new JLabel(); JLabel jLabel2 = new JLabel(); JLabel jLabel3 = new JLabel(); JLabel jLabel4 = new JLabel(); JLabel jLabel5 = new JLabel(); JLabel jLabel6 = new JLabel(); JLabel jLabel7 = new JLabel(); JLabel jLabel8 = new JLabel(); JLabel jLabel9 = new JLabel(); JLabel jLabel10 = new JLabel(); JLabel jLabel11 = new JLabel(); - 18 - JLabel jLabel12 = new JLabel(); JLabel jLabel13 = new JLabel(); JLabel jLabel14 = new JLabel(); JLabel jLabel15 = new JLabel(); JLabel jLabel16 = new JLabel(); JLabel unknownUserLabel = new JLabel(); JButton jButton1 = new JButton(); JButton jButton2 = new JButton(); JButton jButton3 = new JButton(); JButton jButton4 = new JButton(); JButton jButton5 = new JButton(); JButton jButton6 = new JButton(); JButton jButton7 = new JButton(); JButton jButton8 = new JButton(); JButton jButton9 = new JButton(); JButton jButton10 = new JButton(); JButton jButton11 = new JButton(); JButton jButton12 = new JButton(); JButton jButton13 = new JButton(); JButton jButton14 = new JButton(); JButton jButton15 = new JButton(); JButton jButton16 = new JButton(); JButton jButton17 = new JButton(); JTextArea jTextArea1 = new JTextArea(); JTextArea jTextArea2 = new JTextArea(); JTextArea jTextArea3 = new JTextArea(); JComboBox jComboBox1 = new JComboBox(); JComboBox jComboBox2 = new JComboBox(); JComboBox jComboBox3 = new JComboBox(); JTextField jTextField1 = new JTextField(); JTextField jTextField2 = new JTextField(); JTextField jTextField3 = new JTextField(); JTextField jTextField4 = new JTextField(); JScrollPane jScrollPane1 = new JScrollPane(); JPasswordField jPasswordField1 = new JPasswordField(); public Client() { //start connection - 19 - connection = new ConnectServer(this); connection.start(); //build GUI buildGUI(); } public static void main(String[] args) { Client client = new Client(); client.setVisible(true); } public void actionPerformed(ActionEvent e) { Object s = e.getSource(); //check if the triggered action is a button if (s instanceof JButton) { // Login: send the username and password to the server for verification if (s == jButton1) { connection.sendLogin(); String userName = new String(jTextField1.getText()); jTextField2.setText(userName); //set the TO: field jTextField2.setEditable(false); } // createmail button, show create mail panel if (s == jButton2) { cardLayout1.show(mainPanel, "createMail"); } // sendmail button if (s == jButton3) { if (userType.equalsIgnoreCase("client") && !jComboBox2.getSelectedItem().toString().equalsIgnoreCase( "Address_Book") || userType.equalsIgnoreCase("admin") && !jComboBox2.getSelectedItem().toString().equalsIgnoreCase( "Address_Book")) { connection.sendMessage(); jTextField3.setText(""); jTextArea2.setText(""); if (userType.equalsIgnoreCase("client")) { cardLayout1.show(mainPanel, "mailCenter"); } - 20 - else if (userType.equalsIgnoreCase("admin")) { cardLayout1.show(mainPanel, "superMailCenter"); } } } // show the appropriate super or client mail center if (s == jButton4) { if (userType.equalsIgnoreCase("client")) { cardLayout1.show(mainPanel, "mailCenter"); } else if (userType.equalsIgnoreCase("admin")) { cardLayout1.show(mainPanel, "superMailCenter"); } } // client get the selected mail if (s == jButton5) { if (!jComboBox1.getSelectedItem().toString().equalsIgnoreCase( "Select Message")) { connection.getClientMail(); } } // exit if (s == jButton6) { System.exit(0); } // show client/super create mail panel if (s == jButton7) { cardLayout1.show(mainPanel, "createMail"); } // super get the selected mail if (s == jButton8) { if (!jComboBox3.getSelectedItem().toString().equalsIgnoreCase( "Select Message")) { connection.getSuperMail(); } } // exit - 21 - if (s == jButton9) { System.exit(0); } // super show create user panel if (s == jButton10) { cardLayout1.show(mainPanel, "superCreateUser"); } // super create user if (s == jButton11) { if (jTextField4.getText().length() > 0) { connection.createUser(); connection.refreshAddressBook(); jTextField4.setText(""); cardLayout1.show(mainPanel, "superMailCenter"); } } // super mailCenter if (s == jButton12) { cardLayout1.show(mainPanel, "superMailCenter"); } // super remove user if (s == jButton13) { connection.deleteUser(); jTextField4.setText(""); cardLayout1.show(mainPanel, "superMailCenter"); } // client remove messages if (s == jButton14) { connection.deleteMesages(); jComboBox1.removeAllItems(); jComboBox1.addItem("No Messages"); } // super remove messages if (s == jButton15) { connection.deleteMesages(); jComboBox3.removeAllItems(); jComboBox3.addItem("No Messages"); - 22 - } // send/receive messages client if (s == jButton16) { connection.sendAndReceive(); } // send/recieve messages super if (s == jButton17) { connection.sendAndReceive(); } } } private void buildGUI() { setSize(550, 600); // panel 1 login panel //************************************************************************** jPanel1.setLayout(null); jPanel1.setSize(550, 600); jPanel1.setBackground(Color.black); jPasswordField1.setBounds(new Rectangle(218, 253, 111, 21)); jTextField1.setBounds(new Rectangle(218, 198, 111, 21)); jLabel1.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel1.setForeground(Color.green); jLabel1.setText("User Name"); jLabel1.setBounds(new Rectangle(218, 171, 111, 20)); jLabel2.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel2.setForeground(Color.green); jLabel2.setText("Password"); jLabel2.setBounds(new Rectangle(220, 231, 109, 15)); jLabel3.setFont(new java.awt.Font("Dialog", 0, 25)); jLabel3.setForeground(Color.green); jLabel3.setText("SES Login"); jLabel3.setBounds(new Rectangle(211, 116, 140, 39)); jLabel4.setFont(new java.awt.Font("Dialog", 0, 20)); jLabel4.setForeground(Color.green); jLabel4.setText("SES Mail Center"); jLabel4.setBounds(new Rectangle(199, 5, 211, 26)); - 23 - unknownUserLabel.setFont(new java.awt.Font("Dialog", 0, 25)); unknownUserLabel.setForeground(Color.red); unknownUserLabel.setBounds(new Rectangle(45, 348, 466, 30)); jButton1.setBounds(new Rectangle(218, 293, 73, 25)); jButton1.setText("Login"); jPanel1.add(jLabel3, null); jPanel1.add(jTextField1, null); jPanel1.add(jLabel2, null); jPanel1.add(jPasswordField1, null); jPanel1.add(jLabel1, null); jPanel1.add(jButton1, null); jPanel1.add(unknownUserLabel, null); // panel 2 Mail Center Panel //************************************************************************** jPanel2.setLayout(null); jPanel2.setSize(550, 600); jPanel2.setBackground(Color.black); jScrollPane1.setBounds(new Rectangle(10, 62, 525, 162)); jTextArea1.setText(""); jComboBox1.setBounds(new Rectangle(11, 262, 523, 21)); jLabel5.setForeground(Color.green); jLabel5.setText("Display Mail"); jLabel5.setBounds(new Rectangle(14, 46, 170, 15)); jLabel6.setForeground(Color.green); jLabel6.setText("Select Message to display"); jLabel6.setBounds(new Rectangle(11, 245, 209, 15)); jButton2.setBounds(new Rectangle(13, 308, 152, 25)); jButton2.setText("Compose Mail"); jButton14.setBounds(new Rectangle(14, 342, 151, 25)); jButton14.setText("Delete Messages"); jButton16.setBounds(new Rectangle(184, 342, 138, 25)); jButton16.setText("Refresh"); - 24 - jPanel2.add(jLabel4, null); jPanel2.add(jComboBox1, null); jPanel2.add(jLabel5, null); jPanel2.add(jLabel6, null); jPanel2.add(jScrollPane1, null); jPanel2.add(jButton2, null); jPanel2.add(jButton5, null); jPanel2.add(jButton6, null); jPanel2.add(jButton14, null); jPanel2.add(jButton16, null); jScrollPane1.getViewport().add(jTextArea1, null); // panel 3 is the send mail panel //************************************************************************** jPanel3.setLayout(null); jPanel3.setBackground(Color.black); jComboBox2.setBounds(new Rectangle(77, 60, 440, 21)); jLabel7.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel7.setForeground(Color.green); jLabel7.setText("To:"); jLabel7.setBounds(new Rectangle(34, 58, 35, 20)); jLabel8.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel8.setForeground(Color.green); jLabel8.setText("From:"); jLabel8.setBounds(new Rectangle(23, 104, 47, 22)); jLabel9.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel9.setForeground(Color.green); jLabel9.setText("Subject:"); jLabel9.setBounds(new Rectangle(6, 152, 64, 16)); jLabel10.setFont(new java.awt.Font("Dialog", 0, 15)); jLabel10.setForeground(Color.green); jLabel10.setText("Message"); jLabel10.setBounds(new Rectangle(79, 195, 83, 19)); jLabel11.setFont(new java.awt.Font("Dialog", 0, 20)); jLabel11.setForeground(Color.green); jLabel11.setText("Compose Mail"); jLabel11.setBounds(new Rectangle(205, 18, 186, 24)); - 25 - jButton3.setBounds(new Rectangle(403, 373, 115, 30)); jButton3.setText("Send Mail"); jTextField2.setBounds(new Rectangle(76, 103, 438, 24)); jTextField3.setBounds(new Rectangle(77, 148, 437, 23)); jTextArea2.setBounds(new Rectangle(80, 221, 438, 138)); jButton4.setBounds(new Rectangle(403, 416, 116, 31)); jButton4.setText("Mail Center"); jButton5.setBounds(new Rectangle(184, 309, 138, 25)); jButton5.setText("Display Mail"); jButton6.setBounds(new Rectangle(341, 309, 98, 25)); jButton6.setText("Exit"); jPanel3.add(jButton3, null); jPanel3.add(jTextArea2, null); jPanel3.add(jLabel10, null); jPanel3.add(jTextField3, null); jPanel3.add(jTextField2, null); jPanel3.add(jComboBox2, null); jPanel3.add(jLabel9, null); jPanel3.add(jLabel8, null); jPanel3.add(jLabel7, null); jPanel3.add(jLabel11, null); jPanel3.add(jButton4, null); // jpanel4 superMailCenter //************************************************************************** jPanel4.setLayout(null); jTextArea3.setText(""); jTextArea3.setBounds(new Rectangle(15, 64, 521, 158)); jLabel12.setBounds(new Rectangle(16, 48, 170, 15)); jLabel12.setText("Display Mail"); jLabel12.setForeground(Color.green); jLabel13.setBounds(new Rectangle(191, 14, 211, 26)); jLabel13.setText("SES Mail Center"); jLabel13.setForeground(Color.green); jLabel13.setFont(new java.awt.Font("Dialog", 0, 20)); jComboBox3.setBounds(new Rectangle(16, 270, 523, 21)); jLabel14.setBounds(new Rectangle(17, 257, 209, 15)); jLabel14.setText("Select Message to display"); jLabel14.setForeground(Color.green); - 26 - jButton7.setText("Compose Mail"); jButton7.setBounds(new Rectangle(17, 305, 138, 25)); jButton8.setText("Display Mail"); jButton8.setBounds(new Rectangle(164, 305, 117, 25)); jButton9.setText("Exit"); jButton9.setBounds(new Rectangle(433, 305, 98, 25)); jButton10.setBounds(new Rectangle(290, 305, 135, 25)); jButton10.setText("Create/Remove User"); jButton15.setBounds(new Rectangle(17, 341, 139, 25)); jButton15.setText("Delete Messages"); jButton17.setBounds(new Rectangle(164, 340, 115, 25)); jButton17.setText("Refresh"); jLabel15.setFont(new java.awt.Font("Dialog", 0, 20)); jLabel15.setForeground(Color.green); jLabel15.setText("Create User"); jLabel15.setBounds(new Rectangle(221, 5, 107, 26)); jPanel4.setSize(550, 600); jPanel4.setBackground(Color.black); jPanel4.add(jTextArea3, null); jPanel4.add(jLabel12, null); jPanel4.add(jLabel13, null); jPanel4.add(jComboBox3, null); jPanel4.add(jLabel14, null); jPanel4.add(jButton7, null); jPanel4.add(jButton10, null); jPanel4.add(jButton8, null); jPanel4.add(jButton9, null); jPanel4.add(jButton15, null); jPanel4.add(jButton17, null); // jpanel4 createUser //************************************************************************** jTextField4.setText(""); jTextField4.setBounds(new Rectangle(19, 94, 521, 21)); jLabel16.setForeground(Color.green); jLabel16.setText("User Name"); jLabel16.setBounds(new Rectangle(20, 78, 209, 15)); jButton11.setBounds(new Rectangle(19, 127, 147, 30)); jButton11.setText("Add User"); jButton12.setText("Mail Center"); jButton12.setBounds(new Rectangle(346, 126, 116, 31)); jButton13.setBounds(new Rectangle(175, 126, 157, 31)); - 27 - jButton13.setText("Remove User"); jPanel5.setLayout(null); jPanel5.setSize(550, 600); jPanel5.setBackground(Color.black); jPanel5.add(jLabel15, null); jPanel5.add(jTextField4, null); jPanel5.add(jLabel16, null); jPanel5.add(jButton11, null); jPanel5.add(jButton12, null); jPanel5.add(jButton13, null); // add action listeners to buttons //************************************************************************** jButton1.addActionListener(this); jButton2.addActionListener(this); jButton3.addActionListener(this); jButton4.addActionListener(this); jButton5.addActionListener(this); jButton6.addActionListener(this); jButton7.addActionListener(this); jButton8.addActionListener(this); jButton9.addActionListener(this); jButton10.addActionListener(this); jButton11.addActionListener(this); jButton12.addActionListener(this); jButton13.addActionListener(this); jButton14.addActionListener(this); jButton15.addActionListener(this); jButton16.addActionListener(this); jButton17.addActionListener(this); mainPanel.setSize(550, 600); mainPanel.setLayout(cardLayout1); mainPanel.add(jPanel1, "login"); // on init show the login panel cardLayout1.show(mainPanel, "login"); // add mainPanel to the contentPane this.getContentPane().setLayout(new BorderLayout()); this.getContentPane().add(mainPanel, BorderLayout.CENTER); } - 28 - // load the messages into jComboBox1 and jComboBox2 public void loadMessages(String s) { Vector v = new Vector(); String parseMe = s.substring(s.indexOf("MESSAGE_LIST") + 12); StringTokenizer st = new StringTokenizer(parseMe, "@@@@"); v.add("Select Message"); while (st.hasMoreTokens()) { v.add(st.nextToken()); } jComboBox1.removeAllItems(); jComboBox3.removeAllItems(); for (int i = 0; i < v.size(); i++) { jComboBox1.addItem(v.elementAt(i)); jComboBox3.addItem(v.elementAt(i)); } } // load the users addresses book in jComboBox2 public void loadAddress(String s) { Vector v = new Vector(); StringTokenizer st = new StringTokenizer(s); String command = st.nextToken(); while (st.hasMoreTokens()) { v.add(st.nextToken()); } jComboBox2.removeAllItems(); for (int i = 0; i < v.size(); i++) { jComboBox2.addItem(v.elementAt(i)); } } } /* ConnectServer Class * establishes a connection with the server and continuously * waits for input on a separate thread ***********************************************************************/ class ConnectServer extends Thread { //source keeps a handle on the GUI so you can get and display text Client source; String host = "localhost"; - 29 - int port = 2003; // main socket used to get input and output streams, which each run // on separate threads Socket connection; DataInputStream inDataStream; ReplyServer rs; String message; // constructor with handle to the gui ConnectServer(Client c) { source = (Client) c; } public void run() { host = source.host; port = source.port; try { connection = new Socket(host, port); inDataStream = new DataInputStream(connection.getInputStream()); // infinite loop that continually reads data from the dataInputStream while (true) { // create new threaded class for writing to the outputstream rs = new ReplyServer(connection, source); // start the thread run rs.start(); // read the input into string message message = inDataStream.readUTF(); // checks whether the server granted client permission if (message.toString().indexOf("CLIENT_LOGIN_SUCCESSFUL") >= 0) { source.userType = "client"; source.mainPanel.add(source.jPanel2, "mailCenter"); source.mainPanel.add(source.jPanel3, "createMail"); source.cardLayout1.show(source.mainPanel, "mailCenter"); } // checks whether the server granted admin permission else if (message.toString().indexOf("ADMIN_LOGIN_SUCCESSFUL") >= 0) { source.userType = "admin"; source.mainPanel.add(source.jPanel3, "createMail"); - 30 - source.mainPanel.add(source.jPanel4, "superMailCenter"); source.mainPanel.add(source.jPanel5, "superCreateUser"); source.cardLayout1.show(source.mainPanel, "superMailCenter"); } // if the user is unknow display login message else if (message.toString().indexOf("UNKNOWN_USER") >= 0) { source.unknownUserLabel.setText("Unknown Username or Password"); } // load the users address book else if (message.toString().indexOf("ADDRESS_BOOK") >= 0) { source.loadAddress(message); } // load the users message list else if (message.toString().indexOf("MESSAGE_LIST") >= 0) { source.loadMessages(message); } // display the requested message else if (message.toString().indexOf("MESSAGE_REPLY") >= 0) { displayMessageInTextArea(message.substring(message.indexOf("||"))); } } } catch (Exception e) { System.out.println( "YOU MUST FIRST RUN THE SERVER BEFORE ADDING A CLIENT\n" + "PLEASE RESTART THE SERVER AND PRESS RUN BUTTON BEFORE\n" + "RUNNING THIS APPLICATION"); System.exit(0); } } // display the selected message in the Text area public void displayMessageInTextArea(String s) { String displayString = ""; StringTokenizer st = new StringTokenizer(s, "||"); if (st.countTokens() >= 3) { displayString += "From: " + st.nextToken() + "\n"; displayString += "Subject: " + st.nextToken() + "\n"; displayString += "Message: " + st.nextToken() + "\n"; - 31 - } source.jTextArea1.setText(displayString); source.jTextArea3.setText(displayString); } // accessor functions to Reply Server class public void sendLogin() { rs.sendLogin(); } public void refreshAddressBook() { rs.refreshAddressBook(); } public void getClientMail() { rs.getClientMail(); } public void getSuperMail() { rs.getSuperMail(); } public void createUser() { rs.createUser(); } public void sendMessage() { rs.sendMessage(); } public void deleteMesages() { rs.deleteMessages(); } public void deleteUser() { rs.deleteUser(); } public void sendAndReceive() { rs.sendAndReceive(); } } - 32 - class ReplyServer extends Thread { DataOutputStream outDataStream; // handle to the GUI Client source; // same socket created in ConnectServer Socket connection; // constructor accepts socket and a handle to the GUI ReplyServer(Socket connection, Client source) { this.connection = connection; this.source = source; } public void run() { try { outDataStream = new DataOutputStream(connection.getOutputStream()); } catch (Exception e) { System.out.println("Could not create outputstream"); } } // retreive the login information and send it to the server public void sendLogin() { try { String userName = new String(source.jTextField1.getText()); String password = new String(source.jPasswordField1.getPassword()); if (userName.length() > 0 && password.length() > 0) { String logMe = "LOGIN||" + userName + "||" + password; // send message outDataStream.writeUTF(logMe); } } catch (Exception e) { System.out.println("LOGIN FAILED"); } } // refresh the address book if a user is added or deleted public void refreshAddressBook() { try { - 33 - // send message outDataStream.writeUTF("GET_ADDRESS_BOOK"); } catch (Exception e) { System.out.println("REFRESHING ADDRESS BOOK FAILED"); } } // request the selected mail from the server public void getClientMail() { try { String messageDesc = new String(source.jComboBox1.getSelectedItem(). toString()); String getMe = "GET_MESSAGE||" + messageDesc; //send message outDataStream.writeUTF(getMe); } catch (Exception e) { System.out.println("GET MAIL FAILED"); } } // request the selected mail from the server public void getSuperMail() { try { String messageDesc = new String(source.jComboBox3.getSelectedItem(). toString()); String getMe = "GET_MESSAGE||" + messageDesc; //send message outDataStream.writeUTF(getMe); } catch (Exception e) { System.out.println("GET MAIL FAILED"); } } // super create user public void createUser() { try { String userName = new String(source.jTextField4.getText()); if (userName.length() > 0) { String user = "CREATE_USER||" + userName; //send message - 34 - outDataStream.writeUTF(user); } } catch (Exception e) { System.out.println("CREATE USER FAILED"); } } // delete all of a users messages public void deleteMessages() { try { String user = new String(source.jTextField2.getText()); outDataStream.writeUTF("DELETE_ALL_MESSAGES||" + user); refreshAddressBook(); source.jTextArea1.setText(""); source.jTextArea3.setText(""); } catch (Exception e) { System.out.println("DELETE MESSAGES FAILED"); } } // super delete user public void deleteUser() { try { String userName = new String(source.jTextField4.getText()); if (userName.length() > 0) { String user = "DELETE_CLIENT_USER||" + userName; //send message outDataStream.writeUTF(user); } } catch (Exception e) { System.out.println("DELETE USER FAILED"); } } public void sendAndReceive() { try { //send message String user = new String(source.jTextField2.getText()); String sendMe = new String("REFRESH_MESSAGES_LIST||" + user); outDataStream.writeUTF(sendMe); - 35 - } catch (Exception e) { System.out.println("REFRESHING MESSAGES FAILED"); } } // retrieves the appropriate info from text fields and sends the message to // the server for delivery to the recipient public void sendMessage() { try { String to = new String(source.jComboBox2.getSelectedItem().toString()); String from = new String(source.jTextField2.getText()); String subj = new String(source.jTextField3.getText()); String mess = new String(source.jTextArea2.getText()); if (to.length() > 0 && from.length() > 0 && subj.length() > 0 && mess.length() > 0) { String message = "NEW_MESSAGE||" + to + "||" + from + "||" + subj + "||" + mess; // send message outDataStream.writeUTF(message); } } catch (Exception e) { System.out.println("SEND FAILED"); } } } - 36 - Appendix II: Code Listing (Server Side) /** * ECE 3553 Final Project * SES Team 2004 */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.net.*; import java.io.*; import java.util.*; import java.util.Date; public class Server extends JFrame implements ActionListener { ServerListener listen; String connectionLog = ""; String messageLog = ""; String host = "localhost"; int port = 2003; JScrollPane jScrollPane1 = new JScrollPane(); JScrollPane jScrollPane2 = new JScrollPane(); // displays all incoming and outgoing traffic through the server JTextArea trafficTextArea = new JTextArea(); // displays all connections and recieved packets JTextArea connectionTextArea = new JTextArea(); // text field where a manual reply is filled in JTextField sendTextField = new JTextField(); // runButton starts the server JButton runButton = new JButton(); // closes all files and exits the application JButton exitButton = new JButton(); // sends a manual reply to the client JButton sendButton = new JButton(); JLabel titleLabel = new JLabel(); JLabel connectionLabel = new JLabel(); JLabel sendLabel = new JLabel(); - 37 - /***************************************************************************** * Server.java ****************************************************************************/ public Server() { // construct the graphical user interface buildGUI(); } /***************************************************************************** * main starts the server and sets the gui visible ****************************************************************************/ public static void main(String[] args) { Server server = new Server(); server.setVisible(true); } /***************************************************************************** * actionPerformed recieves ActionEvents from the JButtons ****************************************************************************/ public void actionPerformed(ActionEvent e) { Object s = e.getSource(); // check if the action is an instance of JButton if (s instanceof JButton) { // run server if (s == runButton) { listen = new ServerListener(this); listen.start(); } // exit server if (s == exitButton) { System.exit(0); } // send message from sendTextField if (s == sendButton) { messageLog += "Server: " + sendTextField.getText() + "\n"; trafficTextArea.setText(messageLog); listen.setMessage(sendTextField.getText()); sendTextField.setText(""); } } } - 38 - /***************************************************************************** * buildGUI constructs the gui ****************************************************************************/ private void buildGUI() { // set the size of the gui setSize(525, 535); // add jScrollPanes to make the text areas scrollable jScrollPane1.setBounds(new Rectangle(12, 42, 491, 189)); jScrollPane2.setBounds(new Rectangle(12, 268, 488, 86)); // set the text area parameters trafficTextArea.setText(""); trafficTextArea.setForeground(Color.blue); connectionTextArea.setText(""); connectionTextArea.setForeground(Color.red); sendTextField.setBounds(new Rectangle(14, 399, 488, 26)); jScrollPane1.getViewport().add(trafficTextArea, null); jScrollPane2.getViewport().add(connectionTextArea, null); // add the Gui title information titleLabel.setFont(new java.awt.Font("Dialog", 0, 20)); titleLabel.setForeground(Color.green); titleLabel.setText("SES Server Traffic Monitor"); titleLabel.setBounds(new Rectangle(13, 22, 261, 15)); connectionLabel.setFont(new java.awt.Font("Dialog", 0, 20)); connectionLabel.setForeground(Color.green); connectionLabel.setText("Connection Monitor"); connectionLabel.setBounds(new Rectangle(12, 241, 237, 21)); sendLabel.setFont(new java.awt.Font("Dialog", 0, 20)); sendLabel.setForeground(Color.green); sendLabel.setText("Send Manual Reply"); sendLabel.setBounds(new Rectangle(13, 373, 302, 23)); runButton.setBounds(new Rectangle(10, 456, 160, 25)); runButton.setText("Run"); sendButton.setBounds(new Rectangle(180, 456, 160, 26)); sendButton.setText("Send"); exitButton.setBounds(new Rectangle(352, 456, 160, 25)); - 39 - exitButton.setText("Exit"); // register action listeners runButton.addActionListener(this); exitButton.addActionListener(this); sendButton.addActionListener(this); // all of the objects are added to the content pane. this.getContentPane().setLayout(null); this.getContentPane().setBackground(Color.black); this.getContentPane().add(jScrollPane1, null); this.getContentPane().add(runButton, null); this.getContentPane().add(connectionLabel, null); this.getContentPane().add(jScrollPane2, null); this.getContentPane().add(sendTextField, null); this.getContentPane().add(sendLabel, null); this.getContentPane().add(titleLabel, null); this.getContentPane().add(sendButton, null); this.getContentPane().add(exitButton, null); } } /***************************************************************************** * ServerListener creates the serverSocket and enters an infinite loop * receiving transmissions from the client ****************************************************************************/ class ServerListener extends Thread { Server source; ServerSocket listenSocket; int port; Socket connection; SendReceive sr; ServerListener(Server s) { source = (Server) s; } public void run() { port = source.port; try { // holds up to 50 incoming connections in the connection queue listenSocket = new ServerSocket(port,50); - 40 - source.connectionLog += "Server running:\nlistening on port " + port + "\n"; source.connectionTextArea.setText(source.connectionLog); //infinite loop listing for connections while (true) { Socket connection = listenSocket.accept(); // sr starts threaded class for sending and recieving info sr = new SendReceive(connection, source); sr.start(); } } catch (IOException e) { source.connectionLog += "Error opening ServerSocket\n"; source.connectionTextArea.setText(source.connectionLog); System.exit(0); } } public void setMessage(String s) { sr.sendMessage(s); } } /***************************************************************************** * SendReceive is responsibe for all communication with the client. * SendReceive extends thread so the gui is not tied up. ****************************************************************************/ class SendReceive extends Thread { Server source; String message; Socket connection; DataInputStream inDataStream; DataOutputStream outDataStream; String user = ""; // constructor with socket and a handle to the GUI SendReceive(Socket socket, Server s) { connection = socket; source = s; } public void run() { - 41 - source.connectionLog += "Client Added: \nlocalhost : " + connection.getPort() +"\n"; source.connectionTextArea.setText(source.connectionLog); try { outDataStream = new DataOutputStream(connection.getOutputStream()); inDataStream = new DataInputStream(connection.getInputStream()); while (true) { message = inDataStream.readUTF(); // parse the message and determine the header in the string parseMessage(message.toString()); // update the server display source.connectionLog += "Message received: " + new Date() + "\n"; source.connectionTextArea.setText(source.connectionLog); source.messageLog += "Client: " + message + "\n"; source.trafficTextArea.setText(source.messageLog); } } catch (IOException e) { source.connectionLog += "Connection closed by Client at: " + new Date() + "\n"; source.connectionTextArea.setText(source.connectionLog); return; } } /***************************************************************************** * Parse message parses through the recieved message string and determines * what action to take. ****************************************************************************/ public void parseMessage(String message) { if (message.length() > 0) { if (message.indexOf("CREATE_USER") >= 0) { addUser(message); } else if (message.indexOf("NEW_MESSAGE") >= 0) { addMessage(message); } else if (message.indexOf("GET_MESSAGE") >= 0) { sendIndividualMessage(user, message); } else if (message.indexOf("LOGIN") >= 0) { - 42 - // verify the user verifyUser(message); } else if (message.indexOf("GET_ADDRESS_BOOK") >= 0) { sendAddressBook(); } else if (message.indexOf("DELETE_ALL_MESSAGES") >= 0) { // delete all messages deleteMessages (message); } else if (message.indexOf("DELETE_CLIENT_USER") >= 0) { // delete all messages deleteUser (message); } else if (message.indexOf("REFRESH_MESSAGES_LIST") >= 0) { // send updated message list StringTokenizer st = new StringTokenizer (message,"||"); if (st.countTokens()==2) { String command = st.nextToken(); user = st.nextToken(); sendMessageList(user); } } } } /***************************************************************************** * verifyUser parses through the command string and separates the parameters. * If the user exists a confirmation reply message is sent to the client. If * there are no registered users and the new user logs on with "admin" as his * password, then a new addressbook is created and he/she becomes the first * registered user. The new admin is responsible for adding new users. ****************************************************************************/ public void verifyUser(String message) { StringTokenizer st = new StringTokenizer(message, "||"); String command = ""; // command string user = ""; // user name String passW = ""; // password String userFile = ""; // user's file boolean userExists = false; // bool determining if the user exists boolean addressBookExists = false; // bool determining if the addressbook // exists // assign the appropriate section of the line to its string name - 43 - if (st.countTokens() == 3) { command = st.nextToken(); user = st.nextToken(); passW = st.nextToken(); } userFile = user.toLowerCase() + "AddressBook.txt"; userExists = (new File(userFile)).exists(); ; addressBookExists = (new File("AddressBook.txt")).exists(); ; // if the user's files exist and the password is client, then send // a reply message to the client confirming his/her login if (userExists && passW.equalsIgnoreCase("client")) { sendMessage("CLIENT_LOGIN_SUCCESSFUL"); // send the address book to the user sendAddressBook(); // send the user a list of messages sendMessageList(user); } // if the user's files exist and the password is client, then send // a reply message to the client confirming admin permissions else if (userExists && passW.equalsIgnoreCase("admin")) { sendMessage("ADMIN_LOGIN_SUCCESSFUL"); // send the address book to the user sendAddressBook(); // send the user a list of messages sendMessageList(user); } // if no addressbook exists and the user's password is admin, begin // a new mail system and add the new user as the first member else if (!addressBookExists && passW.equalsIgnoreCase("admin")) { newMailSystem(user); sendMessage("ADMIN_LOGIN_SUCCESSFUL"); } // send an unknown user error to the client if the user cannot // be confirmed else { sendMessage("UNKNOWN_USER"); } } - 44 - /***************************************************************************** * newMailSystem creates a new mail system and adds the current admin user * as the first member of the mail system ****************************************************************************/ public void newMailSystem(String user) { try { if (new File("AddressBook.txt").exists()) { PrintWriter pww = new PrintWriter(new FileOutputStream( "AddressBook.txt", true)); pww.println(user); pww.flush(); pww.close(); } else { PrintWriter pw = new PrintWriter(new FileWriter("AddressBook.txt")); pw.println("ADDRESS_BOOK "); pw.println(user); pw.flush(); pw.close(); } PrintWriter addressWriter = new PrintWriter(new FileWriter(user + "AddressBook.txt")); PrintWriter messageWriter = new PrintWriter(new FileWriter(user + "MessageLog.txt")); addressWriter.println("ADDRESS_BOOK "); addressWriter.println(user); addressWriter.flush(); addressWriter.close(); messageWriter.flush(); messageWriter.close(); } catch (IOException e) { System.out.println("failed to create address book"); } } /***************************************************************************** * addMessage adds the message to the correct user's messageLog.txt file ****************************************************************************/ public void addMessage(String message) { try { StringTokenizer st = new StringTokenizer(message, "||"); String command = ""; - 45 - String to = ""; String from = ""; String subj = ""; String body = ""; String addMe = ""; boolean userExists = false; if (st.countTokens() >= 3) { command = st.nextToken(); to = st.nextToken(); from = st.nextToken(); subj = st.nextToken(); body = st.nextToken(); addMe = message.substring(message.indexOf(from)); } if (new File(to + "MessageLog.txt").exists()) { PrintWriter pww = new PrintWriter(new FileOutputStream(to + "MessageLog.txt", true)); pww.println(addMe); pww.flush(); pww.close(); } } catch (IOException e) {} } /***************************************************************************** * addUser can only be called by a user logged in as an administrator. A user * is added by creating a new addressbook and messageLog file. If a user is * added then every member of the mailsystem recieves an updated addressbook ****************************************************************************/ public void addUser(String message) { StringTokenizer st = new StringTokenizer(message, "||"); String command = ""; boolean userExists = false; if (st.countTokens() == 2) { command = st.nextToken(); user = st.nextToken(); try { PrintWriter addressWriter = new PrintWriter(new FileWriter(user + "AddressBook.txt")); PrintWriter messageWriter = new PrintWriter(new FileWriter(user + "MessageLog.txt")); - 46 - if (new File("AddressBook.txt").exists()) { PrintWriter masterAddressBook = new PrintWriter(new FileOutputStream( "AddressBook.txt", true)); masterAddressBook.println(user); masterAddressBook.flush(); masterAddressBook.close(); BufferedReader br = new BufferedReader(new FileReader( "AddressBook.txt")); String line = ""; while ( (line = br.readLine()) != null) { addressWriter.println(line); } br.close(); addressWriter.flush(); addressWriter.close(); messageWriter.flush(); messageWriter.close(); //update everyones address book updateIndividualAddressBooks (); } } catch (IOException e) { System.out.println("failed to create address book"); } } } /***************************************************************************** * updates all registered user's addressbooks ****************************************************************************/ public void updateIndividualAddressBooks () { try { Vector tmpAddressBook = new Vector(); BufferedReader br = new BufferedReader(new FileReader("AddressBook.txt")); String line = ""; while ( (line = br.readLine()) != null) { tmpAddressBook.add(line); } br = new BufferedReader(new FileReader("AddressBook.txt")); PrintWriter updateWriter; String line2 = ""; while ( (line2 = br.readLine()) != null) { - 47 - if (new File(line2 + "AddressBook.txt").exists()) { updateWriter = new PrintWriter(new FileWriter(line2 + "AddressBook.txt")); for (int i = 0; i < tmpAddressBook.size(); i++) { updateWriter.println(tmpAddressBook.elementAt(i)); } updateWriter.flush(); updateWriter.close(); } } br.close(); tmpAddressBook.clear(); } catch (IOException e) {System.out.println("ERROR UPDATING ADDRESS BOOKS"); } } /***************************************************************************** * deleteMessages verifies if the user's messageLog exists and deletes all * off the messages ****************************************************************************/ public void deleteMessages (String s) { StringTokenizer st = new StringTokenizer (s,"||"); if (st.countTokens()==2) { String command = st.nextToken(); String user = st.nextToken(); if (new File(user+"MessageLog.txt").exists()) { //delete all entries try { PrintWriter pw = new PrintWriter(new FileWriter(user + "MessageLog.txt")); pw.print(""); pw.flush(); pw.close(); } catch (IOException e) {} } } } /***************************************************************************** * deleteUser verifies if the user exists and deletes all files associated * with the user. ****************************************************************************/ - 48 - public void deleteUser (String s) { StringTokenizer st = new StringTokenizer (s,"||"); if (st.countTokens()==2) { String command = st.nextToken(); String user = st.nextToken(); //delete all entries if (new File(user + "MessageLog.txt").delete() && new File(user + "AddressBook.txt").delete()) { } else { System.out.println("DELETE USER FAILED"); } deleteUserFromAddressBook (user); } } /***************************************************************************** * deleteUserFromAddressBook deletes the user from the addressBook and * updates everyones individual address book ****************************************************************************/ public void deleteUserFromAddressBook (String user) { try { BufferedReader br = new BufferedReader(new FileReader("AddressBook.txt")); PrintWriter tempAddress = new PrintWriter(new FileWriter("temp.txt")); String line = ""; while ( (line = br.readLine()) != null) { if (line.indexOf(user) < 0) { tempAddress.println(line); } } tempAddress.flush(); tempAddress.close(); br.close(); //replace the addressBook with the temp BufferedReader br2 = new BufferedReader(new FileReader("temp.txt")); PrintWriter replaceAddr = new PrintWriter(new FileWriter( "AddressBook.txt")); String line2 = ""; while ( (line2 = br2.readLine()) != null) { replaceAddr.println(line2); } replaceAddr.flush(); replaceAddr.close(); - 49 - br2.close(); //delete temp file if (!new File("temp.txt").delete()) { System.out.println("FAILED TO DELETE TEMPORARY ADDRESS BOOK"); } //update everyusers addressbook updateIndividualAddressBooks (); sendAddressBook(); } catch (IOException e) { } } /***************************************************************************** * sendIndividualMessage parses through a users message log and * returns the selected message to the client ****************************************************************************/ public void sendIndividualMessage(String user, String message) { try { BufferedReader br = new BufferedReader(new FileReader(user + "MessageLog.txt")); String messageReply = "MESSAGE_REPLY||"; String line = ""; while ( (line = br.readLine()) != null) { if (line.indexOf(message.substring(16)) >= 0) { messageReply += line + "\n"; } } br.close(); sendMessage(messageReply); } catch (IOException e) {} } /***************************************************************************** * sendMessageList sends a string of messages containing who each message in * their message log is from the subject. The messages are delimited by * "@@@@" for easy parsing on the client side. ****************************************************************************/ public void sendMessageList(String user) { try { BufferedReader br = new BufferedReader(new FileReader(user + "MessageLog.txt")); - 50 - String messageList = "MESSAGE_LIST@@@@"; StringTokenizer st; String line = ""; while ( (line = br.readLine()) != null) { st = new StringTokenizer(line, "||"); if (st.countTokens() >= 3) { messageList += st.nextToken() + "||" + st.nextToken() + "@@@@"; } } br.close(); sendMessage(messageList); } catch (IOException e) {} } /***************************************************************************** * sendAddressBook sends a list of registered members of the mail system to * the client. ****************************************************************************/ public void sendAddressBook() { try { BufferedReader br = new BufferedReader(new FileReader("AddressBook.txt")); String addressLine = "ADDRESS_BOOK "; String line = ""; while ( (line = br.readLine()) != null) { addressLine += line + " "; } br.close(); sendMessage(addressLine); } catch (IOException e) {} } /***************************************************************************** * sendMessage sends a plain text string to the client ****************************************************************************/ public void sendMessage(String s) { try { outDataStream.writeUTF(s); } catch (IOException eee) {} } - 51 - Appendix III: Screen Shots Figure 1.14 Server Activated - 52 - Figure 1.15: Login Screen - 53 - Figure 1.16: Administrator Screen - 54 - Figure 1.17: Add New User - 55 - Figure 1.18: Compose New Mail - 56 - Figure 1.19: User Inbox - 57 - Figure 1.20: Read Mail - 58 - Figure 1.21: Invalid User - 59 - Appendix IV: Readme.txt This document serves as a walkthrough enabling the user to setup a secure email server. However, prior to following the steps listed, please ensure that your system is equipped with java support. Else, you may wish to download J2SE(TM) Development Kit 5.0 from http://www.java.com, prior to proceeding with the following. Further, it is essential to note that JAVA is case-sensitive, therefore a potential server processing error may be as such. In order to ensure that system security is not compromised, it is best recommended that the network administrator download the latest JAVA related security updates from the developer site. The setup walkthrough is as follows: Compile Client.java and Server.java using standard javac notation Run the server by typing “java Server” Run the client in the same manner, only “java Client” The followup screens explain themselves As administrator, you can create/delete users To send mail, select “Compose Mail” and fill in the fields To view selected message, select “Display Mail” To clear inbox, select “Delete Messages” If multiple clients are communicating simultaneously, you may have to refresh your screen in order to receive recently sent mail To quit the application, select “Exit” NOTE: If this solution is being run for the first time, login with the desired username, and set the password as “admin”. This gives you access to the solutions universal functionalities. Further help can be found at http://www.google.com (query your specific topic of interest). Thank you for choosing the Secure Email Server – brought to you by SES. - 60 -