001/*
002 * Copyright (c) 2016 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2017-09-04 12:58:02 -0700 (Mon, 04 Sep 2017) $' 
007 * '$Revision: 1405 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029package org.kepler.webview.server;
030
031import java.io.File;
032import java.util.HashSet;
033import java.util.LinkedList;
034import java.util.List;
035import java.util.Set;
036
037import org.apache.commons.httpclient.util.HttpURLConnection;
038import org.kepler.CommandLineArgument;
039import org.kepler.build.modules.Module;
040import org.kepler.configuration.ConfigurationManager;
041import org.kepler.configuration.ConfigurationProperty;
042import org.kepler.util.DotKeplerManager;
043import org.kepler.webview.server.auth.DrupalAuth;
044import org.kepler.webview.server.auth.NoneAuth;
045import org.kepler.webview.server.auth.SimpleAuth;
046
047import io.vertx.ext.auth.AuthProvider;
048
049/** Utility class to read WebView configuration.
050 * 
051 * @author Daniel Crawl
052 * @version $Id: WebViewConfiguration.java 1405 2017-09-04 19:58:02Z crawl $
053 */
054public class WebViewConfiguration {
055
056    /** This class cannot be instantiated. */
057    private WebViewConfiguration() {
058        
059    }
060
061    /** Returns true if the http server table of contents should be enabled. */
062    public static boolean enableHttpServerTableOfContents() {        
063        return _getConfigurationBoolean("server.tableOfContents.enable", false);
064    }
065
066    /** Returns true if the http server should use ssl. */
067    public static boolean enableHttps() {
068        return _getConfigurationBoolean("server.ssl.enable", false);
069    }
070
071    /** Returns any models to be preloaded. */
072    public static Set<String> getPreloadModels() {
073        return _getConfigurationStrings("server.preload.model");        
074    }
075    
076    /** Returns the auth token for ROHUB. */
077    public static String getROHubAuthToken() {
078        return _getConfigurationString("server.roHub.authToken", null);
079    }
080    
081    /** Returns the URI for ROHUB REST API. */
082    public static String getROHubURI() {
083        return _getConfigurationString("server.roHub.uri", null);       
084    }
085    
086    /** Get the authorization group.
087     *  @param username The user name.
088     *  @param password The password.
089     *  @return Returns null if username not found, or password does not match.
090     */ 
091    public static String getSimpleAuthGroup(String username, String password) {
092        for(ConfigurationProperty property : _getConfigurationProperties("server.auth.entity")) {
093            if(property.getProperty("user").getValue().equals(username)) {
094                if(property.getProperty("password").getValue().equals(password)) {
095                    return property.getProperty("group").getValue();
096                }
097                // found user, but incorrect password.
098                return null;
099            }
100        }
101        // did not find user.
102        return null;
103    }
104    
105    /** Get the class name of an app. */
106    public static String getAppClassName(String appName) {
107        for(ConfigurationProperty property : _getConfigurationProperties("server.apps.app")) {
108            if(property.getProperty("name").getValue().equals(appName)) {
109                return property.getProperty("class").getValue();
110            }
111        }
112        return null;
113    }
114    
115    /** Get config properties for an app. */
116    public static List<ConfigurationProperty> getAppProperties(String appName, String confName) {
117
118        for(ConfigurationProperty property : _getConfigurationProperties("server.apps.app")) {
119            if(property.getProperty("name").getValue().equals(appName)) {
120                return property.getProperties(confName);
121            }
122        }
123        return new LinkedList<ConfigurationProperty>();
124    }
125
126    /** Get an authentication provider based on the authentication type
127     *  specified in the configuration.
128     */
129    public static AuthProvider getAuthProvider() {
130        String authType = _getConfigurationString("server.auth.type", null);
131        if(authType == null || authType.equals("simple")) {
132            return new SimpleAuth();
133        } else if(authType.equals("none")) {
134            System.err.println("WARNING: WebView server authentication disabled.");
135            return new NoneAuth();
136        } else if(authType.equals("drupal")) {
137            return new DrupalAuth(_getConfigurationString("server.auth.drupal.host", null),
138                _getConfigurationString("server.auth.drupal.service", null),
139                _getConfigurationString("server.auth.drupal.role", null),
140                _getConfigurationString("server.auth.drupal.groupsField", null),
141                _getConfigurationString("server.auth.drupal.fullNameField", null));
142
143        } else if(authType.equals("class")) {
144            String className = _getConfigurationString("server.auth.class", null);
145            if(className != null) {
146                try {
147                    Class<?> clazz = Class.forName(className);
148                    return (AuthProvider)clazz.newInstance();
149                } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
150                    System.err.println("ERROR: could not instantiate auth class " + className + ": " + e.getMessage());
151                    e.printStackTrace();
152                }
153            }
154        } else {
155            System.err.println("ERROR: unknown type of authentication: " + authType);
156        }
157        return null;
158    }
159
160    /** Get the CORS allow origin pattern. */
161    public static String getHttpServerCorsAllowOriginPattern() {
162        return _getConfigurationString("server.cors.allowOrigin", null);
163    }
164    
165    /** Returns true if the http server allows CORS. */
166    public static boolean getHttpServerCorsEnabled() {
167        return _getConfigurationBoolean("server.cors.enable", false);
168    }
169
170    /** Returns true if the http server allows workflows to be downloaded. */
171    public static boolean getHttpServerAllowWorkflowDownloads() {
172        return _getConfigurationBoolean("server.allowWorkflowDownloads", false);
173    }
174
175    public static boolean getHttpServerAppendIndexHtml() {
176        return _getConfigurationBoolean("server.appendIndexHtml", false);
177    }
178        
179    /** Get list of server directories that can be indexed. */
180    public static Set<String> getHttpServerDirectoriesToIndex() {
181        return _getConfigurationStrings("server.directoryIndex.dir");
182    }
183    
184    /** Get the number of instances of http servers to start. */
185    public static int getHttpServerInstances() {
186        
187        boolean wasParsed = CommandLineArgument.wasParsed(WEBVIEW_SERVER_INSTANCES_FLAG);
188        if(wasParsed) {
189            return Integer.valueOf(
190                CommandLineArgument.get(WEBVIEW_SERVER_INSTANCES_FLAG).getValue())
191                .intValue();
192        }        
193
194        return _getConfigurationInteger("server.instances", DEFAULT_WEBVIEW_SERVER_INSTANCES);
195    }
196    
197    /** Get the log directory and file name for the http server. */
198    public static String getHttpServerLogPath() {
199        return _getConfigurationString("server.logPath",
200            DotKeplerManager.getInstance().getPersistentModuleDirectory("web-view") +
201            File.separator +
202            "server.log");
203    }
204
205    /** Get the metadata file name. */
206    public static String getHttpServerMetadataFileName() {
207        String fileName = _getConfigurationString("server.metadataFile", null);
208        if(fileName != null && !fileName.startsWith(File.separator)) {
209            fileName = _getConfigurationModule("server.metadataFile").getConfigurationsDir() +
210                File.separator + fileName;
211        }
212        return fileName;
213    }
214
215    /* Get the port number for the http server. */
216    public static int getHttpServerPort() {
217        
218        boolean wasParsed = CommandLineArgument.wasParsed(WEBVIEW_SERVER_PORT_FLAG);
219        if(wasParsed) {
220            return Integer.valueOf(
221                CommandLineArgument.get(WEBVIEW_SERVER_PORT_FLAG).getValue())
222                .intValue();
223        }        
224
225        return _getConfigurationInteger("server.port", DEFAULT_WEBVIEW_SERVER_PORT);
226    }
227
228    /** Get the http redirect status code. */
229    public static int getHttpServerRedirectStatus() {
230        return _getConfigurationInteger("server.ssl.redirectHttp.status", HttpURLConnection.HTTP_MOVED_PERM);
231    }
232    
233    /** Get the hostname to redirect http requests to. */
234    public static String getHttpServerRedirectHostname() {
235        return _getConfigurationString("server.ssl.redirectHttp.hostname", "localhost");
236    }
237    
238    /** Get the port to redirect http requests to. */
239    public static int getHttpServerRedirectPort() {
240        return _getConfigurationInteger("server.ssl.redirectHttp.port", DEFAULT_WEBVIEW_SECURE_SERVER_PORT);
241    }
242
243    /** Returns the root directory for the HTTP Server. If none specified,
244     *  returns null.
245     */
246    public static String getHttpServerRootDir() {
247        
248        boolean wasParsed = CommandLineArgument.wasParsed(WEBVIEW_SERVER_ROOT_DIR_FLAG);
249        if(wasParsed) {
250            return CommandLineArgument.get(WEBVIEW_SERVER_ROOT_DIR_FLAG).getValue();
251        }        
252
253        return _getConfigurationString("server.rootDir", null);
254    }
255
256    /** Get the timeout, in milliseconds, for the session if not accessed. */
257    public static long getHttpServerSessionTimeout() {
258        return _getConfigurationLong("server.sessionTimeout",
259            DEFAULT_WEBVIEW_SERVER_SESSION_TIMEOUT);
260    }
261    
262    /** Get the path regex of the http server table of contents. */
263    public static String getHttpServerTableOfContentsPath() {
264        return _getConfigurationString("server.tableOfContents.pathRegex", null);
265    }
266    
267    /** Returns the number of threads for the worker pool. */
268    public static int getHttpServerWorkerThreads() {
269        return _getConfigurationInteger("server.workerThreads", 1);
270    }
271
272    /** Get the timeout, in milliseconds, for workflow execution.
273     * Returns -1 for no timeout.
274     */
275    public static long getHttpServerWorkflowTimeout() {
276        return _getConfigurationLong("server.workflowTimeout", -1);
277    }
278
279    /** Get the port number for the https server. */
280    public static int getHttpsServerPort() {
281        return _getConfigurationInteger("server.ssl.port", DEFAULT_WEBVIEW_SECURE_SERVER_PORT);
282    }
283
284    /** Get the SSL PEM Key file path. */
285    public static String getHttpsPEMKeyPath() {
286        return _getConfigurationString("server.ssl.key", null);
287    }
288
289    /** Get the SSL PEM Certificate file path.*/
290    public static String getHttpsPEMCertPath() {
291        return _getConfigurationString("server.ssl.cert", null);
292    }
293        
294    public static boolean shouldHttpServerRedirect() {
295        return _getConfigurationBoolean("server.ssl.redirectHttp.enable", false);
296    }
297
298    /** Returns true if the web view http server should start. */
299    public static boolean shouldStartHttpServer() {
300        
301        boolean retval = CommandLineArgument.wasParsed(WEBVIEW_START_SERVER_FLAG);
302                
303        if(!retval) {
304            retval = _getConfigurationBoolean("server.startServer", false);
305        }
306        
307        return retval;
308    }
309    
310    /** Returns true if the web view http server should start in daemon mode. */
311    public static boolean shouldStartHttpServerAsDaemon() {
312        
313        boolean retval = CommandLineArgument.wasParsed(WEBVIEW_SERVER_DAEMON_FLAG);
314        
315        if(!retval) {
316            return _getConfigurationBoolean("server.daemon", false);
317        }
318        
319        return retval;
320    }
321
322    ///////////////////////////////////////////////////////////////////
323    ////                         public variables                  ////
324
325    /** Command line flag to specify the server port. */
326    public final static String WEBVIEW_SERVER_PORT_FLAG = "-wvport";
327    
328    /** The default server port. */
329    public final static int DEFAULT_WEBVIEW_SERVER_PORT = 9122;
330    
331    /** The default secure sever port. */
332    public final static int DEFAULT_WEBVIEW_SECURE_SERVER_PORT = 8443;
333    
334    /** Command line flag to specify the root directory. */
335    public final static String WEBVIEW_SERVER_ROOT_DIR_FLAG = "-wvroot";
336    
337    /** The default root directory. */
338    public final static String DEFAULT_WEBVIEW_SERVER_ROOT_DIR = "web-view/resources/html";
339
340    /** Command line flag to start the server. */
341    public final static String WEBVIEW_START_SERVER_FLAG = "-wv";
342    
343    /** Command line flag to run the server in daemon mode. */
344    public final static String WEBVIEW_SERVER_DAEMON_FLAG = "-wvd";
345
346    /** Command line flag to specify the number of server instances. */
347    public final static String WEBVIEW_SERVER_INSTANCES_FLAG = "-wvnum";
348    
349    /** The default number of server instances. */
350    public final static int DEFAULT_WEBVIEW_SERVER_INSTANCES = 1;
351
352    ///////////////////////////////////////////////////////////////////
353    ////                         private methods                   ////
354
355    /** Get a configuration property in the web-view config file. */
356    private static ConfigurationProperty _getConfigurationProperty(String path) {
357        return ConfigurationManager.getInstance()
358                .getProperty(ConfigurationManager.getModule("web-view")).getProperty(path);
359    }
360
361    /** Get a list of configuration properties in the web-view config file. */
362    private static List<ConfigurationProperty> _getConfigurationProperties(String path) {
363        return ConfigurationManager.getInstance()
364                .getProperties(ConfigurationManager.getModule("web-view"), path);
365    }
366
367    /** Get a configuration value in the web-view config file. Returns
368     *  the default value if the path does not exist or is not set.
369     */
370    private static String _getConfigurationString(String path, String defaultValue) {
371        ConfigurationProperty property = _getConfigurationProperty(path);
372        if(property != null) {
373            String value = property.getValue();
374            if(value != null) {
375                return value;
376            }
377        }
378        return defaultValue;
379    }
380    
381    /** Get set of strings from multiple configuration values with the same name. */
382    private static Set<String> _getConfigurationStrings(String path) {
383        Set<String> retval = new HashSet<String>();
384        for(ConfigurationProperty property: _getConfigurationProperties(path)) {
385            retval.add(property.getValue());
386        }
387        return retval;
388    }
389        
390    /** Get a boolean configuration value in the web-view config file. */
391    private static boolean _getConfigurationBoolean(String path, boolean defaultValue) {
392        String value = _getConfigurationString(path, null);
393        if(value != null) {
394            return Boolean.valueOf(value);
395        }
396        return defaultValue;
397    }
398    
399    /** Get an integer configuration value in the web-view config file. */
400    private static int _getConfigurationInteger(String path, int defaultValue) {
401        String value = _getConfigurationString(path, null);
402        if(value != null) {
403            return Integer.valueOf(value);
404        }
405        return defaultValue;
406    }
407    
408    /** Get a long configuration value in the web-view config file. */
409    private static long _getConfigurationLong(String path, long defaultValue) {
410        String value = _getConfigurationString(path, null);
411        if(value != null) {
412            return Long.valueOf(value);
413        }
414        return defaultValue;
415    }
416
417    private static Module _getConfigurationModule(String path) {
418        ConfigurationProperty property = _getConfigurationProperty(path);
419        if(property != null) {
420            return property.getModule();
421        }
422        return null;
423    }
424
425    /** Default session timeout in milliseconds */
426    private static final long DEFAULT_WEBVIEW_SERVER_SESSION_TIMEOUT = 3600*1000;
427
428    public static boolean deployInKubernetes() {
429        return _getConfigurationBoolean("server.cluster.deployInKubernetes", false);
430    }
431
432    public static String getHazelcastDiscoveryDnsServiceName() {
433        return _getConfigurationString("server.cluster.hazelcastDiscoveryK8sDnsService", null);
434    }
435
436    /** Get if vertx should use hazelcast for clustered mode. */
437    public static boolean shouldStartClusterHazelcast() {
438        String typeStr = _getConfigurationString("server.cluster.type", null);
439        return (typeStr != null && typeStr.equals("hazelcast"));
440    }
441    
442    /** Get if vertx should start in clustered mode. */
443    public static boolean shouldStartCluster() {
444        String typeStr = _getConfigurationString("server.cluster.type", null);
445        return (typeStr != null && typeStr.trim().length() > 0 &&
446                !typeStr.toLowerCase().equals("none") &&
447                !typeStr.toLowerCase().equals("false"));
448    }
449
450}