All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fcrepo.utilities.install.FedoraHome Maven / Gradle / Ivy

/* The contents of this file are subject to the license and copyright terms
 * detailed in the license directory at the root of the source tree (also
 * available online at http://fedora-commons.org/license/).
 */

package org.fcrepo.utilities.install;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Properties;

import org.apache.commons.io.IOUtils;
import org.fcrepo.server.config.ModuleConfiguration;
import org.fcrepo.server.config.ServerConfiguration;
import org.fcrepo.server.config.ServerConfigurationParser;
import org.fcrepo.server.resourceIndex.ResourceIndex;
import org.fcrepo.server.security.BESecurityConfig;
import org.fcrepo.server.security.DefaultRoleConfig;
import org.fcrepo.server.security.servletfilters.xmluserfile.FedoraUsers;
import org.fcrepo.server.security.servletfilters.xmluserfile.User;
import org.fcrepo.utilities.ExecUtility;
import org.fcrepo.utilities.FileUtils;
import org.fcrepo.utilities.Zip;

public class FedoraHome {

	private final Distribution _dist;

	private final InstallOptions _opts;

	private final File _installDir;

	private final boolean _clientOnlyInstall;

	private InetAddress _host;

	private LLStoreType _usingAkubra;

	public FedoraHome(Distribution dist, InstallOptions opts) {
		_dist = dist;
		_opts = opts;
		_installDir = new File(_opts.getValue(InstallOptions.FEDORA_HOME));
		_clientOnlyInstall = _opts.getValue(InstallOptions.INSTALL_TYPE)
				.equals(InstallOptions.INSTALL_CLIENT);
	}

	public void install() throws InstallationFailedException {
		unpack();

		if (!_clientOnlyInstall) {
			configure();
		}
	}

	/**
	 * Unpacks the contents of the FEDORA_HOME directory from the Distribution.
	 * 
	 * @throws InstallationFailedException
	 */
	private void unpack() throws InstallationFailedException {
		System.out.println("Preparing FEDORA_HOME...");

		if (!_installDir.exists() && !_installDir.mkdirs()) {
			throw new InstallationFailedException(
					"Unable to create FEDORA_HOME: "
							+ _installDir.getAbsolutePath());
		}
		if (!_installDir.isDirectory()) {
			throw new InstallationFailedException(_installDir.getAbsolutePath()
					+ " is not a directory");
		}
		try {
			Zip.unzip(_dist.get(Distribution.FEDORA_HOME), _installDir);
			setScriptsExecutable(new File(_installDir, "client"
					+ File.separator + "bin"));

			File serverDir = new File(_installDir, "server");
			if (_clientOnlyInstall) {
				FileUtils.delete(serverDir);
			} else {
				setScriptsExecutable(new File(serverDir, "bin"));
			}
		} catch (IOException e) {
			throw new InstallationFailedException(e.getMessage(), e);
		}
	}

	/**
	 * Sets various configuration files based on InstallOptions
	 * 
	 * @throws InstallationFailedException
	 */
	private void configure() throws InstallationFailedException {
		configureFCFG();
        configureAkubra();
		configureSpringProperties();
		configureSpringAuth();
		configureFedoraUsers();
		configureBeSecurity();
		configureSpringTestConfigs();
	}

