Browse Source

onejar improvements

Jason Rivard 7 years ago
parent
commit
5a129f59be

+ 0 - 10
onejar/pom.xml

@@ -124,16 +124,6 @@
         </dependency>
 
         <!-- embedded tomcat -->
-        <dependency>
-            <groupId>org.apache.tomcat</groupId>
-            <artifactId>tomcat-catalina</artifactId>
-            <version>${tomcat.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tomcat</groupId>
-            <artifactId>tomcat-util</artifactId>
-            <version>${tomcat.version}</version>
-        </dependency>
         <dependency>
             <groupId>org.apache.tomcat.embed</groupId>
             <artifactId>tomcat-embed-core</artifactId>

+ 82 - 0
onejar/src/main/java/password/pwm/Argument.java

@@ -0,0 +1,82 @@
+package password.pwm;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.TreeMap;
+
+enum Argument
+{
+    applicationPath,
+    workPath,
+    version,
+    help,
+    war,
+    port,
+    context,
+    properties,
+    localAddress,
+
+    ;
+
+    static Options asOptions()
+    {
+        final Options options = new Options();
+        asOptionMap().values().forEach( options::addOption );
+        return options;
+    }
+
+    static Map<Argument,Option> asOptionMap() {
+        final Map<Argument,Option> optionMap = new TreeMap<>(  );
+
+        optionMap.put(Argument.applicationPath, Option.builder(Argument.applicationPath.name()  )
+                .desc( "application path (required)" )
+                .numberOfArgs( 1 )
+                .build());
+
+        optionMap.put(Argument.workPath, Option.builder(Argument.workPath.name() )
+                .desc( "temporary work path" )
+                .numberOfArgs( 1 )
+                .build());
+
+        optionMap.put(Argument.version, Option.builder(Argument.version.name()  )
+                .desc( "show version" )
+                .numberOfArgs( 0 )
+                .build());
+
+        optionMap.put(Argument.port, Option.builder( Argument.port.name() )
+                .desc( "web server port (default " + Resource.defaultPort.getValue() + ")" )
+                .numberOfArgs( 1 )
+                .build() );
+
+        optionMap.put(Argument.localAddress, Option.builder( Argument.localAddress.name() )
+                .desc( "local network address (default localhost)" )
+                .numberOfArgs( 1 )
+                .build() );
+
+        optionMap.put(Argument.context, Option.builder(Argument.context.name() )
+                .desc( "context (url path) name (default " + Resource.defaultContext.getValue() + ")" )
+                .numberOfArgs( 1 )
+                .build() );
+
+        optionMap.put(Argument.help, Option.builder(Argument.help.name())
+                .desc( "show this help" )
+                .numberOfArgs( 0 )
+                .build());
+
+        optionMap.put(Argument.properties, Option.builder(Argument.properties.name())
+                .desc( "read arguments from properties file" )
+                .numberOfArgs( 1 )
+                .build());
+
+        optionMap.put(Argument.war, Option.builder(Argument.war.name())
+                .desc( "source war file (default embedded)" )
+                .numberOfArgs( 1 )
+                .build());
+
+        return Collections.unmodifiableMap(optionMap);
+    }
+
+}

+ 225 - 0
onejar/src/main/java/password/pwm/ArgumentParser.java

@@ -0,0 +1,225 @@
+package password.pwm;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.ParseException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class ArgumentParser
+{
+
+    public TomcatConfig parseArguments(final String[] args)
+            throws ArgumentParserException, TomcatOneJarException
+    {
+        if (args == null || args.length == 0) {
+            ArgumentParser.outputHelp();
+        } else {
+            final CommandLine commandLine;
+
+            try {
+                commandLine = new DefaultParser().parse( Argument.asOptions(), args );
+            } catch ( ParseException e ) {
+                throw new ArgumentParserException( "unable to parse command line: " + e.getMessage());
+            }
+
+            if ( commandLine.hasOption( Argument.version.name() ) ) {
+                TomcatOneJarMain.out( TomcatOneJarMain.getVersion() );
+                return null;
+            } else if ( commandLine.hasOption( Argument.help.name() ) ) {
+                ArgumentParser.outputHelp();
+                return null;
+            } else {
+                final Map<Argument, String> argumentMap;
+                if (commandLine.hasOption( Argument.properties.name())) {
+                    if (args.length > 2) {
+                        throw new ArgumentParserException( Argument.properties.name() + " must be the only argument specified" );
+                    }
+                    final String filename = commandLine.getOptionValue( Argument.properties.name() );
+                    argumentMap = mapFromProperties( filename );
+                } else {
+                    argumentMap = mapFromCommandLine( commandLine );
+                }
+                final TomcatConfig tomcatConfig;
+                try {
+                    tomcatConfig = makeTomcatConfig( argumentMap );
+                } catch ( IOException e ) {
+                    throw new ArgumentParserException( "error while reading input: " + e.getMessage() );
+                }
+                return tomcatConfig;
+            }
+        }
+
+        return null;
+    }
+
+    private Map<Argument,String> mapFromProperties(final String filename) throws ArgumentParserException
+    {
+        final Properties props = new Properties();
+        try {
+            props.load(new FileInputStream( new File( filename) ));
+        } catch ( IOException e ) {
+            throw new ArgumentParserException( "unable to read properties input file: " + e.getMessage());
+        }
+
+        final Map<Argument,String> map = new HashMap<>(  );
+        for (final Option option : Argument.asOptionMap().values()) {
+            if (option.hasArg()) {
+                final Argument argument = Argument.valueOf( option.getOpt() );
+                final String value = props.getProperty( argument.name() );
+                if (value != null) {
+                    map.put( argument, value );
+                }
+            }
+        }
+        return Collections.unmodifiableMap( map );
+    }
+
+    private Map<Argument,String> mapFromCommandLine(final CommandLine commandLine) {
+        final Map<Argument,String> map = new HashMap<>(  );
+        for (final Option option : Argument.asOptionMap().values()) {
+            if (option.hasArg()) {
+                if (commandLine.hasOption( option.getOpt() )) {
+                    final Argument argument = Argument.valueOf( option.getOpt() );
+                    final String value = commandLine.getOptionValue( option.getOpt() );
+                    map.put( argument, value );
+                }
+            }
+        }
+        return Collections.unmodifiableMap(map);
+    }
+
+
+    private TomcatConfig makeTomcatConfig( final Map<Argument,String> argumentMap) throws IOException, ArgumentParserException
+    {
+        final TomcatConfig tomcatConfig = new TomcatConfig();
+        tomcatConfig.setApplicationPath( parseFileOption( argumentMap, Argument.applicationPath ) );
+
+        tomcatConfig.setContext( argumentMap.getOrDefault( Argument.context, Resource.defaultContext.getValue() ) );
+
+        if (argumentMap.containsKey( Argument.war )) {
+            final File inputWarFile = new File ( argumentMap.get( Argument.war ));
+            if (!inputWarFile.exists()) {
+                System.out.println( "output war file " + inputWarFile.getAbsolutePath() + "does not exist" );
+                System.exit( -1 );
+                return null;
+            }
+            tomcatConfig.setWar( new FileInputStream( inputWarFile ) );
+        } else {
+            tomcatConfig.setWar( getEmbeddedWar() );
+        }
+
+        tomcatConfig.setPort( Integer.parseInt( Resource.defaultPort.getValue() ) );
+        if (argumentMap.containsKey( Argument.port )) {
+            try {
+                tomcatConfig.setPort( Integer.parseInt( argumentMap.get( Argument.port ) ) );
+            } catch (NumberFormatException e) {
+                System.out.println( Argument.port.name()  + " argument must be numeric" );
+                System.exit( -1 );
+            }
+        }
+
+        tomcatConfig.setLocalAddress( argumentMap.getOrDefault( Argument.localAddress, Resource.defaultLocalAddress.getValue() ) );
+
+        try {
+            final ServerSocket socket = new ServerSocket(tomcatConfig.getPort(), 100, InetAddress.getByName( tomcatConfig.getLocalAddress() ));
+            socket.close();
+        } catch(Exception e) {
+            throw new ArgumentParserException( "port or address conflict: " + e.getMessage() );
+        }
+
+        if (argumentMap.containsKey( Argument.workPath )) {
+            tomcatConfig.setWorkingPath( parseFileOption( argumentMap, Argument.workPath   ) );
+        } else {
+            tomcatConfig.setWorkingPath( figureDefaultWorkPath( tomcatConfig) );
+        }
+
+        return tomcatConfig;
+    }
+
+
+
+    private static void outputHelp() throws TomcatOneJarException
+    {
+        final HelpFormatter formatter = new HelpFormatter();
+        System.out.println( TomcatOneJarMain.getVersion() );
+        System.out.println( "usage:" );
+        formatter.printOptions(
+                System.console().writer(),
+                HelpFormatter.DEFAULT_WIDTH,
+                Argument.asOptions(),
+                3 ,
+                8);
+    }
+
+
+    private static File parseFileOption(final Map<Argument,String> argumentMap, final Argument argName) throws ArgumentParserException
+    {
+        if (!argumentMap.containsKey( argName )) {
+            throw new ArgumentParserException( "option " + argName + " required");
+        }
+        final File file = new File(argumentMap.get( argName ));
+        if (!file.isAbsolute()) {
+            throw new ArgumentParserException( "a fully qualified file path name is required for " + argName);
+        }
+        if (!file.exists()) {
+            throw new ArgumentParserException( "path specified by " + argName + " must exist");
+        }
+        return file;
+    }
+
+    private static File figureDefaultWorkPath(final TomcatConfig tomcatConfig) {
+        final String userHomePath = System.getProperty( "user.home" );
+        if (userHomePath != null && !userHomePath.isEmpty()) {
+            final File basePath = new File(userHomePath + File.separator
+                    + Resource.defaultWorkPathName.getValue());
+            basePath.mkdir();
+            final File workPath = new File( basePath.getPath() + File.separator
+                    + "work"
+                    + "-"
+                    + escapeFilename( tomcatConfig.getContext() )
+                    + "-"
+                    + escapeFilename( Integer.toString( tomcatConfig.getPort() ) )
+                    + "-"
+                    + escapeFilename( tomcatConfig.getLocalAddress() )
+            );
+            workPath.mkdir();
+            System.out.println( "using work directory: " + workPath.getAbsolutePath() );
+            return workPath;
+        }
+
+        System.out.println( "cant locate user home directory" );
+        System.exit( -1 );
+        return null;
+    }
+
+    private static InputStream getEmbeddedWar() throws IOException, ArgumentParserException
+    {
+        final Class clazz = TomcatOneJarMain.class;
+        final String className = clazz.getSimpleName() + ".class";
+        final String classPath = clazz.getResource(className).toString();
+        if (!classPath.startsWith("jar")) {
+            throw new ArgumentParserException("not running from war, war option must be specified");
+        }
+        final String warPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
+                "/" + Resource.defaultWarFileName.getValue();
+        return new URL(warPath).openStream();
+    }
+
+    private static String escapeFilename(final String input) {
+        return input.replaceAll("\\W+", "_");
+    }
+
+}

+ 9 - 0
onejar/src/main/java/password/pwm/ArgumentParserException.java

@@ -0,0 +1,9 @@
+package password.pwm;
+
+public class ArgumentParserException extends Exception
+{
+    public ArgumentParserException( final String msg )
+    {
+        super(msg);
+    }
+}

+ 24 - 0
onejar/src/main/java/password/pwm/Resource.java

@@ -0,0 +1,24 @@
+package password.pwm;
+
+import java.util.ResourceBundle;
+
+enum Resource
+{
+    defaultContext,
+    defaultWorkPathName,
+    defaultPort,
+    defaultLocalAddress,
+    defaultWarFileName,
+
+    ;
+
+    String getValue() {
+        return readResource( this );
+    }
+
+    private static String readResource(final Resource resource) {
+        final ResourceBundle bundle = ResourceBundle.getBundle(Resource.class.getName());
+        return bundle.getString( resource.name() );
+    }
+
+}

+ 11 - 0
onejar/src/main/java/password/pwm/TomcatConfig.java

@@ -9,6 +9,7 @@ class TomcatConfig {
     private File workingPath;
     private InputStream war;
     private String context;
+    private String localAddress;
 
     public int getPort( )
     {
@@ -59,4 +60,14 @@ class TomcatConfig {
     {
         this.context = context;
     }
+
+    public String getLocalAddress( )
+    {
+        return localAddress;
+    }
+
+    public void setLocalAddress( final String localAddress )
+    {
+        this.localAddress = localAddress;
+    }
 }

+ 8 - 0
onejar/src/main/java/password/pwm/TomcatOneJarException.java

@@ -0,0 +1,8 @@
+package password.pwm;
+
+public class TomcatOneJarException extends Exception
+{
+    public TomcatOneJarException(final String msg) {
+        super(msg);
+    }
+}

+ 140 - 229
onejar/src/main/java/password/pwm/TomcatOneJarMain.java

@@ -1,150 +1,107 @@
 package password.pwm;
 
-import org.apache.catalina.Context;
 import org.apache.catalina.LifecycleException;
 import org.apache.catalina.connector.Connector;
-import org.apache.catalina.connector.CoyoteAdapter;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.util.ServerInfo;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
 
 import javax.servlet.ServletException;
 import java.io.File;
-import java.io.FileInputStream;
+import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.Socket;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.net.URL;
+import java.net.URLClassLoader;
 import java.nio.file.FileVisitOption;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Comparator;
-import java.util.Map;
-import java.util.TreeMap;
+import java.util.List;
+import java.util.Properties;
 import java.util.jar.Attributes;
 import java.util.jar.Manifest;
-import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 public class TomcatOneJarMain
 {
-    private static final  Logger LOGGER = Logger.getLogger(TomcatOneJarMain.class.getName());
+    //private static final String TEMP_WAR_FILE_NAME = "embed.war";
+    private static final String KEYSTORE_PASSWORD = "password";
+    private static final String KEYSTORE_ALIAS = "https";
 
-    private static final String ARG_APP_PATH = "applicationPath";
-    private static final String ARG_WORK_PATH = "workPath";
-    private static final String ARG_VERSION = "version";
-    private static final String ARG_HELP = "help";
-    private static final String ARG_WARFILE = "war";
-    private static final String ARG_PORT = "port";
-    private static final String ARG_CONTEXT = "context";
-
-    private static final String DEFAULT_CONTEXT = "pwm";
-    private static final int DEFAULT_PORT = 8080;
-    private static final String DEFAULT_WORK_DIR_NAME = ".pwm-workpath";
-
-    private static final String EMBED_WAR_NAME = "embed.war";
-
-    public static void main(final String[] args) throws ServletException, IOException, LifecycleException
+    public static void main(final String[] args)
     {
-        if (args == null || args.length == 0) {
-            outputHelp();
-        } else
-        {
-            final CommandLine commandLine = parseOptions( args );
-            if ( commandLine.hasOption( ARG_VERSION ) ) {
-                System.out.println( getVersion() );
-            } else if ( commandLine.hasOption( ARG_HELP ) ) {
-                outputHelp();
-            } else {
-                final TomcatConfig tomcatConfig = makeTomcatConfig( commandLine );
-                startTomcat(tomcatConfig);
+        final ArgumentParser argumentParser = new ArgumentParser();
+        TomcatConfig tomcatConfig = null;
+        try {
+            tomcatConfig = argumentParser.parseArguments( args );
+        } catch ( ArgumentParserException | TomcatOneJarException e ) {
+            out("error parsing command line: " + e.getMessage());
+        }
+        if (tomcatConfig != null) {
+            try {
+                startTomcat( tomcatConfig );
+            } catch ( TomcatOneJarException | ServletException | IOException e ) {
+                out("error starting tomcat: " + e.getMessage());
             }
         }
     }
 
-    private static TomcatConfig makeTomcatConfig(final CommandLine commandLine) throws IOException
-    {
-        final TomcatConfig tomcatConfig = new TomcatConfig();
-        tomcatConfig.setApplicationPath( parseFileOption( commandLine, ARG_APP_PATH ) );
+    private static File getWarFolder(final TomcatConfig tomcatConfig) throws IOException {
+        return new File(tomcatConfig.getWorkingPath().getAbsoluteFile() + File.separator + "war");
+    }
 
-        if (commandLine.hasOption( ARG_CONTEXT )) {
-            tomcatConfig.setContext( commandLine.getOptionValue( ARG_CONTEXT ) );
-        } else {
-            tomcatConfig.setContext( DEFAULT_CONTEXT );
-        }
+    private static File getKeystoreFile( final TomcatConfig tomcatConfig ) {
+        return new File(tomcatConfig.getWorkingPath().getAbsoluteFile() + File.separator + "keystore");
+    }
 
-        if (commandLine.hasOption( ARG_WARFILE )) {
-            final File inputWarFile = new File (commandLine.getOptionValue( ARG_WARFILE ));
-            if (!inputWarFile.exists()) {
-                System.out.println( "output war file " + inputWarFile.getAbsolutePath() + "does not exist" );
-                System.exit( -1 );
-                return null;
-            }
-            tomcatConfig.setWar( new FileInputStream( inputWarFile ) );
-        } else {
-            tomcatConfig.setWar( getEmbeddedWar() );
-        }
+    private static File getPwmAppPropertiesFile( final TomcatConfig tomcatConfig ) {
+        return new File(tomcatConfig.getWorkingPath().getAbsoluteFile() + File.separator + "application.properties");
+    }
 
-        tomcatConfig.setPort( DEFAULT_PORT );
-        if (commandLine.hasOption( ARG_PORT )) {
-            try {
-                tomcatConfig.setPort( Integer.parseInt( commandLine.getOptionValue( ARG_PORT ) ) );
-            } catch (NumberFormatException e) {
-                System.out.println( ARG_PORT + " argument must be numeric" );
-                System.exit( -1 );
-            }
-        }
 
-        if ( checkIfPortInUse( tomcatConfig.getPort())) {
-            System.out.println( "port " + tomcatConfig.getPort() +  " is in use" );
-            System.exit( -1 );
-        }
+    private static void explodeWar( final TomcatConfig tomcatConfig) throws IOException
+    {
+        final InputStream warSource = tomcatConfig.getWar();
+        final ZipInputStream zipInputStream = new ZipInputStream( warSource );
+        final File outputFolder = getWarFolder( tomcatConfig );
+        outputFolder.mkdir();
 
-        if (commandLine.hasOption( ARG_WORK_PATH )) {
-            tomcatConfig.setWorkingPath( parseFileOption( commandLine, ARG_WORK_PATH ) );
-        } else {
-            tomcatConfig.setWorkingPath( figureDefaultWorkPath(tomcatConfig) );
-        }
+        ZipEntry zipEntry = zipInputStream.getNextEntry();
 
-        return tomcatConfig;
-    }
+        while( zipEntry!=null ) {
+            final String fileName = zipEntry.getName();
+            final File newFile = new File( outputFolder + File.separator + fileName );
 
-    private static File parseFileOption(final  CommandLine commandLine, final String argName) {
-        if (!commandLine.hasOption( argName )) {
-            outAndExit(  "option " + argName + " required");
-        }
-        final File file = new File(commandLine.getOptionValue( argName ));
-        if (!file.isAbsolute()) {
-            outAndExit( "a fully qualified file path name is required for " + argName);
-        }
-        if (!file.exists()) {
-            outAndExit( "path specified by " + argName + " must exist");
+            if (!zipEntry.isDirectory()) {
+                newFile.getParentFile().mkdirs();
+                Files.copy( zipInputStream, newFile.toPath() );
+            }
+            zipEntry = zipInputStream.getNextEntry();
         }
-        return file;
-    }
 
-    private static void outputHelp() throws IOException
-    {
-        final HelpFormatter formatter = new HelpFormatter();
-        System.out.println( getVersion() );
-        System.out.println( "usage:" );
-        formatter.printOptions( System.console().writer(), HelpFormatter.DEFAULT_WIDTH, makeOptions(),3 , 8);
     }
 
-    private static void startTomcat( final TomcatConfig tomcatConfig) throws ServletException, IOException
+    private static void startTomcat( final TomcatConfig tomcatConfig) throws ServletException, IOException, TomcatOneJarException
     {
         purgeDirectory( tomcatConfig.getWorkingPath().toPath() );
-        {
-            final Path outputPath = tomcatConfig.getWorkingPath().toPath().resolve( EMBED_WAR_NAME );
-            final InputStream warSource = tomcatConfig.getWar();
-            Files.copy(warSource, outputPath);
+
+        explodeWar( tomcatConfig );
+        out( "deployed war" );
+
+        try {
+            generatePwmKeystore( tomcatConfig );
+            out("keystore generated");
+        } catch ( Exception e ) {
+            throw new TomcatOneJarException( "error generating keystore: " + e.getMessage() );
         }
-        System.setProperty( "PWM_APPLICATIONPATH", tomcatConfig.getApplicationPath().getAbsolutePath() );
+
+        outputPwmAppProperties( tomcatConfig );
+
+        setupEnv( tomcatConfig );
 
         final Tomcat tomcat = new Tomcat();
 
@@ -165,123 +122,67 @@ public class TomcatOneJarMain
             tomcat.getHost().setAppBase( workPath.getAbsolutePath() );
         }
 
-        tomcat.setConnector( makeConnector( tomcatConfig ) );
-
-        tomcat.setPort( DEFAULT_PORT );
-        tomcat.getConnector();
 
         tomcat.getHost().setAutoDeploy(false);
         tomcat.getHost().setDeployOnStartup(false);
 
-        final String warPath = tomcatConfig.getWorkingPath().getAbsolutePath() + File.separator + EMBED_WAR_NAME;
-        final Context pwmContext = tomcat.addWebapp( "/" + tomcatConfig.getContext(), warPath );
-        LOGGER.info("Deployed " + pwmContext.getBaseName() + " as " + pwmContext.getBaseName());
+        final String warPath = getWarFolder( tomcatConfig ).getAbsolutePath();
+        tomcat.addWebapp( "/" + tomcatConfig.getContext(), warPath );
 
         try {
             tomcat.start();
+
+            tomcat.setConnector( makeConnector( tomcatConfig ) );
+
+            out("tomcat started on " + tomcat.getHost());
         } catch (LifecycleException e) {
-            outAndExit( "unable to start tomcat: " + e.getMessage() );
+            throw new TomcatOneJarException( "unable to start tomcat: " + e.getMessage() );
         }
-        LOGGER.info("tomcat started on " + tomcat.getHost());
 
         tomcat.getServer().await();
+
+        System.out.println( "\n" );
     }
 
     private static Connector makeConnector(final TomcatConfig tomcatConfig) {
         final Connector connector = new Connector("HTTP/1.1");
         connector.setPort(tomcatConfig.getPort());
-        return connector;
-    }
 
-    private static CommandLine parseOptions(final String[] args) {
-        final CommandLineParser parser = new DefaultParser();
-        try {
-            return parser.parse( makeOptions(), args);
-        } catch ( ParseException e ) {
-            outAndExit(  "error parsing commandline: " + e.getMessage() );
+        if (tomcatConfig.getLocalAddress() != null)
+        {
+            connector.setProperty( "address", tomcatConfig.getLocalAddress() );
         }
-        return null;
-    }
+        connector.setSecure( true );
+        connector.setScheme( "https" );
+        connector.setAttribute( "SSLEnabled", "true" );
+        connector.setAttribute( "keystoreFile", getKeystoreFile( tomcatConfig ).getAbsolutePath() );
+        connector.setAttribute( "keystorePass", "password" );
+        connector.setAttribute( "keyAlias", "https" );
+        connector.setAttribute( "clientAuth", "false");
 
-    private static Options makeOptions() {
-        final Map<String,Option> optionMap = new TreeMap<>(  );
-
-        optionMap.put(ARG_APP_PATH,Option.builder(ARG_APP_PATH)
-                .desc( "application path (required)" )
-                .numberOfArgs( 1 )
-                .required(false)
-                .build());
-
-        optionMap.put(ARG_WORK_PATH,Option.builder(ARG_WORK_PATH)
-                .desc( "temporary work path" )
-                .numberOfArgs( 1 )
-                .required(false)
-                .build());
-
-        optionMap.put(ARG_VERSION,Option.builder(ARG_VERSION)
-                .desc( "show version" )
-                .numberOfArgs( 0 )
-                .required(false)
-                .build());
-
-        optionMap.put(ARG_PORT,Option.builder()
-                .longOpt( ARG_PORT )
-                .desc( "web server port (default " + DEFAULT_PORT + ")" )
-                .numberOfArgs( 1 )
-                .build() );
-
-        optionMap.put(ARG_CONTEXT,Option.builder()
-                .longOpt( ARG_CONTEXT )
-                .desc( "context (url path) name (default " + DEFAULT_CONTEXT + ")" )
-                .numberOfArgs( 1 )
-                .build() );
-
-        optionMap.put(ARG_HELP,Option.builder(ARG_HELP)
-                .desc( "show this help" )
-                .numberOfArgs( 0 )
-                .required(false)
-                .build());
-
-        optionMap.put(ARG_WARFILE,Option.builder(ARG_WARFILE)
-                .desc( "source war file (default embedded)" )
-                .numberOfArgs( 1 )
-                .required(false)
-                .build());
-
-        final Options options = new Options();
-        optionMap.values().forEach( options::addOption );
-        return options;
-    }
-
-    private static InputStream getEmbeddedWar() throws IOException
-    {
-        final Class clazz = TomcatOneJarMain.class;
-        final String className = clazz.getSimpleName() + ".class";
-        final String classPath = clazz.getResource(className).toString();
-        if (!classPath.startsWith("jar")) {
-            outAndExit("not running from war, war option must be specified");
-            return null;
-        }
-        final String warPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
-                "/" + EMBED_WAR_NAME;
-        return new URL(warPath).openStream();
+        return connector;
     }
 
-    private static String getVersion() throws IOException
+    static String getVersion( ) throws TomcatOneJarException
     {
-        final Class clazz = TomcatOneJarMain.class;
-        final String className = clazz.getSimpleName() + ".class";
-        final String classPath = clazz.getResource(className).toString();
-        if (!classPath.startsWith("jar")) {
-            // Class not from JAR
-            return "--version missing--";
+        try
+        {
+            final Class clazz = TomcatOneJarMain.class;
+            final String className = clazz.getSimpleName() + ".class";
+            final String classPath = clazz.getResource( className ).toString();
+            if ( !classPath.startsWith( "jar" ) ) {
+                // Class not from JAR
+                return "version missing, not running inside jar";
+            }
+            final String manifestPath = classPath.substring( 0, classPath.lastIndexOf( "!" ) + 1 ) +
+                    "/META-INF/MANIFEST.MF";
+            final Manifest manifest = new Manifest( new URL( manifestPath ).openStream() );
+            final Attributes attr = manifest.getMainAttributes();
+            return attr.getValue( "Implementation-Version-Display" )
+                    + "  [" + ServerInfo.getServerInfo() + "]";
+        } catch (IOException e) {
+            throw new TomcatOneJarException("error reading internal version info: " + e.getMessage());
         }
-        final String manifestPath = classPath.substring(0, classPath.lastIndexOf("!") + 1) +
-                "/META-INF/MANIFEST.MF";
-        final Manifest manifest = new Manifest(new URL(manifestPath).openStream());
-        final Attributes attr = manifest.getMainAttributes();
-        return attr.getValue("Implementation-Version-Display")
-                + ", " + ServerInfo.getServerInfo();
     }
 
     private static void purgeDirectory(final Path rootPath)
@@ -295,41 +196,51 @@ public class TomcatOneJarMain
                 .forEach(File::delete);
     }
 
-    private static boolean checkIfPortInUse( final int portNumber) {
-        boolean result;
 
-        try {
-            Socket s = new Socket("localhost", portNumber);
-            s.close();
-            result = true;
-        } catch(IOException e) {
-            result = false;
-        }
 
-        return(result);
+    static void out(final String output) {
+        System.out.println( output );
     }
 
-    private static File figureDefaultWorkPath(final TomcatConfig tomcatConfig) {
-        final String userHomePath = System.getProperty( "user.home" );
-        if (userHomePath != null && !userHomePath.isEmpty()) {
-            final File basePath = new File(userHomePath + File.separator
-                    + "." + DEFAULT_CONTEXT);
-            basePath.mkdir();
-            final File workPath = new File( basePath.getPath() + File.separator
-                    + "work-" + tomcatConfig.getContext() + "-" + Integer.toString( tomcatConfig.getPort() ));
-            workPath.mkdir();
-            System.out.println( "using work directory: " + workPath.getAbsolutePath() );
-            return workPath;
-        }
 
-        System.out.println( "cant locate user home directory" );
-        System.exit( -1 );
-        return null;
+    static void generatePwmKeystore( final TomcatConfig tomcatConfig) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException
+    {
+        final File warPath = getWarFolder( tomcatConfig );
+        final String keystoreFile = getKeystoreFile( tomcatConfig ).getAbsolutePath();
+        final File webInfPath = new File(warPath.getAbsolutePath() + File.separator + "WEB-INF" + File.separator + "lib");
+        final File[] jarFiles = webInfPath.listFiles();
+        final List<URL> jarURLList = new ArrayList<>(  );
+        for (final File jarFile : jarFiles) {
+            jarURLList.add( jarFile.toURI().toURL() );
+        }
+        final URLClassLoader classLoader = URLClassLoader.newInstance( jarURLList.toArray( new URL[jarURLList.size()] ) );
+        final Class pwmMainClass = classLoader.loadClass( "password.pwm.util.cli.MainClass" );
+        final Method mainMethod = pwmMainClass.getMethod( "main", String[].class );
+        final String[] arguments = new String[]{
+                "-applicationPath=" + tomcatConfig.getApplicationPath().getAbsolutePath(),
+                "ExportHttpsKeyStore",
+                keystoreFile,
+                KEYSTORE_ALIAS,
+                KEYSTORE_PASSWORD,
+        };
+
+        mainMethod.invoke( null, (Object)arguments );
+        classLoader.close();
     }
 
-    private static Object outAndExit(final String output) {
-        System.out.println(output);
-        System.exit( -1 );
-        return null;
+    static void setupEnv(final TomcatConfig tomcatConfig) {
+        System.setProperty( "PWM_APPLICATIONPATH", tomcatConfig.getApplicationPath().getAbsolutePath() );
+        System.setProperty( "PWM_APPLICATIONFLAGS", "ManageHttps" );
+        System.setProperty( "PWM_APPLICATIONPARAMFILE", getPwmAppPropertiesFile( tomcatConfig ).getAbsolutePath() );
+    }
+
+    static void outputPwmAppProperties(final TomcatConfig tomcatConfig) throws IOException
+    {
+        final Properties properties = new Properties();
+        properties.setProperty( "AutoExportHttpsKeyStoreFile", getKeystoreFile( tomcatConfig ).getAbsolutePath());
+        properties.setProperty( "AutoExportHttpsKeyStorePassword", KEYSTORE_PASSWORD);
+        properties.setProperty( "AutoExportHttpsKeyStoreAlias", KEYSTORE_ALIAS);
+        final File propFile = getPwmAppPropertiesFile( tomcatConfig );
+        properties.store( new FileWriter( propFile ), "auto-generated file" );
     }
 }

+ 5 - 0
onejar/src/main/resources/password/pwm/Resource.properties

@@ -0,0 +1,5 @@
+defaultContext=pwm
+defaultWorkPathName=.pwm-workpath
+defaultPort=8443
+defaultLocalAddress=0.0.0.0
+defaultWarFileName=embed.war

+ 13 - 14
server/src/main/java/password/pwm/util/cli/MainClass.java

@@ -203,19 +203,18 @@ public class MainClass {
         out("environment initialized");
         out("");
 
-        try (Writer outputStream = new OutputStreamWriter(System.out, PwmConstants.DEFAULT_CHARSET)) {
-            return new CliEnvironment(
-                    configReader,
-                    configurationFile,
-                    config,
-                    applicationPath,
-                    pwmApplication,
-                    localDB,
-                    outputStream,
-                    options,
-                    MAIN_OPTIONS
-            );
-        }
+        final Writer outputStream = new OutputStreamWriter(System.out, PwmConstants.DEFAULT_CHARSET);
+        return new CliEnvironment(
+                configReader,
+                configurationFile,
+                config,
+                applicationPath,
+                pwmApplication,
+                localDB,
+                outputStream,
+                options,
+                MAIN_OPTIONS
+        );
     }
 
     public static Map<String,Object> parseCommandOptions(
@@ -354,7 +353,7 @@ public class MainClass {
             }
         }
 
-        System.exit(0);
+        //System.exit(0);
         return;
 
     }