source: trunk/src/org/expeditee/auth/AuthenticatorBrowser.java@ 1540

Last change on this file since 1540 was 1540, checked in by bnemhaus, 4 years ago

Removed reliance of System.getProperty("user.name") by introducing some functions and a variable to Browser to be used instead. All previous occurrences of System.getProperty("user.name") now use these functions.

At the time, introduced new piping into various functions related to the creation and management of profile frames that distinguished between a profile name and a user name. This allows functions to be more specific about what is being used. For example, when modifying the users profile frames (in the profiles directory) that users profile name can be used instead of naming the variable 'username'. This distinction is important because while username's can end with numbers, profile names cannot and therefore get an 'A' on the end.

File size: 15.7 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.Paths;
10import java.security.KeyFactory;
11import java.security.KeyStore;
12import java.security.KeyStore.SecretKeyEntry;
13import java.security.KeyStoreException;
14import java.security.NoSuchAlgorithmException;
15import java.security.PublicKey;
16import java.security.SecureRandom;
17import java.security.UnrecoverableEntryException;
18import java.security.cert.CertificateException;
19import java.security.spec.InvalidKeySpecException;
20import java.security.spec.X509EncodedKeySpec;
21import java.sql.SQLException;
22import java.util.Arrays;
23import java.util.Base64;
24import java.util.Collection;
25import java.util.Scanner;
26import java.util.stream.Stream;
27
28import javax.crypto.SecretKey;
29import javax.crypto.spec.SecretKeySpec;
30
31import org.expeditee.actions.Actions;
32import org.expeditee.core.Dimension;
33import org.expeditee.core.Point;
34import org.expeditee.encryption.CryptographyConstants;
35import org.expeditee.gio.EcosystemManager;
36import org.expeditee.gio.GraphicsManager;
37import org.expeditee.gio.InputManager;
38import org.expeditee.gio.InputManager.WindowEventListener;
39import org.expeditee.gio.InputManager.WindowEventType;
40import org.expeditee.gio.gesture.StandardGestureActions;
41import org.expeditee.gui.Browser;
42import org.expeditee.gui.DisplayController;
43import org.expeditee.gui.Frame;
44import org.expeditee.gui.FrameIO;
45import org.expeditee.gui.FrameUtils;
46import org.expeditee.gui.MessageBay;
47import org.expeditee.io.ExpReader;
48import org.expeditee.items.Item;
49import org.expeditee.items.ItemUtils;
50import org.expeditee.items.Text;
51import org.expeditee.settings.Settings;
52import org.expeditee.settings.UserSettings;
53import org.expeditee.settings.identity.secrets.KeyList;
54
55public final class AuthenticatorBrowser extends Browser implements CryptographyConstants {
56
57 // The frame number of the frame containing the current authenticated users public key.
58 public static int CREDENTIALS_FRAME = -1;
59 public static int PASSWORD_RECOVERY_FRAME = -1;
60 public static int SECRETS_FRAME = -1;
61 public static final String ADMINACCOUNT = "authadmin";
62 public static final String PROFILEENCRYPTIONLABEL = "Profile";
63
64 public static boolean Authenticated = false;
65
66 private KeyStore keyStore = KeyStore.getInstance(KeystoreType);
67 public static String USER_NOBODY = "nobody";
68
69 private static final byte[] TRUE = "yes".getBytes();
70 private static final byte[] FALSE = "no".getBytes();
71 private static final String KEYSTOREFILENAME = "keystore.ks" + File.separator;
72
73 private static AuthenticatorBrowser instance;
74
75 public static AuthenticatorBrowser getInstance() throws KeyStoreException, FileNotFoundException, NoSuchAlgorithmException, CertificateException, IOException, ClassNotFoundException, SQLException {
76 if (instance == null) { instance = new AuthenticatorBrowser(); }
77 return instance;
78 }
79
80 public static boolean isAuthenticationRequired() {
81 return Boolean.getBoolean("expeditee.authentication");
82 }
83
84 public static boolean isAuthenticated() {
85 //return isAuthenticationRequired() && !UserSettings.UserName.get().equals(AuthenticatorBrowser.USER_NOBODY);
86 return isAuthenticationRequired() && !Browser.getExpediteeUserName().equals(AuthenticatorBrowser.USER_NOBODY);
87 }
88
89 private AuthenticatorBrowser() throws KeyStoreException, FileNotFoundException, IOException, NoSuchAlgorithmException, CertificateException, ClassNotFoundException, SQLException {
90 super("Authentication");
91 UserSettings.setupDefaultFolders();
92
93 // initialise keystore and actions
94 loadKeystore();
95 Actions.LoadMethods(org.expeditee.auth.Actions.class);
96 Actions.LoadMethods(org.expeditee.encryption.Actions.class);
97
98 // Does the account Authentication.ADMINACCOUNT exist?
99 // If not then we have get the user to assign a password to it.
100 if (!keyStore.containsAlias(AuthenticatorBrowser.ADMINACCOUNT)) {
101 new File(FrameIO.PARENT_FOLDER).mkdirs();
102 protectAdmin();
103 }
104
105 // draw the window
106 GraphicsManager g = EcosystemManager.getGraphicsManager();
107 g.setWindowLocation(new Point(50, 50));
108 DisplayController.Init();
109 g.setWindowSize(new Dimension(UserSettings.InitialWidth.get(), UserSettings.InitialHeight.get()));
110 setInputManagerWindowRoutines();
111
112 // Load documentation and start pages
113 FrameUtils.extractResources(false);
114
115 // Load fonts before loading any frames so the items on the frames will be able to access their fonts
116 Text.InitFonts();
117
118 // initialing settings does not require a user profile established
119 Settings.Init();
120
121 // Ensure messages go to public directory whilst we are not logged into an account.
122 FrameIO.MESSAGES_PATH = Paths.get(FrameIO.PARENT_FOLDER).resolve("resources-public").resolve("messages").toString() + File.separator;
123
124 // navigate to authentication frame
125 Frame authFrame = FrameIO.LoadFrame("authentication1");
126 DisplayController.setCurrentFrame(authFrame, true);
127
128 // set initial values
129 Stream<Text> usernameItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtUsername"));
130 Stream<Text> passwordItemsStream = authFrame.getTextItems().stream().filter(t -> t.getData() != null && t.getData().contains("txtPassword"));
131 usernameItemsStream.forEach(txtUsername -> txtUsername.setText(System.getProperty("startinguser.name", "")));
132 passwordItemsStream.forEach(txtPassword -> { txtPassword.setText(""); txtPassword.invalidateAll(); });
133
134 MessageBay.warningMessages(org.expeditee.actions.Actions.Init());
135
136 // class load database classes
137 Class.forName("org.sqlite.JDBC");
138 }
139
140 private void protectAdmin() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
141 FileNotFoundException, IOException {
142 // Fetch desired password
143 @SuppressWarnings("resource")
144 Scanner in = new Scanner(System.in);
145 System.out.println("No administrative password set.");
146 boolean passwordIsSet = false;
147
148 for (int i = 0; i < 3; i++) {
149 System.out.print("Please enter it now: ");
150 System.out.flush();
151 String password = in.nextLine();
152 System.out.print("And again: ");
153 System.out.flush();
154 if (in.nextLine().equals(password)) {
155 // Register account.
156 putKey(ADMINACCOUNT, password, new SecretKeySpec("null".getBytes(), AsymmetricAlgorithm));
157 //in.close();
158 passwordIsSet = true;
159 break;
160 } else {
161 System.out.println("Mismatched passwords, let's try that again.");
162 }
163 }
164
165 if (!passwordIsSet) {
166 System.out.println("Failed to set an admin password. Exiting Expeditee.");
167 System.exit(1);
168 }
169 }
170
171 private void loadKeystore()
172 throws IOException, NoSuchAlgorithmException, CertificateException, FileNotFoundException {
173 final File keyStoreFile = new File(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME);
174 if (!keyStoreFile.exists()) {
175 keyStore.load(null, "ExpediteeAuthPassword".toCharArray());
176 } else {
177 try (final InputStream in = new FileInputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME)) {
178 keyStore.load(in, "ExpediteeAuthPassword".toCharArray());
179 }
180 }
181 }
182
183 public final SecretKey getSecretKey(final String label, final String password) throws NoSuchAlgorithmException, KeyStoreException {
184
185 char[] password_ca = password.toCharArray();
186
187 SecretKey secret_key;
188 try {
189 secret_key = (SecretKey) keyStore.getKey(label, password_ca);
190 } catch (final UnrecoverableEntryException e) {
191 return null;
192 }
193
194 return secret_key;
195 }
196
197 public final void putKey(final String label, final String password, final SecretKey key) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
198 final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(key);
199 final KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(password.toCharArray());
200 keyStore.setEntry(label, entry, entryPassword);
201 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
202 }
203
204 public final boolean confirmIntergalaticNumber(final String username, final String intergalacticNumber) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException {
205 try {
206 KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
207 KeyStore.SecretKeyEntry entry = (SecretKeyEntry) keyStore.getEntry(username + "_IntergalacticNumber", entryPassword);
208 if (entry == null) {
209 return false;
210 } else if (Arrays.equals(entry.getSecretKey().getEncoded(), TRUE)) {
211 keyStore.deleteEntry(username + "_IntergalacticNumber");
212 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
213 return true;
214 } else {
215 return false;
216 }
217 } catch (final UnrecoverableEntryException e) {
218 return false;
219 }
220 }
221
222 public final String newIntergalacticNumber(final String username, final String email) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException {
223 // generate intergalactic number
224 SecureRandom rand = new SecureRandom();
225 byte[] intergalacticNumberBytes = new byte[16];
226 rand.nextBytes(intergalacticNumberBytes);
227 String intergalacticNumber = Base64.getEncoder().encodeToString(intergalacticNumberBytes);
228
229 // store intergalactic number
230 KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(new SecretKeySpec(TRUE, SymmetricAlgorithm));
231 KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(intergalacticNumber.toCharArray());
232 keyStore.setEntry(username + "_IntergalacticNumber", entry, entryPassword);
233 keyStore.store(new FileOutputStream(FrameIO.PARENT_FOLDER + KEYSTOREFILENAME), "ExpediteeAuthPassword".toCharArray());
234
235 return intergalacticNumber;
236 }
237
238 public 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 public 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), "ExpediteeAuthPassword".toCharArray());
272 }
273
274 public 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), "ExpediteeAuthPassword".toCharArray());
279 }
280
281 public 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.