	private void configureFCFG() throws InstallationFailedException {
		System.out.println("\tConfiguring fedora.fcfg");
		File fcfgBase = new File(_installDir,
				"server/fedora-internal-use/config/fedora-base.fcfg");
		File fcfg = new File(_installDir, "server/config/fedora.fcfg");

		Properties props = new Properties();
		if (_opts.getValue(InstallOptions.TOMCAT_HTTP_PORT) != null) {
			props.put("server:fedoraServerPort",
					_opts.getValue(InstallOptions.TOMCAT_HTTP_PORT));
		}
		if (_opts.getValue(InstallOptions.TOMCAT_SHUTDOWN_PORT) != null) {
			props.put("server:fedoraShutdownPort",
					_opts.getValue(InstallOptions.TOMCAT_SHUTDOWN_PORT));
		}
		if (_opts.getValue(InstallOptions.TOMCAT_SSL_PORT) != null) {
			props.put("server:fedoraRedirectPort",
					_opts.getValue(InstallOptions.TOMCAT_SSL_PORT));
		}
		if (_opts.getValue(InstallOptions.FEDORA_SERVERHOST) != null) {
			props.put("server:fedoraServerHost",
					_opts.getValue(InstallOptions.FEDORA_SERVERHOST));
		}

		if (_opts.getValue(InstallOptions.FEDORA_APP_SERVER_CONTEXT) != null) {
			props.put("server:fedoraAppServerContext",
					_opts.getValue(InstallOptions.FEDORA_APP_SERVER_CONTEXT));
		}

		String database = _opts.getValue(InstallOptions.DATABASE);
		String dbPoolName = "";
		String backslashIsEscape = "true";
		if (database.equals(InstallOptions.DERBY)
				|| database.equals(InstallOptions.INCLUDED)) {
			dbPoolName = "localDerbyPool";
			backslashIsEscape = "false";
		} else if (database.equals(InstallOptions.MYSQL)) {
			dbPoolName = "localMySQLPool";
		} else if (database.equals(InstallOptions.ORACLE)) {
			dbPoolName = "localOraclePool";
			backslashIsEscape = "false";
		} else if (database.equals(InstallOptions.POSTGRESQL)) {
			dbPoolName = "localPostgreSQLPool";
		} else {
			throw new InstallationFailedException(
					"unable to configure for unknown database: " + database);
		}
		props.put("module.org.fcrepo.server.storage.DOManager:storagePool",
				dbPoolName);
		props.put("module.org.fcrepo.server.search.FieldSearch:connectionPool",
				dbPoolName);
		props.put(
				"module.org.fcrepo.server.storage.ConnectionPoolManager:poolNames",
				dbPoolName);
		props.put(
				"module.org.fcrepo.server.storage.ConnectionPoolManager:defaultPoolName",
				dbPoolName);
		props.put(
				"module.org.fcrepo.server.storage.lowlevel.ILowlevelStorage:backslash_is_escape",
				backslashIsEscape);
		props.put("datastore." + dbPoolName + ":jdbcURL",
				_opts.getValue(InstallOptions.DATABASE_JDBCURL));
		props.put("datastore." + dbPoolName + ":dbUsername",
				_opts.getValue(InstallOptions.DATABASE_USERNAME));
		props.put("datastore." + dbPoolName + ":dbPassword",
				_opts.getValue(InstallOptions.DATABASE_PASSWORD));
		props.put("datastore." + dbPoolName + ":jdbcDriverClass",
				_opts.getValue(InstallOptions.DATABASE_DRIVERCLASS));

		if (_opts.getBooleanValue(InstallOptions.XACML_ENABLED, true)) {
			props.put(
					"module.org.fcrepo.server.security.Authorization:ENFORCE-MODE",
					"enforce-policies");
		} else {
			props.put(
					"module.org.fcrepo.server.security.Authorization:ENFORCE-MODE",
					"permit-all-requests");
		}

		if (_opts.getBooleanValue(InstallOptions.RI_ENABLED, true)) {
			props.put(
					"module.org.fcrepo.server.resourceIndex.ResourceIndex:level",
					String.valueOf(ResourceIndex.INDEX_LEVEL_ON));
		} else {
			props.put(
					"module.org.fcrepo.server.resourceIndex.ResourceIndex:level",
					String.valueOf(ResourceIndex.INDEX_LEVEL_OFF));
		}

		if (_opts.getBooleanValue(InstallOptions.MESSAGING_ENABLED, false)) {
			props.put("module.org.fcrepo.server.messaging.Messaging:enabled",
					String.valueOf(true));
			props.put(
					"module.org.fcrepo.server.messaging.Messaging:java.naming.provider.url",
					_opts.getValue(InstallOptions.MESSAGING_URI));
		} else {
			props.put("module.org.fcrepo.server.messaging.Messaging:enabled",
					String.valueOf(false));
		}

		props.put(
				"module.org.fcrepo.server.access.Access:doMediateDatastreams",
				_opts.getValue(InstallOptions.APIA_AUTH_REQUIRED));

		// FeSL AuthZ needs a management decorator for syncing the policy cache
		// with policies in objects
		if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
			// NOTE: assumes messaging decorator only is present in
			// fedora-base.fcfg as decorator1
			props.put(
					"module.org.fcrepo.server.management.Management:decorator2",
					"org.fcrepo.server.security.xacml.pdp.decorator.PolicyIndexInvocationHandler");
		}

