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

Last change on this file since 1244 was 1244, checked in by davidb, 5 years ago

After change to have resources-public and resources-private, some changes needed to support running Expeditee for a single user; other main change is to allow FrameDirs to specify relative directory paths, to help with when Expeditee is run on the cloud -- similar work still needs to occurr for ImageDir and AudioDir; some other minor changes also made.

File size: 15.6 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.IOException;
8import java.io.InputStream;
9import java.nio.file.Path;
10import java.nio.file.Paths;
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.PreparedStatement;
25import java.sql.ResultSet;
26import java.sql.SQLException;
27import java.util.Arrays;
28import java.util.Base64;
29import java.util.Collection;
30import java.util.HashMap;
31import java.util.Map;
32import java.util.Scanner;
33import java.util.stream.Stream;
34
35import javax.crypto.SecretKey;
36import javax.crypto.spec.SecretKeySpec;
37
38import org.expeditee.actions.Actions;
39import org.expeditee.auth.tags.Constants;
40import org.expeditee.core.Dimension;
41import org.expeditee.core.Point;
42import org.expeditee.gio.EcosystemManager;
43import org.expeditee.gio.GraphicsManager;
44import org.expeditee.gio.InputManager;
45import org.expeditee.gio.InputManager.WindowEventListener;
46import org.expeditee.gio.InputManager.WindowEventType;
47import org.expeditee.gio.gesture.StandardGestureActions;
48import org.expeditee.gui.Browser;
49import org.expeditee.gui.DisplayController;
50import org.expeditee.gui.Frame;
51import org.expeditee.gui.FrameIO;
52import org.expeditee.gui.FrameUtils;
53import org.expeditee.gui.MessageBay;
54import org.expeditee.io.ExpReader;
55import org.expeditee.items.Item;
56import org.expeditee.items.ItemUtils;
57import org.expeditee.items.Text;
58import org.expeditee.settings.Settings;
59import org.expeditee.settings.UserSettings;
60import org.expeditee.settings.identity.secrets.KeyList;
61import org.ngikm.cryptography.CryptographyConstants;
62
63public final class Authenticator implements CryptographyConstants {
64
65 // The frame number of the frame containing the current authenticated users public key.
66 public static int CREDENTIALS_FRAME = 13;
67
68 public static boolean Authenticated = false;
69
70 private final KeyStore keyStore = KeyStore.getInstance(KeystoreType);
71
72 private static final byte[] TRUE = "yes".getBytes();
73 private static final byte[] FALSE = "no".getBytes();
74 private static final String KEYSTOREFILENAME = "keystore.ks" + File.separator;
75
76 private static Authenticator instance;
77
78 public static Authenticator getInstance() throws KeyStoreException, FileNotFoundException, NoSuchAlgorithmException, CertificateException, IOException, ClassNotFoundException, SQLException {
79 if (instance == null) { instance = new Authenticator(); }
80 return instance;
81 }
82
83 private Authenticator() throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, ClassNotFoundException, SQLException {
84 UserSettings.setupDefaultFolders();
85
86 // initialise keystore and actions
87 loadKeystore();
88 Actions.LoadMethods(org.expeditee.auth.Actions.class);
89
90 // draw the window
91 GraphicsManager g = EcosystemManager.getGraphicsManager();
92 g.setWindowLocation(new Point(50, 50));
93 DisplayController.Init();
94 g.setWindowSize(new Dimension(UserSettings.InitialWidth.get(), UserSettings.InitialHeight.get()));
95 setInputManagerWindowRoutines();
96
97 // Load documentation and start pages
98 FrameUtils.extractResources(false);
99
100 // Load fonts before loading any frames so the items on the frames will be able to access their fonts
101 Text.InitFonts();
102
103 // initialing settings does not require a user profile established
104 Settings.Init();
105
106 // navigate to authentication frame
107 Frame authFrame = FrameIO.LoadFrame("authentication1");
108 DisplayController.setCurrentFrame(authFrame, true);
109
110 // set initial values
111 Stream<Text> usernameItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtUsername"));
112 Stream<Text> passwordItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtPassword"));
113 usernameItemsStream.forEach(txtUsername -> txtUsername.setText(System.getProperty("user.name", "")));
114 passwordItemsStream.forEach(txtPassword -> txtPassword.setText(System.getProperty("user.password", "")));
115
116 MessageBay.warningMessages(org.expeditee.actions.Actions.Init());
117
118 // class load database classes
119 Class.forName("org.sqlite.JDBC");
120 }
121
122 private void loadKeystore()
123 throws IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException {
124 final File keyStoreFile = new File(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME);
125 if (!keyStoreFile.exists()) {
126 keyStore.load(null, Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
127 } else {
128 try (final InputStream in = new FileInputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME)) {
129 keyStore.load(in, Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
130 }
131 }
132 }
133
134 final void loadMailFromDirectory(Path contactDir) throws SQLException {
135 // Load in all mail.
136 Connection c = DriverManager.getConnection("jdbc:sqlite:" + contactDir.resolve("expmail.db"));
137 String sql = "SELECT * FROM EXPMAIL";
138 PreparedStatement query = c.prepareStatement(sql);
139 ResultSet allMail = query.executeQuery();
140
141 // Construct all mail objects using content from database.
142 while(allMail.next()) {
143 String timestamp = allMail.getString("time");
144 String from = allMail.getString("snd");
145 String to = allMail.getString("rec");
146 String msg = allMail.getString("msg");
147 String msg2 = allMail.getString("msg2");
148 String[] opts = allMail.getString("opts").split(",");
149 opts[0] = opts[0].replace("[", "");
150 opts[opts.length - 1] = opts[opts.length - 1].replace("]", "");
151 String[] optsVal = allMail.getString("optsval").split(",");
152 optsVal[0] = optsVal[0].replace("[", "");
153 optsVal[optsVal.length - 1] = optsVal[optsVal.length - 1].replace("]", "");
154
155 Map<String, String> options = new HashMap<String, String>();
156 for (int i = 0, o = 0; i < opts.length && o < optsVal.length; i++, o++) {
157 String key = opts[i].trim();
158 String val = optsVal[o].trim();
159 options.put(key, val);
160 }
161
162 Mail.addEntry(new Mail.MailEntry(timestamp, from, to, msg, msg2, options));
163 }
164
165 // Disconnect from database.
166 allMail.close();
167 query.close();
168 c.close();
169 }
170
171 final void loadMailDatabase() throws SQLException {
172 Path contactsPath = Paths.get(FrameIO.CONTACTS_PATH);
173 File[] contacts = contactsPath.toFile().listFiles();
174 for (int i = 0; i < contacts.length; i++) {
175 if (contacts[i].isDirectory()) {
176 Path contact = Paths.get(contacts[i].getAbsolutePath());
177 loadMailFromDirectory(contact);
178 }
179 }
180 }
181
182 final SecretKey getSecretKey(final String label, final String password) throws NoSuchAlgorithmException, KeyStoreException {
183
184 char[] password_ca = password.toCharArray();
185 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password_ca);
186
187 SecretKey secret_key;
188 try {
189 SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(label, entryPassword);
190 secret_key = entry.getSecretKey();
191
192 } catch (final UnrecoverableEntryException e) {
193 secret_key = null;
194 }
195
196 return secret_key;
197 }
198
199 final void putKey(final String label, final String password, final SecretKey key) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
200 final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
201 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
202 keyStore.setEntry(label, entry, entryPassword);
203 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
204 }
205
206 final boolean confirmIntergalaticNumber(final String username, final String email, final String intergalacticNumber) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException {
207 try {
208 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
209 final KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(email + username, entryPassword);
210 if (entry == null) {
211 return false;
212 } else if (entry.getSecretKey().getEncoded() == TRUE) {
213 keyStore.deleteEntry(email + username);
214 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
215 return true;
216 } else { return false; }
217 } catch (final UnrecoverableEntryException e) {
218 return false;
219 }
220 }
221
222 final String newIntergalacticNumber(final String username, final String email) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
223 // generate intergalactic number
224 final SecureRandom rand = new SecureRandom();
225 final byte[] intergalacticNumberBytes = new byte[20];
226 rand.nextBytes(intergalacticNumberBytes);
227 final String intergalacticNumber = Base64.getEncoder().encodeToString(intergalacticNumberBytes);
228
229 // store intergalactic number
230 final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(TRUE, SymmetricAlgorithm));
231 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
232 keyStore.setEntry(email + username, entry, entryPassword);
233 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
234
235 return intergalacticNumber;
236 }
237
238 final PublicKey getPublicKey(String username) throws InvalidKeySpecException, NoSuchAlgorithmException, FileNotFoundException {
239 // load in frame with public key on it.
240 String credentialsFramesetPath = FrameIO.CONTACTS_PATH + username + "-credentials" + File.separator;
241 if (!new File(credentialsFramesetPath).exists()) {
242 return null;
243 }
244 Scanner in = new Scanner(new File(credentialsFramesetPath + "credentials.inf"));
245 String credentialsFrameNumber = in.nextLine().replace(ExpReader.EXTENTION, "");
246 in.close();
247 Frame frame = FrameIO.LoadFrame(username + "-credentials" + credentialsFrameNumber, FrameIO.CONTACTS_PATH);
248 if (frame == null) {
249 return null;
250 }
251
252 // obtain public key from frame
253 Collection<Item> canditates = org.expeditee.auth.Actions.getByContent(frame, "PublicKey");
254 String keyEncoded = "";
255 for (Item i: canditates) {
256 if (i.getData() != null) {
257 keyEncoded = i.getData().get(0);
258 }
259 }
260 if (keyEncoded.isEmpty()) {
261 return null;
262 }
263 byte[] keyBytes = Base64.getDecoder().decode(keyEncoded);
264 return KeyFactory.getInstance(AsymmetricAlgorithm).generatePublic(new X509EncodedKeySpec(keyBytes));
265 }
266
267 final void markRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
268 KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(TRUE, SymmetricAlgorithm));
269 KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
270 keyStore.setEntry(username + "colleaguesRequested", entry, entryPassword);
271 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
272 }
273
274 final void clearRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
275 KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(FALSE, SymmetricAlgorithm));
276 KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
277 keyStore.setEntry(username + "colleaguesRequested", entry, entryPassword);
278 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), Constants.CREDENTIALS_KEYSTORE_PASSWORD.toCharArray());
279 }
280
281 final boolean hasRequestedColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
282 String alias = username + "colleaguesRequested";
283 if (!keyStore.containsAlias(alias)) {
284 return false;
285 } else {
286 KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
287 KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(alias, entryPassword);
288 return Arrays.equals(entry.getSecretKey().getEncoded(), TRUE);
289 }
290 }
291
292// final void putColleagues(String username, String[] colleagues) throws KeyStoreException {
293// String alias = username + "colleagues";
294// final SecretKeySpec secretKeySpec = new SecretKeySpec((colleagues[0] + System.getProperty("line.separator") + colleagues[1]).getBytes(), SymmetricAlgorithm);
295// KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(secretKeySpec);
296// KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
297// keyStore.setEntry(alias, entry, entryPassword);
298// }
299//
300// final String[] getColleagues(String username) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {
301// String alias = username + "colleagues";
302// if (!keyStore.containsAlias(alias)) {
303// return null;
304// } else {
305// KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(KeyList.PersonalKey.get().getText().toCharArray());
306// KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(alias, entryPassword);
307// byte[] colleaguesEncoded = entry.getSecretKey().getEncoded();
308// String colleagues = new String(colleaguesEncoded);
309// return colleagues.split(System.getProperty("line.separator"));
310// }
311// }
312
313 private static void setInputManagerWindowRoutines() {
314 InputManager manager = EcosystemManager.getInputManager();
315
316 // Refresh the layout when the window resizes
317 manager.addWindowEventListener(new WindowEventListener() {
318 @Override
319 public void onWindowEvent(WindowEventType type)
320 {
321 if (type != WindowEventType.WINDOW_RESIZED) {
322 return;
323 }
324 DisplayController.refreshWindowSize();
325 FrameIO.RefreshCacheImages();
326 for (Frame frame : DisplayController.getFrames()) {
327 if (frame != null) {
328 ItemUtils.Justify(frame);
329 frame.refreshSize();
330 }
331 }
332 DisplayController.requestRefresh(false);
333 }
334 });
335
336 manager.addWindowEventListener(new WindowEventListener() {
337 @Override
338 public void onWindowEvent(WindowEventType type)
339 {
340 if (type != WindowEventType.MOUSE_EXITED_WINDOW) {
341 return;
342 }
343 StandardGestureActions.mouseExitedWindow();
344 }
345 });
346
347 manager.addWindowEventListener(new WindowEventListener() {
348 @Override
349 public void onWindowEvent(WindowEventType type)
350 {
351 if (type != WindowEventType.MOUSE_ENTERED_WINDOW) {
352 return;
353 }
354 StandardGestureActions.mouseEnteredWindow();
355 }
356 });
357
358 manager.addWindowEventListener(new WindowEventListener() {
359 @Override
360 public void onWindowEvent(WindowEventType type)
361 {
362 if (type != WindowEventType.WINDOW_CLOSED) {
363 return;
364 }
365 if (Browser._theBrowser != null) {
366 Browser._theBrowser.exit();
367 }
368 }
369 });
370 }
371}
Note: See TracBrowser for help on using the repository browser.