source: trunk/src/org/expeditee/auth/account/Create.java@ 1402

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

Permission is now a triple rather than a pair. The new second bit is not yet used but will be used for group level permissions.

gazumpts

File size: 13.2 KB
Line 
1package org.expeditee.auth.account;
2
3import java.io.File;
4import java.io.FileWriter;
5import java.io.IOException;
6import java.nio.file.Path;
7import java.nio.file.Paths;
8import java.security.KeyPair;
9import java.security.KeyPairGenerator;
10import java.security.KeyStoreException;
11import java.security.NoSuchAlgorithmException;
12import java.security.SecureRandom;
13import java.security.cert.CertificateException;
14import java.sql.SQLException;
15import java.util.Base64;
16import java.util.Collection;
17import java.util.HashMap;
18import java.util.Map;
19import java.util.Random;
20import java.util.function.Consumer;
21
22import javax.crypto.SecretKey;
23import javax.crypto.spec.SecretKeySpec;
24
25import org.apollo.io.AudioPathManager;
26import org.expeditee.agents.ExistingFramesetException;
27import org.expeditee.agents.InvalidFramesetNameException;
28import org.expeditee.auth.Actions;
29import org.expeditee.auth.AuthenticatorBrowser;
30import org.expeditee.auth.tags.AuthenticationTag;
31import org.expeditee.core.Colour;
32import org.expeditee.encryption.CryptographyConstants;
33import org.expeditee.gui.DisplayController;
34import org.expeditee.gui.Frame;
35import org.expeditee.gui.FrameIO;
36import org.expeditee.gui.MessageBay;
37import org.expeditee.gui.MessageBay.Progress;
38import org.expeditee.io.ExpReader;
39import org.expeditee.items.Item;
40import org.expeditee.items.PermissionTriple;
41import org.expeditee.items.Text;
42import org.expeditee.items.UserAppliedPermission;
43import org.expeditee.setting.GenericSetting;
44import org.expeditee.setting.Setting;
45import org.expeditee.setting.TextSetting;
46import org.expeditee.settings.UserSettings;
47import org.expeditee.settings.folders.FolderSettings;
48import org.expeditee.settings.identity.secrets.KeyList;
49
50public class Create implements CryptographyConstants {
51
52 /**
53 * Create a user account using the specified information in userdata. Creates and stores user keys.
54 * @param userdata Should contain username, password and email.
55 */
56 public static CreateResult createAccount(Map<AuthenticationTag, String> userdata) {
57 // Track progress
58 String message = "Creating new user account...";
59 int progress = 0;
60 int step = 16;
61
62 // Extract user details
63 String username = userdata.get(AuthenticationTag.Username);
64 String password = userdata.get(AuthenticationTag.Password);
65 String email = userdata.get(AuthenticationTag.Email);
66
67 Progress progressBar = MessageBay.displayProgress(message);
68 progress = progress(message + "Generating Keys.", progress, step, progressBar);
69
70 // Generate keys
71 // Personal key
72 String personalKey = generatePersonalKey(username, password);
73 if (personalKey == null) {
74 return CreateResult.ErrorSymmetricKey;
75 }
76 // Public and private keys
77 String[] keys = generateAsymmetricKeys();
78 if (keys == null) {
79 return CreateResult.ErrorAsymmetricKeys;
80 }
81 String privateKey = keys[0];
82 String publicKey = keys[1];
83
84 progress = progress(message + "Creating Profile Frameset.", progress, step, progressBar);
85
86 // Update in memory settings
87 System.setProperty("user.name", username);
88 UserSettings.UserName.set(username);
89 UserSettings.ProfileName.set(username);
90 UserSettings.setupDefaultFolders();
91
92 Frame profile;
93 try {
94 profile = createNewProfile(username, email, personalKey, privateKey, publicKey);
95 } catch (InvalidFramesetNameException | ExistingFramesetException e) {
96 return CreateResult.ErrorNewProfile;
97 }
98
99 if (AuthenticatorBrowser.CREDENTIALS_FRAME == -1) {
100 return CreateResult.ErrorCredentialsFrame;
101 }
102
103 progress = progress(message + "Establishing user credentials.", progress, step, progressBar);
104
105 // Create credentials
106 boolean success = setupCredentialsFrameAndINFs(username, profile);
107 if (!success) {
108 return CreateResult.ErrorIODuringCredentialsFrameSetup;
109 }
110
111 progress = progress(message + "Creating Individual Space.", progress, step, progressBar);
112
113 // Copy private resources to personal area
114 Path personalResources = createPersonalArea(username);
115
116 progress = progress(message + "Creating Space For Dead Drops.", progress, step, progressBar);
117
118 createDeaddropsArea(personalResources);
119
120 System.err.println("**** Hardwired call in Apollo's AuthioPathManager");
121 AudioPathManager.activateAndScanAudioDir(); // ****
122
123 progress = progress(message + "Done.", progress, step, progressBar);
124
125 return CreateResult.SuccessCreateAccount;
126 }
127
128 public enum CreateResult {
129 SuccessCreateAccount ("Account created."),
130 SuccessAlternativeAccount ("Alternative access to account established."),
131 ErrorSymmetricKey ("An error occured while trying to generate your personal key."),
132 ErrorAsymmetricKeys ("An error occured while trying to generate asymmetric keys."),
133 ErrorNewProfile ("An error occured while creating the profile frames."),
134 ErrorCredentialsFrame ("Unable to establish credentials frame for new profile frame."),
135 ErrorIODuringCredentialsFrameSetup ("An error occured during the setup of the new users credentials frame.");
136
137 private String message = null;
138
139 private CreateResult(String message) {
140 this.message = message;
141 }
142
143 public String toString() {
144 return message;
145 }
146 }
147
148 private static int progress(String message, int progress, int step, Progress progressBar) {
149 try {
150 progressBar.UpdateMessage(message, progress += step);
151 } catch (Exception e) {
152 e.printStackTrace();
153 }
154 DisplayController.refreshBayArea();
155 return progress;
156 }
157
158 private static void createDeaddropsArea(Path personalResources) {
159 File deadDropsDir = new File(personalResources.resolve("deaddrops").toAbsolutePath().toString());
160 deadDropsDir.mkdir();
161 }
162
163 private static Path createPersonalArea(String username) {
164 Path personalResources = UserSettings.PublicAndPrivateResources ? FrameIO.setupPersonalResources(username) : Paths.get(FrameIO.PARENT_FOLDER);
165
166 File contactsDir = new File(personalResources.resolve("contacts").toAbsolutePath().toString());
167 contactsDir.mkdir();
168 return personalResources;
169 }
170
171 private static boolean setupCredentialsFrameAndINFs(String username, Frame profile) {
172 try {
173 File credentialsDir = new File(profile.getFramesetPath() + username + "-credentials");
174 credentialsDir.mkdir();
175 // credentials.inf file.
176 String credentialsPath = credentialsDir.getAbsolutePath() + File.separator + "credentials.inf";
177 File credentialsFile = new File(credentialsPath);
178 credentialsFile.createNewFile();
179 FileWriter out = new FileWriter(credentialsFile);
180 out.write(AuthenticatorBrowser.CREDENTIALS_FRAME + ".exp");
181 out.flush();
182 out.close();
183 // migrate credentials frame
184 Frame credentialsFrame = FrameIO.LoadFrame(username + AuthenticatorBrowser.CREDENTIALS_FRAME);
185 Path destinationDirectory = Paths.get(credentialsDir.getAbsolutePath());
186 Path destinationFile = destinationDirectory.resolve(AuthenticatorBrowser.CREDENTIALS_FRAME + ExpReader.EXTENTION);
187 FrameIO.migrateFrame(credentialsFrame, destinationFile);
188 // pwcolleagues.inf file.
189 File pwColleaguesFile = Paths.get(FrameIO.PROFILE_PATH).resolve(username).resolve("pwcolleagues.inf").toFile();
190 pwColleaguesFile.createNewFile();
191 out = new FileWriter(pwColleaguesFile);
192 out.write(AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME + ".exp");
193 out.flush();
194 out.close();
195 return true;
196 } catch (IOException e) {
197 return false;
198 }
199 }
200
201 private static Frame createNewProfile(String username, String email, String personalKey, String privateKey,
202 String publicKey) throws InvalidFramesetNameException, ExistingFramesetException {
203 // Establish the initial settings for the created user.
204 Map<String, Setting> initialSettings = new HashMap<String, Setting>();
205 initialSettings.put("settings.identity.secrets.PersonalKey", constructTextSetting("The AES key used to secure your profile frame - do not share with anyone!", "PersonalKey", personalKey));
206 initialSettings.put("settings.identity.secrets.PrivateKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key - do not share with anyone!", "PrivateKey", privateKey));
207 initialSettings.put("settings.identity.PublicKey", constructTextSetting("The RSA key used to decrypt things encrypted with your RSA public key.", "PublicKey", publicKey));
208 initialSettings.put("settings.identity.Email", constructGenericSetting(String.class, "Your public-facing email address.", "Email", email, username));
209 initialSettings.put("settings.UserSettings.UserName", constructGenericSetting(String.class, "UserName", "UserName", username, username));
210 initialSettings.put("settings.UserSettings.ProfileName", constructGenericSetting(String.class, "ProfileName", "ProfileName", username, username));
211 initialSettings.put("settings.UserSettings.HomeFrame", constructGenericSetting(String.class, "The home frame", "HomeFrame", username + 1, username));
212 initialSettings.put("org.expeditee.gui.folders.FolderSettings.FrameDirs", FolderSettings.FrameDirs);
213 initialSettings.put("org.expeditee.gui.folders.FolderSettings.ImageDirs", FolderSettings.ImageDirs);
214 initialSettings.put("org.expeditee.gui.folders.FolderSettings.AudioDirs", FolderSettings.AudioDirs);
215
216 // Record the credentials frame number and password colleagues frame
217 Map<String, Consumer<Frame>> notifiers = new HashMap<String, Consumer<Frame>>();
218 notifiers.put("settings.identity", frame -> {
219 AuthenticatorBrowser.CREDENTIALS_FRAME = frame.getNumber();
220 frame.addToData("MultiuserCredentials");
221 Collection<Text> textItems = frame.getTextItems();
222 for (Text t: textItems) {
223 if (t.getText().equals("Secrets")) {
224 t.setPermission(new PermissionTriple(UserAppliedPermission.followLinks, UserAppliedPermission.denied, UserAppliedPermission.denied));
225 break;
226 }
227 }
228 });
229 notifiers.put("settings.identity.passwordrecovery", frame -> {
230 frame.addToData("PasswordColleagues");
231 AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME = frame.getNumber();
232 });
233 notifiers.put("settings.identity.secrets", frame -> {
234 frame.addToData("SecretsFrame");
235 AuthenticatorBrowser.SECRETS_FRAME = frame.getNumber();
236 });
237
238 // Create users profile
239 Frame profile = FrameIO.CreateNewProfile(username, initialSettings, notifiers);
240 int lastNumber = FrameIO.getLastNumber(profile.getFramesetName());
241 for (int i = 1; i <= lastNumber; i++) {
242 Frame f = FrameIO.LoadFrame(profile.getFramesetName() + i);
243 Text titleItem = f.getTitleItem();
244 if (i == 1 && titleItem != null) {
245 titleItem.delete();
246 f.setBackgroundColor(new Colour(1, 1, 0.39f));
247 }
248 f.setOwner(username);
249 f.getAllItems().stream().forEach(item -> item.setOwner(username));
250 f.setChanged(true);
251 if (f.getNumber() != AuthenticatorBrowser.CREDENTIALS_FRAME &&
252 f.getNumber() != AuthenticatorBrowser.PASSWORD_RECOVERY_FRAME) {
253 f.setEncryptionLabel(AuthenticatorBrowser.PROFILEENCRYPTIONLABEL);
254 }
255 Collection<Item> secretsLink = Actions.getByContent(f, "Secrets");
256 Collection<Item> publicKeyItem = Actions.getByContent(f, "PublicKey");
257 if (!secretsLink.isEmpty() && !publicKeyItem.isEmpty()) {
258 //Then we are on credentials frame
259 f.addToData("MultiuserCredentials");
260 }
261 Text backupPersonalKey = KeyList.PersonalKey.get();
262 Text tempPersonalKey = KeyList.PersonalKey.generateText();
263 tempPersonalKey.setData(personalKey);
264 KeyList.PersonalKey.setSetting(tempPersonalKey);
265 FrameIO.SaveFrame(f);
266 KeyList.PersonalKey.setSetting(backupPersonalKey);
267 }
268 return profile;
269 }
270
271 private static String generatePersonalKey(String username, String password) {
272 try {
273 Random rand = new SecureRandom();
274 byte[] keyBytes = new byte[16];
275 rand.nextBytes(keyBytes);
276 SecretKey key = new SecretKeySpec(keyBytes, SymmetricAlgorithm);
277 AuthenticatorBrowser.getInstance().putKey(username, password, key);
278 String personalKey = Base64.getEncoder().encodeToString(key.getEncoded());
279 return personalKey;
280 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | ClassNotFoundException
281 | IOException | SQLException e) {
282 return null;
283 }
284 }
285
286 private static String[] generateAsymmetricKeys() {
287 try {
288 KeyPairGenerator keyGen = KeyPairGenerator.getInstance(AsymmetricAlgorithm);
289 keyGen.initialize(1024);
290 KeyPair keyPair = keyGen.generateKeyPair();
291 String publicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
292 String privateKey = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
293 return new String[] { privateKey, publicKey };
294 } catch (NoSuchAlgorithmException e) {
295 return null;
296 }
297 }
298
299 private static TextSetting constructTextSetting(String tooltip, String text, String data) {
300 return new TextSetting(tooltip, text) {
301 @Override
302 public Text generateText() {
303 Text t = new Text(text);
304 t.setData(data);
305 return t;
306 }
307 };
308 }
309
310 private static <T> GenericSetting<T> constructGenericSetting(Class<T> type, String tooltip, String name, T value, String frameset) {
311 return new GenericSetting<T>(type, tooltip, name, value) {
312 @Override
313 public Text generateRepresentation(String name, String frameset) {
314 Text t = new Text(name + ": " + value);
315 return t;
316 }
317 };
318 }
319}
Note: See TracBrowser for help on using the repository browser.