		try {
			FileInputStream fis = new FileInputStream(fcfgBase);
			ServerConfiguration config = new ServerConfigurationParser(fis)
					.parse();
			config.applyProperties(props);

			// If using akubra-fs, set the class of the module and clear params.
			if (usingAkubra()) {
				ModuleConfiguration mConfig = config
						.getModuleConfiguration("org.fcrepo.server.storage.lowlevel.ILowlevelStorage");
				config.getModuleConfigurations().remove(mConfig);
			}

			config.serialize(new FileOutputStream(fcfg));
		} catch (IOException e) {
			throw new InstallationFailedException(e.getMessage(), e);
		}
	}

	private void configureAkubra() throws InstallationFailedException {
	    if (usingAkubra()) {
    		// Rewrite server/config/akubra-llstore.xml replacing the
    		// /tmp/[object|datastream]Store constructor-arg values
    		// with $FEDORA_HOME/data/[object|datastream]Store
    		BufferedReader reader = null;
    		PrintWriter writer = null;
    		try {
    			File file = new File(_installDir,
    					"server/config/spring/akubra-llstore.xml");
    			reader = new BufferedReader(new InputStreamReader(
    					new FileInputStream(file), "UTF-8"));
    
    			File dataDir = new File(_installDir, "data");
    			String oPath = dataDir.getPath() + File.separator + "objectStore";
    			String dPath = dataDir.getPath() + File.separator
    					+ "datastreamStore";
    			StringBuilder xml = new StringBuilder();
    
    			String line = reader.readLine();
    			while (line != null) {
    				if (line.indexOf("/tmp/objectStore") != -1) {
    					line = "    ";
    				} else if (line.indexOf("/tmp/datastreamStore") != -1) {
    					line = "    ";
    				}
    				xml.append(line + "\n");
    				line = reader.readLine();
    			}
    			reader.close();
    
    			writer = new PrintWriter(new OutputStreamWriter(
    					new FileOutputStream(file), "UTF-8"));
    			writer.print(xml.toString());
    			writer.close();
    		} catch (IOException e) {
    			IOUtils.closeQuietly(reader);
    			IOUtils.closeQuietly(writer);
    			throw new InstallationFailedException(e.getClass().getName() + ":"
    					+ e.getMessage());
    		}
	    } else {
	        // remove the stub akubra configuration
            File file = new File(_installDir,
                    "server/config/spring/akubra-llstore.xml");
            file.delete();
            if (file.exists()){
                throw new InstallationFailedException("Could not remove a conflicting config: akubra-llstore.xml");
            }
	    }
	}

	private void configureSpringProperties() throws InstallationFailedException {
		Properties springProps = new Properties();

		/* Set up ssl configuration */
		springProps.put("fedora.port",
				_opts.getValue(InstallOptions.TOMCAT_HTTP_PORT, "8080"));
		if (_opts.getBooleanValue(InstallOptions.SSL_AVAILABLE, false)) {
			springProps.put("fedora.port.secure",
					_opts.getValue(InstallOptions.TOMCAT_SSL_PORT, "8443"));
		} else {
			springProps.put("fedora.port.secure",
					_opts.getValue(InstallOptions.TOMCAT_HTTP_PORT, "8080"));
		}

		springProps
				.put("security.ssl.api.access",
						_opts.getBooleanValue(InstallOptions.APIA_SSL_REQUIRED,
								false) ? "REQUIRES_SECURE_CHANNEL"
								: "ANY_CHANNEL");
		springProps
				.put("security.ssl.api.management",
						_opts.getBooleanValue(InstallOptions.APIM_SSL_REQUIRED,
								false) ? "REQUIRES_SECURE_CHANNEL"
								: "ANY_CHANNEL");
		springProps.put("security.ssl.api.default", "ANY_CHANNEL");

		springProps.put("security.fesl.authN.jaas.apia.enabled",
				_opts.getValue(InstallOptions.APIA_AUTH_REQUIRED, "false"));

		springProps.put("security.fesl.authZ.enabled",
				_opts.getValue(InstallOptions.FESL_AUTHZ_ENABLED, "false"));

		/* Set up authN, authZ filter configuration */
		StringBuilder filters = new StringBuilder();
        if (_opts.getBooleanValue(InstallOptions.FESL_AUTHN_ENABLED, true)) {
			filters.append("AuthFilterJAAS");
		} else {
			filters.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
		}

		if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
			filters.append(",PEPFilter");
		}

		springProps.put("security.auth.filters", filters.toString());

		FileOutputStream out = null;
		try {
			out = new FileOutputStream(new File(_installDir,
					"server/config/spring/web/web.properties"));
			springProps.store(out, "Spring override properties");
		} catch (IOException e) {
			throw new InstallationFailedException(e.getMessage(), e);
		} finally {
			IOUtils.closeQuietly(out);
		}
	}

	/*
	 * This is an ugly workaround for the fact that spring security namespace
	 * config does not support property substitution into lists of beans. It is
	 * also ugly because
	 */
	private void configureSpringAuth() throws InstallationFailedException {
		String PATTERN = "${security.auth.filters}";
		String PATTERN_APIA = "${security.auth.filters.apia}";
		String PATTERN_REST = "${security.auth.filters.rest}";

		boolean fesl_authn_enabled = _opts.getBooleanValue(
InstallOptions.FESL_AUTHN_ENABLED, true);
		boolean apia_auth_required = _opts.getBooleanValue(
				InstallOptions.APIA_AUTH_REQUIRED, false);
		boolean upstream_auth_enabled = _opts.getBooleanValue(
				InstallOptions.UPSTREAM_AUTH_ENABLED, false);

		StringBuilder filters = new StringBuilder();
		StringBuilder filters_apia = new StringBuilder();
		StringBuilder filters_rest = new StringBuilder();

		boolean needsbugFix = false;

		if (fesl_authn_enabled) {
			filters.append("AuthFilterJAAS");
			filters_apia.append("AuthFilterJAAS");
			filters_rest.append("AuthFilterJAAS");
		} else if (upstream_auth_enabled) {
			// use upstream auth filter and nothing else
			String upstreamAuthFilter = "UpstreamAuthFilter";
			filters.append(upstreamAuthFilter);
			filters_apia.append(upstreamAuthFilter);
			filters_rest.append(upstreamAuthFilter);
		}
		else {
			filters.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
			if (apia_auth_required) {
				filters_apia
						.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
				filters_rest
						.append("SetupFilter,XmlUserfileFilter,EnforceAuthnFilter,FinalizeFilter");
			} else {
				filters_apia.append("");
				filters_rest
						.append("SetupFilter,XmlUserfileFilter,RestApiAuthnFilter,FinalizeFilter");
			}

			needsbugFix = true;
		}

		if (_opts.getBooleanValue(InstallOptions.FESL_AUTHZ_ENABLED, false)) {
			filters.append(",PEPFilter");
			filters_apia.append(",PEPFilter");
			filters_rest.append(",PEPFilter");
			copyFESLConfigs();
		}

		FileInputStream springConfig = null;
		PrintWriter writer = null;
		try {
			File xmlFile = new File(_installDir,
					"server/config/spring/web/security.xml");
			springConfig = new FileInputStream(xmlFile);
			String content = IOUtils.toString(springConfig)
					.replace(PATTERN, filters)
					.replace(PATTERN_APIA, filters_apia)
					.replace(PATTERN_REST, filters_rest);

			if (!needsbugFix) {
				/* Delete classic authN bugfix when not applicable */
				content = content.replaceFirst("(?s)", "");
			}

			springConfig.close();

			writer = new PrintWriter(new OutputStreamWriter(
					new FileOutputStream(xmlFile), "UTF-8"));
			writer.print(content);
			writer.close();
		} catch (Exception e) {
			IOUtils.closeQuietly(springConfig);
			IOUtils.closeQuietly(writer);
			throw new InstallationFailedException(e.getMessage(), e);
		}
	}

	private void copyFESLConfigs() throws InstallationFailedException {
		File feslWebDir = new File(_installDir, "server/config/spring/fesl/web");
		File feslModuleDir = new File(_installDir,
				"server/config/spring/fesl/module");
		File webDir = new File(_installDir, "server/config/spring/web");
		File moduleDir = new File(_installDir, "server/config/spring");

		for (File beanDef : feslWebDir.listFiles()) {
			if (beanDef.isFile()) {
				FileReader reader = null;
				FileWriter writer = null;
				try {
					File copy = new File(webDir, beanDef.getName());
					reader = new FileReader(beanDef);
					writer = new FileWriter(copy);
					IOUtils.copy(reader, writer);
					writer.flush();
				} catch (Exception e) {
					throw new InstallationFailedException(e.getMessage(), e);
				} finally {
					IOUtils.closeQuietly(writer);
					IOUtils.closeQuietly(reader);
				}
			}
		}
		for (File beanDef : feslModuleDir.listFiles()) {
			if (beanDef.isFile()) {
				FileReader reader = null;
				FileWriter writer = null;
				try {
					File copy = new File(moduleDir, beanDef.getName());
					reader = new FileReader(beanDef);
					writer = new FileWriter(copy);
					IOUtils.copy(reader, writer);
					writer.flush();
				} catch (Exception e) {
					throw new InstallationFailedException(e.getMessage(), e);
				} finally {
					IOUtils.closeQuietly(writer);
					IOUtils.closeQuietly(reader);
				}
			}
		}
	}

	private void configureSpringTestConfigs()
			throws InstallationFailedException {
		if (_opts.getBooleanValue(InstallOptions.TEST_SPRING_CONFIGS, false)) {
			FileInputStream springConfig = null;
			PrintWriter writer = null;
			try {
				File springDir = new File(_installDir, "server/config/spring");
				for (File file : springDir.listFiles()) {
					if (file.isFile()) {
						springConfig = new FileInputStream(file);
						String content = IOUtils.toString(springConfig);
						content = content.replaceAll(
								"(?s)", "$1");
						springConfig.close();

						writer = new PrintWriter(new OutputStreamWriter(
								new FileOutputStream(file), "UTF-8"));
						writer.print(content);
						writer.close();
					}
				}
			} catch (Exception e) {
				IOUtils.closeQuietly(springConfig);
				IOUtils.closeQuietly(writer);
				throw new InstallationFailedException(e.getMessage(), e);
			}
		}
	}

	private void configureFedoraUsers() throws InstallationFailedException {
		FedoraUsers fu = FedoraUsers.getInstance();
		for (User user : fu.getUsers()) {
			if (user.getName().equals("fedoraAdmin")) {
				user.setPassword(_opts
						.getValue(InstallOptions.FEDORA_ADMIN_PASS));
			}
		}

		try {
			Writer outputWriter = new BufferedWriter(new FileWriter(
					FedoraUsers.fedoraUsersXML));
			fu.write(outputWriter);
			outputWriter.close();
		} catch (IOException e) {
			throw new InstallationFailedException(e.getMessage(), e);
		}
	}

	private void configureBeSecurity() throws InstallationFailedException {
		System.out.println("\tInstalling beSecurity");
		File beSecurity = new File(_installDir, "/server/config/beSecurity.xml");
		boolean apiaAuth = _opts.getBooleanValue(
				InstallOptions.APIA_AUTH_REQUIRED, false);
		boolean apiaSSL = _opts.getBooleanValue(
				InstallOptions.APIA_SSL_REQUIRED, false);
		// boolean apimSSL =
		// _opts.getBooleanValue(InstallOptions.APIM_SSL_REQUIRED, false);

		String[] ipList;
		String host = _opts.getValue(InstallOptions.FEDORA_SERVERHOST);
		if (host != null && host.length() != 0
				&& !(host.equals("localhost") || host.equals("127.0.01"))) {
			ipList = new String[] { "127.0.0.1", getHost() };
		} else {
			ipList = new String[] { "127.0.0.1" };
		}

		PrintWriter pwriter;
		try {
			pwriter = new PrintWriter(new FileOutputStream(beSecurity));
		} catch (FileNotFoundException e) {
			throw new InstallationFailedException(e.getMessage(), e);
		}
		BESecurityConfig becfg = new BESecurityConfig();

		becfg.setDefaultConfig(new DefaultRoleConfig());
		becfg.setInternalBasicAuth(new Boolean(apiaAuth));
		becfg.setInternalIPList(ipList);
		becfg.setInternalPassword("changeme");
		becfg.setInternalSSL(new Boolean(apiaSSL));
		becfg.setInternalUsername("fedoraIntCallUser");
		becfg.write(true, true, pwriter);
		pwriter.close();
	}

	private String getHost() throws InstallationFailedException {
		if (_host == null) {
			String host = _opts.getValue(InstallOptions.FEDORA_SERVERHOST);
			try {
				_host = InetAddress.getByName(host);
			} catch (UnknownHostException e) {
				throw new InstallationFailedException(e.getMessage(), e);
			}
		}
		return _host.getHostAddress();
	}
	
	private boolean usingAkubra() {
	    if (_usingAkubra == null) {
            String llStoreType = _opts.getValue(InstallOptions.LLSTORE_TYPE);
            if (llStoreType == null || llStoreType.equals("akubra-fs")) {
                _usingAkubra = LLStoreType.akubra_fs;
            } else {
                _usingAkubra = LLStoreType.legacy_fs;
            }
	    }
	    return LLStoreType.akubra_fs == _usingAkubra;
	}

	/**
	 * Make scripts (ending with .sh) executable on *nix systems.
	 */
	public static void setScriptsExecutable(File dir) {
		String os = System.getProperty("os.name");
		if (os != null && !os.startsWith("Windows")) {
			FileFilter filter = FileUtils.getSuffixFileFilter(".sh");
			setExecutable(dir, filter);
		}
	}

	private static void setExecutable(File dir, FileFilter filter) {
		File[] files;
		if (filter != null) {
			files = dir.listFiles(filter);
		} else {
			files = dir.listFiles();
		}
		for (File element : files) {
			ExecUtility.exec(new String[] { "chmod", "+x",
					element.getAbsolutePath() });
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy