source: trunk/src/org/expeditee/auth/Authenticator.java@ 1230

Last change on this file since 1230 was 1202, checked in by bln4, 5 years ago

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 size: 15.9 KB
Line 
1package org.expeditee.auth;
2
3import java.io.File;
4import java.io.FileInputStream;
5import java.io.FileNotFoundException;
6import java.io.FileOutputStream;
7import java.io.FileWriter;
8import java.io.IOException;
9import java.io.InputStream;
10import java.io.Writer;
11import java.security.KeyFactory;
12import java.security.KeyStore;
13import java.security.KeyStore.SecretKeyEntry;
14import java.security.KeyStoreException;
15import java.security.NoSuchAlgorithmException;
16import java.security.PublicKey;
17import java.security.SecureRandom;
18import java.security.UnrecoverableEntryException;
19import 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;
33
34import javax.crypto.SecretKey;
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;
49import 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;
57import org.ngikm.cryptography.CryptographyConstants;
58
59public final class Authenticator implements CryptographyConstants {
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);
172 if (!keyStoreFile.exists()) {
173 keyStore.load(null, "ExpediteeAuthPassword".toCharArray());
174 } else {
175 try (final InputStream in = new FileInputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME)) {
176 keyStore.load(in, "ExpediteeAuthPassword".toCharArray());
177 }
178 }
179 }
180
181 final SecretKey getSecretKey(final String label, final String password) throws NoSuchAlgorithmException, KeyStoreException {
182 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
183 KeyStore.SecretKeyEntry entry = null;
184 try {
185 entry = (SecretKeyEntry) keyStore.getEntry(label, entryPassword);
186 } catch (final UnrecoverableEntryException e) {
187 entry = null;
188 }
189 if (entry == null) { return null; }
190 else { return entry.getSecretKey(); }
191 }
192
193 final void putKey(final String label, final String password, final SecretKey key) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
194 final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
195 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
196 keyStore.setEntry(label, entry, entryPassword);
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 });
376 }
377}
Note: See TracBrowser for help on using the repository browser.