Ignore:
Timestamp:
01/30/19 12:49:25 (5 years ago)
Author:
bln4
Message:

Initial commit of functionality concerning multiuser login, further to come.

Actions.java -> Actions that allow users to authenticate and secure their accounts.
AuthenticationTag.java -> Enum like structure for text fields associated with authentication.
Authenticator.java -> Startup functionality for when Expeditee is run in authentication mode.
EncryptedExpReader.java -> Reads exp files previously encrypted with EncryptedExpWriter (not currently used) and EncryptedProfileExpWriter
Mail.java -> Functions for transforming database stored messages into datastructures used to display those messages to the MailBay.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/expeditee/auth/Authenticator.java

    r1201 r1202  
    55import java.io.FileNotFoundException;
    66import java.io.FileOutputStream;
     7import java.io.FileWriter;
    78import java.io.IOException;
    89import java.io.InputStream;
     10import java.io.Writer;
     11import java.security.KeyFactory;
    912import java.security.KeyStore;
    1013import java.security.KeyStore.SecretKeyEntry;
    1114import java.security.KeyStoreException;
    1215import java.security.NoSuchAlgorithmException;
     16import java.security.PublicKey;
     17import java.security.SecureRandom;
    1318import java.security.UnrecoverableEntryException;
    1419import java.security.cert.CertificateException;
     20import java.security.spec.InvalidKeySpecException;
     21import java.security.spec.X509EncodedKeySpec;
     22import java.sql.Connection;
     23import java.sql.DriverManager;
     24import java.sql.ResultSet;
     25import java.sql.SQLException;
     26import java.sql.Statement;
     27import java.util.Arrays;
     28import java.util.Base64;
     29import java.util.Collection;
     30import java.util.HashMap;
     31import java.util.Map;
     32import java.util.stream.Stream;
    1533
    1634import javax.crypto.SecretKey;
    17 
     35import javax.crypto.spec.SecretKeySpec;
     36
     37import org.expeditee.actions.Actions;
     38import org.expeditee.core.Dimension;
     39import org.expeditee.core.Point;
     40import org.expeditee.gio.EcosystemManager;
     41import org.expeditee.gio.GraphicsManager;
     42import org.expeditee.gio.InputManager;
     43import org.expeditee.gio.InputManager.WindowEventListener;
     44import org.expeditee.gio.InputManager.WindowEventType;
     45import org.expeditee.gio.gesture.StandardGestureActions;
     46import org.expeditee.gui.Browser;
     47import org.expeditee.gui.DisplayController;
     48import org.expeditee.gui.Frame;
    1849import org.expeditee.gui.FrameIO;
     50import org.expeditee.gui.FrameUtils;
     51import org.expeditee.gui.MessageBay;
     52import org.expeditee.items.ItemUtils;
     53import org.expeditee.items.Text;
     54import org.expeditee.settings.Settings;
     55import org.expeditee.settings.UserSettings;
     56import org.expeditee.settings.auth.secrets.KeyList;
    1957import org.ngikm.cryptography.CryptographyConstants;
    2058
    2159public final class Authenticator implements CryptographyConstants {
    22         final KeyStore keyStore = KeyStore.getInstance(KeystoreType);
    23         private static final String keystoreFileName = FrameIO.PARENT_FOLDER + "keystore.ks" + File.separator;
    24        
    25         public Authenticator() throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException {
    26                 final File keyStoreFile = new File(keystoreFileName);
     60       
     61        // The frame number of the frame containing the current authenticated users public key.
     62        public static final int PUBLIC_KEY_FRAME = 4;
     63       
     64        private final KeyStore keyStore = KeyStore.getInstance(KeystoreType);
     65        private static final byte[] TRUE = "yes".getBytes();
     66        private static final byte[] FALSE = "no".getBytes();
     67        private static final String KEYSTOREFILENAME = "keystore.ks" + File.separator;
     68       
     69        private static Authenticator instance;
     70       
     71        public static Authenticator getInstance() throws KeyStoreException, FileNotFoundException, NoSuchAlgorithmException, CertificateException, IOException, ClassNotFoundException, SQLException {
     72                if (instance == null) { instance = new Authenticator(); }
     73                return instance;
     74        }
     75       
     76        private Authenticator() throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, ClassNotFoundException, SQLException {
     77                UserSettings.setupDefaultFolders();
     78               
     79                // initialise keystore and actions
     80                loadKeystore();
     81                Actions.LoadMethods(org.expeditee.auth.Actions.class);
     82
     83                // draw the window
     84                final GraphicsManager g = EcosystemManager.getGraphicsManager();
     85                g.setWindowLocation(new Point(50, 50));
     86                DisplayController.Init();
     87                g.setWindowSize(new Dimension(UserSettings.InitialWidth.get(), UserSettings.InitialHeight.get()));
     88                setInputManagerWindowRoutines();
     89               
     90                // Load documentation and start pages
     91                FrameUtils.extractResources(false);
     92
     93                // Load fonts before loading any frames so the items on the frames will be able to access their fonts
     94                Text.InitFonts();
     95               
     96                // initialing settings does not require a user profile established
     97                Settings.Init();
     98               
     99                // navigate to authentication frame
     100                final Frame authFrame = FrameIO.LoadFrame("authentication1");
     101                DisplayController.setCurrentFrame(authFrame, true);
     102               
     103                // set initial values
     104                final Stream<Text> usernameItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtUsername"));
     105                final Stream<Text> passwordItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtPassword"));
     106                usernameItemsStream.forEach(txtUsername -> txtUsername.setText(System.getProperty("user.name", "")));
     107                passwordItemsStream.forEach(txtPassword -> txtPassword.setText(System.getProperty("user.password", "")));
     108                                               
     109                MessageBay.warningMessages(org.expeditee.actions.Actions.Init());
     110               
     111                // ensure database
     112                Class.forName("org.sqlite.JDBC");
     113                if (!mailDatabaseExists()) {
     114                        createMailDatabase();
     115                }
     116        }
     117       
     118        private void createMailDatabase() throws ClassNotFoundException, SQLException {
     119                Connection c = DriverManager.getConnection("jdbc:sqlite:" + FrameIO.PARENT_FOLDER + "/expmail.db");
     120                Statement createTable = c.createStatement();
     121                String sql = "CREATE TABLE EXPMAIL (" +
     122                                "SND            TEXT                                    NOT NULL, " +
     123                                "REC            TEXT                                    NOT NULL, " +
     124                                "MSG            TEXT                                    NOT NULL, " +
     125                                "MSG2           TEXT                                    NOT NULL, " +
     126                                "OPTS           ARRAY                                   NOT NULL, " +
     127                                "OPTSVAL        ARRAY                                   NOT NULL)";
     128                createTable.executeUpdate(sql);
     129                createTable.close();
     130                c.close();
     131        }
     132       
     133        final void loadMailDatabase() throws SQLException {
     134                Connection c = DriverManager.getConnection("jdbc:sqlite:" + FrameIO.PARENT_FOLDER + "/expmail.db");
     135                Statement query = c.createStatement();
     136                ResultSet results = query.executeQuery("SELECT * FROM EXPMAIL");
     137                Mail.clear();
     138                while (results.next()) {
     139                        String from = results.getString("snd");
     140                        String to = results.getString("rec");
     141                        String msg = results.getString("msg");
     142                        String msg2 = results.getString("msg2");
     143                        String[] opts = results.getString("opts").split(",");
     144                        opts[0] = opts[0].replace("[", "");
     145                        opts[opts.length - 1] = opts[opts.length - 1].replace("]", "");
     146                        String[] optsVal = results.getString("optsval").split(",");
     147                        optsVal[0] = optsVal[0].replace("[", "");
     148                        optsVal[optsVal.length - 1] = optsVal[optsVal.length - 1].replace("]", "");
     149                       
     150                        Map<String, String> options = new HashMap<String, String>();
     151                        for (int i = 0, o = 0; i < opts.length && o < optsVal.length; i++, o++) {
     152                                String key = opts[i].trim();
     153                                String val = optsVal[o].trim();
     154                                options.put(key, val);
     155                        }
     156                       
     157                        Mail.addEntry(new Mail.MailEntry(from, to, msg, msg2, options));
     158                }
     159                results.close();
     160                query.close();
     161                c.close();
     162        }
     163       
     164        private boolean mailDatabaseExists() {
     165                final File file = new File(FrameIO.PARENT_FOLDER + "/expmail.db");
     166                return file.exists();
     167        }
     168               
     169        private void loadKeystore()
     170                        throws IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException {
     171                final File keyStoreFile = new File(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME);
    27172                if (!keyStoreFile.exists()) {
    28173                        keyStore.load(null, "ExpediteeAuthPassword".toCharArray());
    29174                } else {
    30                         try (final InputStream in = new FileInputStream(keystoreFileName)) {
     175                        try (final InputStream in = new FileInputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME)) {
    31176                                keyStore.load(in, "ExpediteeAuthPassword".toCharArray());
    32177                        }
     
    34179        }
    35180       
    36         public final SecretKey getSecretKey(final String label, final String password) throws NoSuchAlgorithmException, UnrecoverableEntryException, KeyStoreException {               
     181        final SecretKey getSecretKey(final String label, final String password) throws NoSuchAlgorithmException, KeyStoreException {           
    37182                final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
    38                 final KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(label, entryPassword);
     183                KeyStore.SecretKeyEntry entry = null;
     184                try {
     185                        entry = (SecretKeyEntry) keyStore.getEntry(label, entryPassword);
     186                } catch (final UnrecoverableEntryException e) {
     187                        entry = null;
     188                }
    39189                if (entry == null) { return null; }
    40190                else { return entry.getSecretKey(); }
    41191        }
    42192       
    43         public final void putKey(final String label, final String password, final SecretKey key) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
     193        final void putKey(final String label, final String password, final SecretKey key) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
    44194                final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
    45195                final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
    46196                keyStore.setEntry(label, entry, entryPassword);
    47                 keyStore.store(new FileOutputStream(keystoreFileName), "ExpediteeAuthPassword".toCharArray());
     197                keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
     198        }
     199       
     200        final void putEmail(String username, String email) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
     201                // Establish location of email file
     202                String emailFilePath = FrameIO.PROFILE_PATH + username + File.separator + username + ".email";
     203                File emailFile = new File(emailFilePath);
     204               
     205                // Delete old version if it exists.
     206                if (emailFile.exists()) {
     207                        emailFile.delete();
     208                }
     209               
     210                // Write email to file
     211                emailFile.createNewFile();
     212                Writer w = new FileWriter(emailFile);
     213                w.write(email);
     214                w.flush();
     215                w.close();
     216               
     217                // TODO: set rights on file to be read only by 'owner' once installed on drive.
     218        }
     219       
     220        final boolean hasRegisteredEmail(String username) throws KeyStoreException {
     221                String emailFilePath = FrameIO.PROFILE_PATH + username + File.separator + username + ".email";
     222                File emailFile = new File(emailFilePath);
     223                return emailFile.exists();
     224        }
     225       
     226        final boolean confirmIntergalaticNumber(final String username, final String email, final String intergalacticNumber) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException {
     227                try {
     228                        final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
     229                        final KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(email + username, entryPassword);
     230                        if (entry == null) {
     231                                return false;
     232                        } else if (entry.getSecretKey().getEncoded() == TRUE) {
     233                                keyStore.deleteEntry(email + username);
     234                                keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
     235                                return true;
     236                        } else { return false; }
     237                } catch (final UnrecoverableEntryException e) {
     238                        return false;
     239                }
     240        }
     241       
     242        final String newIntergalacticNumber(final String username, final String email) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
     243                // generate intergalactic number
     244                final SecureRandom rand = new SecureRandom();
     245                final byte[] intergalacticNumberBytes = new byte[20];
     246                rand.nextBytes(intergalacticNumberBytes);
     247                final String intergalacticNumber = Base64.getEncoder().encodeToString(intergalacticNumberBytes);
     248               
     249                // store intergalactic number
     250                final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(TRUE, SymmetricAlgorithm));
     251                final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
     252                keyStore.setEntry(email + username, entry, entryPassword);
     253                keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
     254               
     255                return intergalacticNumber;
     256        }
     257       
     258        final PublicKey getPublicKey(String username) throws InvalidKeySpecException, NoSuchAlgorithmException {
     259                Frame withTargetPublic = FrameIO.LoadFrame(username + Authenticator.PUBLIC_KEY_FRAME);
     260                Collection<Text> textItems = withTargetPublic.getTextItems();
     261                textItems.removeIf(t -> !t.getText().startsWith("PublicKey"));
     262               
     263                if (textItems.isEmpty()) {
     264                        return null;
     265                } else {
     266                        String keyEncoded = textItems.stream().findFirst().get().getData().get(0);
     267                        byte[] keyBytes = Base64.getDecoder().decode(keyEncoded);
     268                        PublicKey key = KeyFactory.getInstance(AsymmetricAlgorithm).generatePublic(new X509EncodedKeySpec(keyBytes));
     269                        return key;
     270                }
     271        }
     272       
     273        final void markRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
     274                KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(TRUE, SymmetricAlgorithm));
     275                KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
     276                keyStore.setEntry(username + "colleaguesRequested", entry, entryPassword);
     277                keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
     278        }
     279       
     280        final void clearRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
     281                KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(FALSE, SymmetricAlgorithm));
     282                KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
     283                keyStore.setEntry(username + "colleaguesRequested", entry, entryPassword);
     284                keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
     285        }
     286       
     287        final boolean hasRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
     288                String alias = username + "colleaguesRequested";
     289                if (!keyStore.containsAlias(alias)) {
     290                        return false;
     291                } else {
     292                        KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
     293                        KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(alias, entryPassword);
     294                        return Arrays.equals(entry.getSecretKey().getEncoded(), TRUE);
     295                }
     296        }
     297       
     298        final void putColleagues(String username, String[] colleagues) throws KeyStoreException {
     299                String alias = username + "colleagues";
     300                final SecretKeySpec secretKeySpec = new SecretKeySpec((colleagues[0] + System.getProperty("line.separator") + colleagues[1]).getBytes(), SymmetricAlgorithm);
     301                KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(secretKeySpec);
     302                KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
     303                keyStore.setEntry(alias, entry, entryPassword);
     304        }
     305       
     306        final String[] getColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
     307                String alias = username + "colleagues";
     308                if (!keyStore.containsAlias(alias)) {
     309                        return null;
     310                } else {
     311                        KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
     312                        KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(alias, entryPassword);
     313                        byte[] colleaguesEncoded = entry.getSecretKey().getEncoded();
     314                        String colleagues = new String(colleaguesEncoded);
     315                        return colleagues.split(System.getProperty("line.separator"));
     316                }
     317        }
     318       
     319        private static void setInputManagerWindowRoutines()     {
     320                InputManager manager = EcosystemManager.getInputManager();
     321               
     322            // Refresh the layout when the window resizes
     323                manager.addWindowEventListener(new WindowEventListener() {
     324                        @Override
     325                        public void onWindowEvent(WindowEventType type)
     326                        {
     327                                if (type != WindowEventType.WINDOW_RESIZED) {
     328                                        return;
     329                                }
     330                                DisplayController.refreshWindowSize();
     331                                FrameIO.RefreshCacheImages();
     332                                for (Frame frame : DisplayController.getFrames()) {
     333                                        if (frame != null) {
     334                                                ItemUtils.Justify(frame);
     335                                                frame.refreshSize();
     336                                        }
     337                                }
     338                                DisplayController.requestRefresh(false);
     339                        }
     340                });
     341               
     342                manager.addWindowEventListener(new WindowEventListener() {
     343                        @Override
     344                        public void onWindowEvent(WindowEventType type)
     345                        {
     346                                if (type != WindowEventType.MOUSE_EXITED_WINDOW) {
     347                                        return;
     348                                }
     349                                StandardGestureActions.mouseExitedWindow();
     350                        }
     351                });
     352               
     353                manager.addWindowEventListener(new WindowEventListener() {
     354                        @Override
     355                        public void onWindowEvent(WindowEventType type)
     356                        {
     357                                if (type != WindowEventType.MOUSE_ENTERED_WINDOW) {
     358                                        return;
     359                                }
     360                                StandardGestureActions.mouseEnteredWindow();
     361                        }
     362                });
     363               
     364                manager.addWindowEventListener(new WindowEventListener() {
     365                        @Override
     366                        public void onWindowEvent(WindowEventType type)
     367                        {
     368                                if (type != WindowEventType.WINDOW_CLOSED) {
     369                                        return;
     370                                }
     371                                if (Browser._theBrowser != null) {
     372                                        Browser._theBrowser.exit();
     373                                }
     374                        }
     375                });
    48376        }
    49377}
Note: See TracChangeset for help on using the changeset viewer.