Sat, 31 Mar 2018 18:11:09 +0200
removes the privileged data source from the application and the ability to have a web UI for a setup
This is a permanent decision: setups should be performed on the server by some admin. There is too much, which could go wrong and we have little chance to catch anything within a web UI.
--- a/src/java/de/uapcore/lightpit/Constants.java Sun Dec 31 17:43:39 2017 +0100 +++ b/src/java/de/uapcore/lightpit/Constants.java Sat Mar 31 18:11:09 2018 +0200 @@ -59,6 +59,11 @@ public static final String CTX_ATTR_DB_SCHEMA = "db-schema"; /** + * Name for the context parameter optionally specifying a database dialect. + */ + public static final String CTX_ATTR_DB_DIALECT = "db-dialect"; + + /** * Key for the request attribute containing the class name of the currently dispatching module. */ public static final String REQ_ATTR_MODULE_CLASSNAME = fqn(AbstractLightPITServlet.class, "moduleClassname");
--- a/src/java/de/uapcore/lightpit/DatabaseFacade.java Sun Dec 31 17:43:39 2017 +0100 +++ b/src/java/de/uapcore/lightpit/DatabaseFacade.java Sat Mar 31 18:11:09 2018 +0200 @@ -56,76 +56,52 @@ */ private static final int DB_TEST_TIMEOUT = 10; + public static enum Dialect { + Postgres; + } + + /** + * The database dialect to use. + * + * May be override by context parameter. + * + * @see Constants#CTX_ATTR_DB_DIALECT + */ + private Dialect dialect = Dialect.Postgres; + /** * The default schema to test against when validating the connection. * * May be overridden by context parameter. + * + * @see Constants#CTX_ATTR_DB_SCHEMA */ private static final String DB_DEFAULT_SCHEMA = "lightpit"; /** - * The attribute name in the servlet context under which an instance of this class can be found. + * The attribute name in the Servlet context under which an instance of this class can be found. */ public static final String SC_ATTR_NAME = DatabaseFacade.class.getName(); private ServletContext sc; - private static final String PRIVILEGED_DS_JNDI_NAME = "jdbc/lightpit/dbo"; - private Optional<DataSource> privilegedDataSource; + private static final String DS_JNDI_NAME = "jdbc/lightpit/app"; + private Optional<DataSource> dataSource; - private static final String UNPRIVILEGED_DS_JNDI_NAME = "jdbc/lightpit/app"; - private Optional<DataSource> unprivilegedDataSource; - - /** - * Returns an optional privileged data source. - * - * Privileged data sources should be able to execute any kind of DDL - * statements to perform installation or configuration steps. - * - * This optional should always be empty in live operation. Modules which - * provide installation or configuration steps MUST check the presence of - * a privileged data source and SHOULD display an informative message if - * it is currently disabled. - * - * @return an optional privileged data source - */ - public Optional<DataSource> getPrivilegedDataSource() { - return privilegedDataSource; - } - - /** - * Returns an optional unprivileged data source. + * Returns the data source. * * The Optional returned should never be empty. However, if something goes * wrong during initialization, the data source might be absent. * Hence, users of this data source are forced to check the existence. * - * @return an optional unprivileged data source - */ - public Optional<DataSource> getUnprivilegedDataSource() { - return unprivilegedDataSource; - } - - /** - * Returns the JNDI resource name of the privileged data source. - * - * Modules may use this information to provide useful information to the user. - * - * @return the JNDI resource name of the privileged data source + * @return a data source */ - public String getPrivilegedDataSourceJNDIName() { - return PRIVILEGED_DS_JNDI_NAME; + public Optional<DataSource> getDataSource() { + return dataSource; } - - /** - * Returns the JNDI resource name of the unprivileged data source. - * - * Modules may use this information to provide useful information to the user. - * - * @return the JNDI resource name of the unprivileged data source - */ - public String getUnprivilegedDataSourceJNDIName() { - return UNPRIVILEGED_DS_JNDI_NAME; + + public Dialect getSQLDialect() { + return dialect; } private static void checkConnection(DataSource ds, String testSchema, String errMsg) { @@ -146,28 +122,13 @@ } } - private static Optional<DataSource> retrievePrivilegedDataSource(Context ctx) { + private static Optional<DataSource> retrieveDataSource(Context ctx) { DataSource ret = null; try { - ret = (DataSource)ctx.lookup(PRIVILEGED_DS_JNDI_NAME); - LOG.info("Privileged data source {} retrieved from context.", PRIVILEGED_DS_JNDI_NAME); - LOG.warn("Your application may be vulnerable due to privileged database access. Make sure that privileged data sources are only available during installation or configuration."); + ret = (DataSource)ctx.lookup(DS_JNDI_NAME); + LOG.info("Data source retrieved."); } catch (NamingException ex) { - LOG.info("Privileged data source not available. This is perfectly OK. Activate only, if you need to do installation or configuration."); - /* in case the absence of the DataSource is not intended, log something more useful on debug level */ - LOG.debug("Reason for the missing data source: ", ex); - } - return Optional.ofNullable(ret); - } - - private static Optional<DataSource> retrieveUnprivilegedDataSource(Context ctx) { - DataSource ret = null; - try { - ret = (DataSource)ctx.lookup(UNPRIVILEGED_DS_JNDI_NAME); - LOG.info("Unprivileged data source retrieved."); - } catch (NamingException ex) { - LOG.error("Unprivileged data source {} not available.", UNPRIVILEGED_DS_JNDI_NAME); - /* for the unprivileged DataSource log the exception on error level (ordinary admins could find this useful) */ + LOG.error("Data source {} not available.", DS_JNDI_NAME); LOG.error("Reason for the missing data source: ", ex); } return Optional.ofNullable(ret); @@ -177,7 +138,7 @@ public void contextInitialized(ServletContextEvent sce) { sc = sce.getServletContext(); - privilegedDataSource = unprivilegedDataSource = null; + dataSource = null; final String contextName = Optional .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT)) @@ -185,17 +146,23 @@ final String dbSchema = Optional .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA)) .orElse(DB_DEFAULT_SCHEMA); + final String dbDialect = sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT); + if (dbDialect != null) { + try { + dialect = Dialect.valueOf(dbDialect); + } catch (IllegalArgumentException ex) { + LOG.error(String.format("Unknown or unsupported database dialect %s. Defaulting to %s.", dbDialect, dialect)); + } + } try { LOG.debug("Trying to access JNDI context {}...", contextName); Context initialCtx = new InitialContext(); Context ctx = (Context) initialCtx.lookup(contextName); - privilegedDataSource = retrievePrivilegedDataSource(ctx); - unprivilegedDataSource = retrieveUnprivilegedDataSource(ctx); + dataSource = retrieveDataSource(ctx); - privilegedDataSource.ifPresent((ds) -> checkConnection(ds, dbSchema, "Checking privileged connection failed")); - unprivilegedDataSource.ifPresent((ds) -> checkConnection(ds, dbSchema, "Checking unprivileged connection failed")); + dataSource.ifPresent((ds) -> checkConnection(ds, dbSchema, "Checking database connection failed")); } catch (NamingException | ClassCastException ex) { LOG.error("Cannot access JNDI resources.", ex); } @@ -206,6 +173,6 @@ @Override public void contextDestroyed(ServletContextEvent sce) { - privilegedDataSource = unprivilegedDataSource = null; + dataSource = null; } }
--- a/web/META-INF/context.xml Sun Dec 31 17:43:39 2017 +0100 +++ b/web/META-INF/context.xml Sat Mar 31 18:11:09 2018 +0200 @@ -2,10 +2,5 @@ <Context path="/lightpit"> <ResourceLink name="jdbc/lightpit/app" global="jdbc/lightpit/app" - type="javax.sql.DataSource" /> - - <!-- Remove this link after installation and configuration --> - <ResourceLink name="jdbc/lightpit/dbo" - global="jdbc/lightpit/dbo" - type="javax.sql.DataSource" /> + type="javax.sql.DataSource" /> </Context>