changeset 1759:97c799a0efbb

thermostat gui should not fail after running setup. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2015-August/015524.html PR2581
author Severin Gehwolf <sgehwolf@redhat.com>
date Tue, 25 Aug 2015 17:32:00 +0200
parents 1498494ddf96
children ce735787f5e3
files setup/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetup.java setup/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetupTest.java
diffstat 6 files changed, 95 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/SetupCommand.java	Tue Aug 25 17:32:00 2015 +0200
@@ -54,6 +54,7 @@
 import com.redhat.thermostat.setup.command.internal.model.ThermostatSetup;
 import com.redhat.thermostat.shared.config.CommonPaths;
 import com.redhat.thermostat.shared.locale.LocalizedString;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class SetupCommand extends AbstractCommand {
 
@@ -63,6 +64,7 @@
     private SetupWindow mainWindow;
     private CommonPaths paths;
     private Launcher launcher;
+    private Keyring keyring;
     private ThermostatSetup thermostatSetup;
     private Console console;
     private String[] origArgsList;
@@ -84,6 +86,8 @@
             requireNonNull(paths, new LocalizedString("CommonPaths dependency not available"));
             this.launcher = dependentServices.getService(Launcher.class);
             requireNonNull(launcher, new LocalizedString("Launcher dependency not available"));
+            this.keyring = dependentServices.getService(Keyring.class);
+            requireNonNull(keyring, new LocalizedString("Keyring dependency not available"));
 
             createMainWindowAndRun();
         } catch (InterruptedException | InvocationTargetException e) {
@@ -115,9 +119,14 @@
         dependentServices.addService(Launcher.class, launcher);
     }
     
