source: trunk/src/org/expeditee/auth/account/Password.java@ 1419

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

Colleague -> User

File size: 17.2 KB
Line 
1package org.expeditee.auth.account;
2
3import java.io.File;
4import java.io.FileNotFoundException;
5import java.io.IOException;
6import java.nio.file.Path;
7import java.nio.file.Paths;
8import java.security.KeyStoreException;
9import java.security.NoSuchAlgorithmException;
10import java.security.SecureRandom;
11import java.security.cert.CertificateException;
12import java.sql.SQLException;
13import java.util.Base64;
14import java.util.Collection;
15import java.util.HashMap;
16import java.util.Iterator;
17import java.util.Map;
18import java.util.Properties;
19import java.util.Scanner;
20
21import javax.crypto.SecretKey;
22import javax.crypto.spec.SecretKeySpec;
23import javax.mail.Message;
24import javax.mail.MessagingException;
25import javax.mail.PasswordAuthentication;
26import javax.mail.Session;
27import javax.mail.Transport;
28import javax.mail.internet.AddressException;
29import javax.mail.internet.InternetAddress;
30import javax.mail.internet.MimeMessage;
31
32import org.expeditee.auth.AuthenticatorBrowser;
33import org.expeditee.auth.mail.Mail;
34import org.expeditee.auth.mail.Mail.MailEntry;
35import org.expeditee.auth.tags.AuthenticationTag;
36import org.expeditee.encryption.CryptographyConstants;
37import org.expeditee.gui.DisplayController;
38import org.expeditee.gui.Frame;
39import org.expeditee.gui.FrameIO;
40import org.expeditee.gui.MessageBay;
41import org.expeditee.items.Text;
42import org.expeditee.settings.UserSettings;
43import org.expeditee.settings.identity.passwordrecovery.Colleagues;
44import org.expeditee.settings.identity.secrets.KeyList;
45import org.expeditee.stats.Formatter;
46
47import com.codahale.shamir.Scheme;
48
49public class Password implements CryptographyConstants {
50 /**
51 * Changes the recorded password for a user in the key store; given the username signaling whose password to change, along with the existing and new password.
52 */
53 public static void changePassword(Map<AuthenticationTag, String> userdata) throws NoSuchAlgorithmException, KeyStoreException, FileNotFoundException, CertificateException, IOException, ClassNotFoundException, SQLException {
54 String username = userdata.get(AuthenticationTag.Username);
55 String password = userdata.get(AuthenticationTag.Password);
56 String newpassword = userdata.get(AuthenticationTag.NewPassword);
57
58 final SecretKey key = AuthenticatorBrowser.getInstance().getSecretKey(username, password);
59 if (key == null) {
60 MessageBay.errorMessage("The username + existing password combination was incorrect.");
61 } else {
62 AuthenticatorBrowser.getInstance().putKey(username, newpassword, key);
63 MessageBay.displayMessage("Password changed successfully.");
64 DisplayController.setCurrentFrame(FrameIO.LoadFrame("multiuser1"), true);
65 }
66 }
67
68 /**
69 * Generates a intergalaictic number for a specified user and emails that number using the specified email.
70 * @param userData
71 */
72 public static void generateAndDeliverIntergalacticNumber(Map<AuthenticationTag, String> userData) {
73 String username = userData.get(AuthenticationTag.Username);
74 String email = userData.get(AuthenticationTag.Email);
75 try {
76 // Generate message text.
77 String intergalacticNumber = AuthenticatorBrowser.getInstance().newIntergalacticNumber(username, email);
78 String nl = System.getProperty("line.separator");
79 StringBuilder sb = new StringBuilder();
80 sb.append("You are receiving this email because someone is attempting to reset your Expeditee password." + nl);
81 sb.append("If you did not make this request then no action is required." + nl);
82 sb.append("If it was you who made this request, the following string of characters is your intergalactic number: " + intergalacticNumber + nl);
83
84 sendEmail(email, sb);
85 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | ClassNotFoundException
86 | IOException | SQLException | MessagingException e) {
87 e.printStackTrace();
88 }
89 }
90
91 /**
92 * Confirms that the specified intergalaictic number matches the one of file for the specified username.
93 * Passing this test it then alerts the users pw colleagues through a one-off secure Expeditee message.
94 * @param tags
95 */
96 public static void confirmIntergalacticNumberAndAlertTrustedUsers(Map<AuthenticationTag, String> tags) {
97 // Confirm intergalactic numbers match
98 String username = tags.get(AuthenticationTag.Username);
99 String intergalacticNumber = tags.get(AuthenticationTag.IntergalacticNumber);
100 boolean match = false;
101 try {
102 match = AuthenticatorBrowser.getInstance().confirmIntergalaticNumber(username, intergalacticNumber);
103 } catch (NoSuchAlgorithmException | KeyStoreException | CertificateException | ClassNotFoundException
104 | IOException | SQLException e) {
105 e.printStackTrace();
106 return;
107 }
108 if (!match) {
109 MessageBay.errorMessage("The provided identity number does not match the one stored on file.");
110 return;
111 }
112
113 // Get colleagues to distribute messages too.
114 String[] colleagues = getPasswordColleaguesFromUsername(username);
115 // Send secure message to colleague one
116 String colleagueOne = colleagues[0];
117 String time = Formatter.getDateTime();
118 String topic = "Password Recovery for " + username;
119 String message = "Your colleague " + username + " would like you to help them recover access to their account.";
120 Map<String, String> options = new HashMap<String, String>();
121 options.put("Provide assistance", "AuthEmailPasswordShare " + username);
122 MailEntry mail = new MailEntry(time, username, colleagueOne, topic, message, options);
123 Mail.sendOneOffMail(mail, colleagueOne, Base64.getDecoder().decode(intergalacticNumber));
124
125 // Send secure message to colleague two
126 String colleagueTwo = colleagues[1];
127 Mail.sendOneOffMail(mail, colleagueTwo, Base64.getDecoder().decode(intergalacticNumber));
128
129 String nl = System.getProperty("line.separator");
130 StringBuilder sb = new StringBuilder();
131 sb.append("You are receiving this email because one of your Expeditee contacts has sent you a one-off secure message." + nl);
132 sb.append("When you log into Expeditee and check your mail it will be there waiting for you." + nl);
133 sb.append("You will need the following key to read this message: " + nl);
134 sb.append(intergalacticNumber);
135 try {
136 // Send email with key to colleague one
137 String colleagueOneEmail = colleagues[2];
138 sendEmail(colleagueOneEmail, sb);
139 // Send email with key to colleague two
140 String colleagueTwoEmail = colleagues[3];
141 sendEmail(colleagueTwoEmail, sb);
142
143 MessageBay.displayMessage("Identity confirmed. Your trusted contacts have been notified via one-off secure Expeditee message. "
144 + "You will recieve an email message with a password share from each once they have completed their part of the process. Enter them below.");
145 } catch (MessagingException e) {
146 e.printStackTrace();
147 }
148 }
149
150 private static String[] getPasswordColleaguesFromUsername(String username) {
151 Path credentialsFilePath = Paths.get(FrameIO.PROFILE_PATH).resolve(username).resolve("pwcolleagues.inf");
152 String fileName = null;
153 if (credentialsFilePath.toFile().exists()) {
154 try (Scanner in = new Scanner(credentialsFilePath)) {
155 fileName = in.nextLine();
156 } catch (IOException e) {
157 MessageBay.errorMessage("Unable to find trusted users contact frame for specified user, are they registered on this computer?");
158 return null;
159 }
160 } else {
161 MessageBay.errorMessage("Unable to find trusted users contact frame for specified user, are they registered on this computer?");
162 return null;
163 }
164
165 int number = Integer.parseInt(fileName.replace(".exp", ""));
166 Frame pwColleagueFrame = FrameIO.LoadFrame(username + number, FrameIO.PROFILE_PATH);
167 Collection<Text> textItems = pwColleagueFrame.getTextItems();
168 textItems.removeIf(text -> !text.getText().startsWith("Colleague"));
169
170 String[] ret = new String[4];
171 Iterator<Text> it = textItems.iterator();
172 while(it.hasNext()) {
173 String content = it.next().getText().toLowerCase().trim();
174 if (content.contains("colleague_one:")) {
175 ret[0] = content.replace("colleague_one:", "").trim();
176 } else if (content.contains("colleague_two:")) {
177 ret[1] = content.replace("colleague_two:", "").trim();
178 }
179 }
180
181 // find colleague one email
182 Path credentialsDirectoryPath = UserSettings.PublicAndPrivateResources
183 ? Paths.get(FrameIO.PARENT_FOLDER).resolve("resources-" + username)
184 : Paths.get(FrameIO.PARENT_FOLDER);
185 credentialsDirectoryPath = credentialsDirectoryPath.resolve("contacts").resolve(ret[0] + "-credentials");
186 try (Scanner in = new Scanner(credentialsDirectoryPath.resolve("credentials.inf").toFile())) {
187 int parseInt = Integer.parseInt(in.nextLine().replace(".exp", ""));
188 Frame frame = FrameIO.LoadFrame(ret[0] + "-credentials" + parseInt, credentialsDirectoryPath.toAbsolutePath().getParent().toString() + File.separator);
189 textItems = frame.getTextItems();
190 textItems.removeIf(text -> !text.getText().startsWith("Email:"));
191 ret[2] = textItems.iterator().next().getText().replace("Email:", "").trim();
192 } catch (FileNotFoundException e) {
193 MessageBay.errorMessage("You do not appear to have contact with your nominated password colleague: " + ret[0]);
194 return null;
195 }
196
197
198 // find colleague two email
199 credentialsDirectoryPath = UserSettings.PublicAndPrivateResources
200 ? Paths.get(FrameIO.PARENT_FOLDER).resolve("resources-" + username)
201 : Paths.get(FrameIO.PARENT_FOLDER);
202 credentialsDirectoryPath = credentialsDirectoryPath.resolve("contacts").resolve(ret[1] + "-credentials");
203 try (Scanner in = new Scanner(credentialsDirectoryPath.resolve("credentials.inf").toFile())) {
204 int parseInt = Integer.parseInt(in.nextLine().replace(".exp", ""));
205 Frame frame = FrameIO.LoadFrame(ret[1] + "-credentials" + parseInt, credentialsDirectoryPath.toAbsolutePath().getParent().toString() + File.separator);
206 textItems = frame.getTextItems();
207 textItems.removeIf(text -> !text.getText().startsWith("Email:"));
208 ret[3] = textItems.iterator().next().getText().replace("Email:", "").trim();
209 } catch (FileNotFoundException e) {
210 MessageBay.errorMessage("You do not appear to have contact with your nominated password colleague: " + ret[1]);
211 return null;
212 }
213
214 return ret;
215 }
216
217
218 public static void sendEmail(String email, StringBuilder sb) throws MessagingException, AddressException {
219 // Establish properties for email.
220 Properties properties = System.getProperties();
221 properties.setProperty("mail.transport.protocol", "smtp");
222 properties.setProperty("mail.smtp.host", "smtp.gmail.com");
223 properties.setProperty("mail.smtp.port", "465");
224 properties.setProperty("mail.smtp.starttls.enable", "true");
225 properties.setProperty("mail.smtp.auth", "true");
226 properties.setProperty("mail.smtp.debug", "true");
227 properties.setProperty("mail.smtp.auth", "true");
228 properties.setProperty("mail.smtp.socketFactory.port", "465");
229 properties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
230 properties.setProperty("mail.smtp.socketFactory.fallback", "false");
231
232 Session session = Session.getDefaultInstance(properties, new javax.mail.Authenticator() {
233 @Override
234 protected PasswordAuthentication getPasswordAuthentication() {
235 return new PasswordAuthentication("noreply.expeditee", "intergalacticnumber");
236 };
237 });
238
239 // construct email message
240 final MimeMessage message = new MimeMessage(session);
241 message.setFrom(new InternetAddress("[email protected]"));
242 message.addRecipient(Message.RecipientType.TO, new InternetAddress(email));
243 message.setSubject("Expeditee Password Recovery");
244 message.setText(sb.toString());
245
246 // send email message
247 Transport.send(message);
248 }
249
250 public static void setPWColleagues(String colleagueOne, String colleagueTwo) {
251 // Get needed text items.
252 Frame pwRecoveryFrame = FrameIO.LoadFrame(UserSettings.UserName.get() + AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME);
253 Collection<Text> textItems = pwRecoveryFrame.getTextItems();
254 textItems.removeIf(t -> !t.getText().toLowerCase().startsWith("colleague"));
255
256 // Find colleague one and two text items. Set appropriate values.
257 Iterator<Text> it = textItems.iterator();
258 while (it.hasNext()) {
259 Text text = it.next();
260 if (text.getText().toLowerCase().startsWith("colleague_one:")) {
261 text.setText("Colleague_one: " + colleagueOne);
262 Colleagues.User_One.set(colleagueOne);
263 } else if (text.getText().toLowerCase().startsWith("colleague_two:")) {
264 text.setText("Colleague_two:" + colleagueTwo);
265 Colleagues.User_Two.set(colleagueTwo);
266 }
267 }
268 FrameIO.ForceSaveFrame(pwRecoveryFrame);
269
270 // Key to split and distribute
271 String fullKey = KeyList.PersonalKey.get().getData().get(0);
272 byte[] keyBytes = Base64.getDecoder().decode(fullKey);
273
274 // Initialise Shamir
275 int totalShares = 2;
276 int requiredShares = 2;
277 Scheme scheme = new Scheme(new SecureRandom(), totalShares, requiredShares);
278
279 // Create shares
280 Map<Integer, byte[]> shares = scheme.split(keyBytes);
281 String colleagueOneShare = Base64.getEncoder().encodeToString(shares.get(1));
282 String colleagueTwoShare = Base64.getEncoder().encodeToString(shares.get(2));
283
284 // Distribute share zero to colleague one
285 String time = org.expeditee.stats.Formatter.getDateTime();
286 String sender = UserSettings.UserName.get();
287 String topic = "Please help me secure my Expeditee account.";
288 String message = "Run the below action to store a secret key that will help me recover access to my account should I ever loose it.";
289 Map<String, String> options = new HashMap<String, String>();
290 options.put("Store Secret Key for " + sender, "AuthAddSecretKey " + sender + "PersonalKeyShare " + colleagueOneShare);
291 MailEntry mail = new MailEntry(time, sender, colleagueOne, topic, message, options);
292 Mail.sendMail(mail, colleagueOne);
293
294 // Distribute share one to colleague two
295 options = new HashMap<String, String>();
296 options.put("Store Secret Key for " + sender, "AuthAddSecretKey " + sender + "PersonalKeyShare " + colleagueTwoShare);
297 mail = new MailEntry(time, sender, colleagueTwo, topic, message, options);
298 Mail.sendMail(mail, colleagueTwo);
299
300 MessageBay.displayMessage("You PW Colleagues have been set to " + colleagueOne + " and " + colleagueTwo + ". "
301 + "They have been sent a Expeditee mail that they can use to store a share of your secret key.");
302 }
303
304 public static void emailPasswordShare(String colleagueName) {
305 Path credentialsDirectoryPath = Paths.get(FrameIO.CONTACTS_PATH).resolve(colleagueName + "-credentials");
306 String colleagueEmail = null;
307 try (Scanner in = new Scanner(credentialsDirectoryPath.resolve("credentials.inf").toFile())) {
308 int parseInt = Integer.parseInt(in.nextLine().replace(".exp", ""));
309 Frame frame = FrameIO.LoadFrame(colleagueName + "-credentials" + parseInt, credentialsDirectoryPath.toAbsolutePath().getParent().toString() + File.separator);
310 Collection<Text> textItems = frame.getTextItems();
311 textItems.removeIf(text -> !text.getText().startsWith("Email:"));
312 colleagueEmail = textItems.iterator().next().getText().replace("Email:", "").trim();
313 } catch (FileNotFoundException e) {
314 MessageBay.errorMessage("You do not appear to have contact with: " + colleagueName);
315 return;
316 }
317
318 Frame secretsFrame = FrameIO.LoadFrame(UserSettings.UserName.get() + AuthenticatorBrowser.SECRETS_FRAME);
319 Collection<Text> textItems = secretsFrame.getTextItems();
320 textItems.removeIf(text -> !text.getText().toLowerCase().equals(colleagueName + "personalkeyshare"));
321 String key = textItems.iterator().next().getData().get(0);
322
323 String nl = System.getProperty("line.separator");
324 StringBuilder sb = new StringBuilder();
325 sb.append("In responce to your request for assistance regaining access to your Expeditee account, your colleague " + UserSettings.UserName.get() + " has provided you with the following key share:" + nl);
326 sb.append(key + nl);
327
328 try {
329 sendEmail(colleagueEmail, sb);
330 MessageBay.displayMessage("Your share of " + colleagueName + "'s password has been sent to their public email address.");
331 } catch (MessagingException e) {
332 MessageBay.errorMessage("An error occured sending a email to your colleage " + colleagueName + " with the email " + colleagueEmail);
333 }
334 }
335
336 public static void regainAccountAccess(Map<AuthenticationTag, String> userData) {
337 // Store shares in map
338 Map<Integer, byte[]> contributingParts = new HashMap<Integer, byte[]>();
339 contributingParts.put(1, Base64.getDecoder().decode(userData.get(AuthenticationTag.PasswordSliceOne)));
340 contributingParts.put(2, Base64.getDecoder().decode(userData.get(AuthenticationTag.PasswordSliceTwo)));
341
342 // initialise shamir
343 int totalShares = 2;
344 int requiredShares = 2;
345 Scheme scheme = new Scheme(new SecureRandom(), totalShares, requiredShares);
346
347 // perform joining
348 byte[] join = scheme.join(contributingParts);
349
350 try {
351 AuthenticatorBrowser.getInstance().putKey(userData.get(AuthenticationTag.Username), userData.get(AuthenticationTag.NewPassword), new SecretKeySpec(join, SymmetricAlgorithm));
352 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | ClassNotFoundException
353 | IOException | SQLException e) {
354 e.printStackTrace();
355 }
356
357 MessageBay.displayMessage("Your new password has been set.");
358 }
359}
Note: See TracBrowser for help on using the repository browser.