+    public void setKeyring(Keyring keyring) {
+        dependentServices.addService(Keyring.class, keyring);
+    }
+    
     public void setServicesUnavailable() {
         dependentServices.removeService(Launcher.class);
         dependentServices.removeService(CommonPaths.class);
+        dependentServices.removeService(Keyring.class);
     }
 
     public boolean isStorageRequired() {
@@ -126,7 +135,7 @@
 
     //package-private for testing
     void createMainWindowAndRun() throws CommandException {
-        thermostatSetup = ThermostatSetup.create(launcher, paths, console);
+        thermostatSetup = ThermostatSetup.create(launcher, paths, console, keyring);
         mainWindow = new SetupWindow(thermostatSetup);
         mainWindow.run();
     }
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/Activator.java	Tue Aug 25 17:32:00 2015 +0200
@@ -48,6 +48,7 @@
 import org.osgi.framework.BundleContext;
 
 import com.redhat.thermostat.setup.command.SetupCommand;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class Activator implements BundleActivator {
 
@@ -63,15 +64,18 @@
 
         Class<?>[] deps = new Class<?>[] {
                 CommonPaths.class,
-                Launcher.class
+                Launcher.class,
+                Keyring.class
         };
         tracker = new MultipleServiceTracker(context, deps, new MultipleServiceTracker.Action() {
             @Override
             public void dependenciesAvailable(Map<String, Object> services) {
                 CommonPaths paths = (CommonPaths) services.get(CommonPaths.class.getName());
                 Launcher launcher = (Launcher) services.get(Launcher.class.getName());
+                Keyring keyring = (Keyring) services.get(Keyring.class.getName());
                 setupCommand.setPaths(paths);
                 setupCommand.setLauncher(launcher);
+                setupCommand.setKeyring(keyring);
             }
 
             @Override
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/SetupWindow.java	Tue Aug 25 17:32:00 2015 +0200
@@ -250,10 +250,12 @@
                 thermostatSetup.createMongodbUser(storageUsername, storagePassword);
                 try {
                     if (userPropertiesView.makeAgentUserSelected()) {
-                        thermostatSetup.createAgentUser(DEFAULT_AGENT_USER, DEFAULT_USER_PASSWORD);
+                        char[] agentPassword = Arrays.copyOf(DEFAULT_USER_PASSWORD, DEFAULT_USER_PASSWORD.length);
+                        thermostatSetup.createAgentUser(DEFAULT_AGENT_USER, agentPassword);
                     }
                     if (userPropertiesView.makeClientAdminSelected()) {
-                        thermostatSetup.createClientAdminUser(DEFAULT_CLIENT_USER, DEFAULT_USER_PASSWORD);
+                        char[] clientPassword = Arrays.copyOf(DEFAULT_USER_PASSWORD, DEFAULT_USER_PASSWORD.length);
+                        thermostatSetup.createClientAdminUser(DEFAULT_CLIENT_USER, clientPassword);
                     }
                     thermostatSetup.commit();
                 } catch (IOException e) {
--- a/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetup.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/main/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetup.java	Tue Aug 25 17:32:00 2015 +0200
@@ -41,11 +41,16 @@
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Objects;
 import java.util.Properties;
 
 import com.redhat.thermostat.common.cli.Console;
+import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.utils.keyring.Keyring;
+import com.redhat.thermostat.utils.keyring.KeyringException;
 
 public class ThermostatSetup implements PersistableSetup {
 
@@ -60,15 +65,21 @@
     private final StructureInformation structureInfo;
     private final CredentialsFileCreator creator;
     private final CommonPaths paths;
+    private final Keyring keyring;
+    private final ClientPreferences prefs;
     private String agentUserName;
     private char[] agentPassword;
+    private String clientUsername;
+    private char[] clientPassword;
     
-    ThermostatSetup(ThermostatUserSetup userSetup, MongodbUserSetup mongodbUserSetup, StructureInformation structureInfo, CommonPaths paths, CredentialsFileCreator creator) {
+    ThermostatSetup(ThermostatUserSetup userSetup, MongodbUserSetup mongodbUserSetup, StructureInformation structureInfo, CommonPaths paths, CredentialsFileCreator creator, Keyring keyring, ClientPreferences prefs) {
         this.mongodbUserSetup = mongodbUserSetup;
         this.userSetup = userSetup;
         this.structureInfo = structureInfo;
         this.paths = paths;
         this.creator = creator;
+        this.keyring = keyring;
+        this.prefs = prefs;
     }
 
     public void createMongodbUser(String username, char[] password) {
@@ -94,6 +105,10 @@
                                               },
                                     "Client admin user username => role assignment."
         );
+        // Hold on to these credentials so that they can be written to keyring
+        // on commit(). This makes gui work out of the box after setup has run.
+        this.clientUsername = username;
+        this.clientPassword = password;
     }
 
     public void createAgentUser(String username, char[] password) {
@@ -118,9 +133,30 @@
         mongodbUserSetup.commit();
         userSetup.commit();
         writeAgentAuthFile();
+        storeClientCredsToKeyring();
     }
     
+    private void storeClientCredsToKeyring() throws IOException {
+        Objects.requireNonNull(clientUsername);
+        Objects.requireNonNull(clientPassword);
+        try {
+            prefs.setSaveEntitlements(true); // force writing on flush()
+            String url = prefs.getConnectionUrl();
+            prefs.setUserName(clientUsername);
+            // Unconditionally save the chosen username. If setup was run again
+            // it will overwrite existing credentials.
+            keyring.savePassword(url, clientUsername, clientPassword);
+            prefs.flush();
+        } catch (KeyringException e) {
+            throw new IOException(e);
+        } finally {
+            Arrays.fill(clientPassword, '\0');
+        }
+    }
+
     private void writeAgentAuthFile() throws IOException {
+        Objects.requireNonNull(agentPassword);
+        Objects.requireNonNull(agentUserName);
         Properties credentialProps = new Properties();
         credentialProps.setProperty("username", agentUserName);
         credentialProps.setProperty("password", String.valueOf(agentPassword));
@@ -128,6 +164,8 @@
         creator.create(credentialsFile);
         try (FileOutputStream fout = new FileOutputStream(credentialsFile)) {
             credentialProps.store(fout, "Credentials used for 'thermostat agent' connections.");
+        } finally {
+            Arrays.fill(agentPassword, '\0');
         }
     }
 
@@ -135,13 +173,14 @@
         return structureInfo.isWebAppInstalled();
     }
     
-    public static ThermostatSetup create(Launcher launcher, CommonPaths paths, Console console) {
+    public static ThermostatSetup create(Launcher launcher, CommonPaths paths, Console console, Keyring keyring) {
         CredentialFinder finder = new CredentialFinder(paths);
         CredentialsFileCreator creator = new CredentialsFileCreator();
         StampFiles stampFiles = new StampFiles(paths);
         StructureInformation info = new StructureInformation(paths);
         MongodbUserSetup mongoSetup = new MongodbUserSetup(new UserCredsValidator(), launcher, finder, creator , console, paths, stampFiles, info);
         ThermostatUserSetup userSetup = new ThermostatUserSetup(new UserPropertiesFinder(finder), new UserCredsValidator(), creator, stampFiles);
-        return new ThermostatSetup(userSetup, mongoSetup, info, paths, creator);
+        ClientPreferences prefs = new ClientPreferences(paths);
+        return new ThermostatSetup(userSetup, mongoSetup, info, paths, creator, keyring, prefs);
     }
 }
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/SetupCommandTest.java	Tue Aug 25 17:32:00 2015 +0200
@@ -64,6 +64,7 @@
 import com.redhat.thermostat.common.cli.Console;
 import com.redhat.thermostat.launcher.Launcher;
 import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class SetupCommandTest {
 
@@ -76,6 +77,7 @@
     private PrintStream output, error;
     private CommonPaths paths;
     private Launcher launcher;
+    private Keyring keyring;
 
     @Before
     public void setUp() {
@@ -90,6 +92,7 @@
         errorBaos = new ByteArrayOutputStream();
         error = new PrintStream(errorBaos);
         launcher = mock(Launcher.class);
+        keyring = mock(Keyring.class);
 
         when(ctxt.getArguments()).thenReturn(mockArgs);
         when(ctxt.getConsole()).thenReturn(console);
@@ -209,6 +212,20 @@
         verify(launcher).run(argThat(new ArgsMatcher(argsList)), eq(false));
     }
     
+    @Test
+    public void testKeyringNotSetFailure() {
+        cmd = createSetupCommand();
+        
+        cmd.setPaths(mock(CommonPaths.class));
+        cmd.setLauncher(mock(Launcher.class));
+        try {
+            cmd.run(ctxt);
+            fail();
+        } catch (CommandException e) {
+            assertTrue(e.getMessage().contains("Keyring dependency not available"));
+        }
+    }
+    
     private SetupCommand createSetupCommand() {
         return new SetupCommand() {
             @Override
@@ -226,6 +243,7 @@
     private void setServices() {
         cmd.setPaths(paths);
         cmd.setLauncher(launcher);
+        cmd.setKeyring(keyring);
     }
     
     private static class ArgsMatcher extends BaseMatcher<String[]> {
--- a/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetupTest.java	Thu Sep 03 11:40:37 2015 +0200
+++ b/setup/command/src/test/java/com/redhat/thermostat/setup/command/internal/model/ThermostatSetupTest.java	Tue Aug 25 17:32:00 2015 +0200
@@ -57,7 +57,9 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.common.config.ClientPreferences;
 import com.redhat.thermostat.shared.config.CommonPaths;
+import com.redhat.thermostat.utils.keyring.Keyring;
 
 public class ThermostatSetupTest {
 
@@ -73,7 +75,7 @@
     @Test
     public void testIsWebAppInstalledDelegates() {
         StructureInformation structureInfo = mock(StructureInformation.class);
-        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, structureInfo, mock(CommonPaths.class), mock(CredentialsFileCreator.class));
+        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, structureInfo, mock(CommonPaths.class), mock(CredentialsFileCreator.class), mock(Keyring.class), mock(ClientPreferences.class));
         when(structureInfo.isWebAppInstalled()).thenReturn(true);
         assertTrue(setup.isWebAppInstalled());
         verify(structureInfo).isWebAppInstalled();
@@ -81,7 +83,7 @@
     
     @Test
     public void testCreateAgentUser() {
-        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), mock(CommonPaths.class), mock(CredentialsFileCreator.class));
+        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), mock(CommonPaths.class), mock(CredentialsFileCreator.class), mock(Keyring.class), mock(ClientPreferences.class));
         setup.createAgentUser("foo-agent", new char[] { 't' });
         verify(userSetup).createRecursiveRole(eq("thermostat-agent"), argThat(new RoleMatcher(UserRoles.AGENT_ROLES)), any(String.class));
         verify(userSetup).assignRolesToUser(eq("foo-agent"), argThat(new RoleMatcher(new String[] { "thermostat-agent", UserRoles.GRANT_FILES_WRITE_ALL })), any(String.class));
@@ -89,7 +91,7 @@
     
     @Test
     public void testCreateClientAdminUser() {
-        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), mock(CommonPaths.class), mock(CredentialsFileCreator.class));
+        ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), mock(CommonPaths.class), mock(CredentialsFileCreator.class), mock(Keyring.class), mock(ClientPreferences.class));
         setup.createClientAdminUser("foo-client", new char[] { 't' });
         verify(userSetup).createRecursiveRole(eq("thermostat-client"), argThat(new RoleMatcher(UserRoles.CLIENT_ROLES)), any(String.class));
         verify(userSetup).createRecursiveRole(eq("thermostat-cmdc"), argThat(new RoleMatcher(UserRoles.CMD_CHANNEL_GRANT_ALL_ACTIONS)), any(String.class));
@@ -99,18 +101,27 @@
     }
     
     @Test
-    public void flushCreatesAgentAuthFile() throws IOException {
+    public void commitCreatesAgentAuthFileStoresToKeyring() throws IOException {
         CommonPaths paths = mock(CommonPaths.class);
         File mockAgentAuthFile = File.createTempFile("thermostat-test-", getClass().getName());
+        Keyring keyring = mock(Keyring.class);
+        ClientPreferences prefs = mock(ClientPreferences.class);
         try {
             when(paths.getUserAgentAuthConfigFile()).thenReturn(mockAgentAuthFile);
-            ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), paths, mock(CredentialsFileCreator.class));
+            ThermostatSetup setup = new ThermostatSetup(userSetup, mongoUserSetup, mock(StructureInformation.class), paths, mock(CredentialsFileCreator.class), keyring, prefs);
             List<String> contents = Files.readAllLines(mockAgentAuthFile.toPath(), Charset.forName("UTF-8"));
             assertEquals(0, contents.size());
             setup.createAgentUser("damian", new char[] { 't', 'e', 's', 't' });
+            String clientUser = "client-admin";
+            char[] clientPass = new char[] { 't' };
+            setup.createClientAdminUser(clientUser, clientPass);
             setup.commit();
             verify(userSetup).commit();
             verify(mongoUserSetup).commit();
+            verify(keyring).savePassword(prefs.getConnectionUrl(), clientUser, clientPass);
+            verify(prefs).flush();
+            verify(prefs).setSaveEntitlements(true);
+            verify(prefs).setUserName(clientUser);
             contents = Files.readAllLines(mockAgentAuthFile.toPath(), Charset.forName("UTF-8"));
             assertTrue("username and password must be present", contents.size() > 2);
             assertTrue("username=damian expected to be found in agent.auth file", contents.contains("username=damian"));