package org.cagrid.gridgrouper.service.tools; import java.io.File; import java.io.FileOutputStream; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Properties; import org.apache.commons.lang.StringUtils; import org.cagrid.core.commandline.BaseCommandLine; import org.cagrid.gaards.pki.CertUtil; import org.cagrid.gaards.pki.KeyUtil; import org.cagrid.gridgrouper.service.impl.GridGrouper; import edu.internet2.middleware.grouper.GrouperConfigHelper; import edu.internet2.middleware.grouper.RegistryInstall; import edu.internet2.middleware.grouper.RegistryReset; import edu.internet2.middleware.subject.GridSourceAdapter; import edu.internet2.middleware.subject.Subject; public class Bootstrapper extends BaseCommandLine { private static final String PROPERTIES_FILE = "src/main/resources/bootstrapper.properties"; private static final String GROUPER_SERVICE_DIR = "cagrid-grid-grouper"; private static final String GROUPER_SERVICE_CFG = "cagrid.gridgrouper.service.cfg"; private static final String GROUPER_CFG = "cagrid.gridgrouper.internet2.cfg"; private static final String GROUPER_WSRF_CFG = "cagrid.gridgrouper.wsrf.cfg"; public static final String CONFIGURE_LEGACY_WSRF_PROMPT = "Do you want to configure a Legacy WSRF Endpoint (true|false)"; public static final String CONFIGURE_LEGACY_WSRF_PROPERTY = "cagrid.gridgrouper.configure.legacy.wsrf"; private static final String TRUSTSTORE_FILE_NAME = "truststore.jks"; private static final String WSRF_HOSTNAME_PROMPT = "Please enter a hostname for the WSRF endpoint"; private static final String WSRF_HOSTNAME_PROPERTY = "cagrid.gridgrouper.wsrf.host"; private static final String WSRF_CERTIFICATE_PROMPT = "Please enter the location of the WSRF endpoint host certificate"; private static final String WSRF_CERTIFICATE_PROPERTY = "cagrid.gridgrouper.certificate.location"; private static final String WSRF_KEY_PROMPT = "Please enter the location of the WSRF endpoint private key"; private static final String WSRF_KEY_PROPERTY = "cagrid.gridgrouper.key.location"; private static final String WSRF_KEYSTORE_ALIAS_PROMPT = "Please enter a alias for the WSRF keystore"; private static final String WSRF_KEYSTORE_ALIAS_PROPERTY = "cagrid.gridgrouper.wsrf.keystore.alias"; private static final String WSRF_KEYSTORE_PASSWORD_PROMPT = "Please enter a password for the WSRF keystore"; private static final String WSRF_KEYSTORE_PASSWORD_PROPERTY = "cagrid.gridgrouper.wsrf.keystore.password"; private static final String WSRF_KEY_PASSWORD_PROMPT = "Please enter a password for the WSRF private key"; private static final String WSRF_KEY_PASSWORD_PROPERTY = "cagrid.gridgrouper.wsrf.key.password"; private static final String WSRF_KEYSTORE_FILE_NAME = "grid-grouper-host.jks"; private static final String WSRF_KEYSTORE_PATH_PROPERTY = "cagrid.gridgrouper.wsrf.keystore.path"; private static final String WSRF_KEYSTORE_PATH = "${karaf.base}/etc/" + GROUPER_SERVICE_DIR + "/" + WSRF_KEYSTORE_FILE_NAME; private static final String WSRF_TRUSTSTORE_PATH_PROPERTY = "cagrid.gridgrouper.wsrf.truststore.path"; private static final String WSRF_TRUSTSTORE_PATH = "${karaf.base}/etc/" + GROUPER_SERVICE_DIR + "/" + TRUSTSTORE_FILE_NAME; private static final String WSRF_TRUSTSTORE_PASSWORD_PROMPT = "Please enter a password for the WSRF truststore"; private static final String WSRF_TRUSTSTORE_PASSWORD_PROPERTY = "cagrid.gridgrouper.wsrf.truststore.password"; public static final String WSRF_URL_PROPERTY = "cagrid.gridgrouper.wsrf.url"; public static final String WSRF_PORT_PROMPT = "Enter a port number for the WSRF service"; public static final String WSRF_PORT_PROPERTY = "cagrid.gridgrouper.wsrf.port"; private static final String LEGACY_WSRF_HOSTNAME_PROMPT = "Please enter a legacy hostname"; private static final String LEGACY_WSRF_HOSTNAME_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.host"; private static final String LEGACY_WSRF_CERTIFICATE_PROMPT = "Please enter the location of the legacy host certificate"; private static final String LEGACY_WSRF_CERTIFICATE_PROPERTY = "cagrid.gridgrouper.legacy-certificate.location"; private static final String LEGACY_WSRF_KEY_PROMPT = "Please enter the location of the legacy private key"; private static final String LEGACY_WSRF_KEY_PROPERTY = "cagrid.gridgrouper.legacy-key.location"; private static final String LEGACY_WSRF_KEYSTORE_ALIAS_PROMPT = "Please enter a alias for the legacy keystore"; private static final String LEGACY_WSRF_KEYSTORE_ALIAS_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.keystore.alias"; private static final String LEGACY_WSRF_KEYSTORE_PASSWORD_PROMPT = "Please enter a password for the legacy keystore"; private static final String LEGACY_WSRF_KEYSTORE_PASSWORD_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.keystore.password"; private static final String LEGACY_WSRF_KEY_PASSWORD_PROMPT = "Please enter a password for the legacy private key"; private static final String LEGACY_WSRF_KEY_PASSWORD_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.key.password"; private static final String LEGACY_WSRF_KEYSTORE_FILE_NAME = "legacy-grid-grouper-host.jks"; private static final String LEGACY_WSRF_KEYSTORE_PATH_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.keystore.path"; private static final String LEGACY_WSRF_KEYSTORE_PATH = "${karaf.base}/etc/" + GROUPER_SERVICE_DIR + "/" + LEGACY_WSRF_KEYSTORE_FILE_NAME; private static final String LEGACY_WSRF_TRUSTSTORE_PATH_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.truststore.path"; private static final String LEGACY_WSRF_TRUSTSTORE_PATH = "${karaf.base}/etc/" + GROUPER_SERVICE_DIR + "/" + TRUSTSTORE_FILE_NAME; private static final String LEGACY_WSRF_TRUSTSTORE_PASSWORD_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.truststore.password"; private static final String LEGACY_WSRF_URL_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.url"; private static final String LEGACY_WSRF_PORT_PROMPT = "Enter a port number for the legacy WSRF service"; private static final String LEGACY_WSRF_PORT_PROPERTY = "cagrid.gridgrouper.legacy-wsrf.port"; private static final String DB_URL_PROMPT = "Please enter the database URL"; private static final String DB_URL_PROPERTY = "cagrid.gridgrouper.internet2.hibernate.connection.url"; private static final String DB_USER_PROMPT = "Please enter the database username"; private static final String DB_USER_PROPERTY = "cagrid.gridgrouper.internet2.hibernate.connection.username"; private static final String DB_PASSWORD_PROMPT = "Please enter the database password"; private static final String DB_PASSWORD_PROPERTY = "cagrid.gridgrouper.internet2.hibernate.connection.password"; private static final String DB_INIT_PROMPT = "Do you want to initialize the Grid Grouper database (true|false)"; private static final String DB_INIT_PROPERTY = "cagrid.gridgrouper.database.init"; public static final String WSRF_REGISTRATION_ENABLED_PROMPT = "Please specify whether or not to enable index service registration of the WSRF endpoint"; public static final String WSRF_REGISTRATION_ENABLED_PROPERTY = "cagrid.gridgrouper.wsrf.registration.on"; public static final String LEGACY_WSRF_REGISTRATION_ENABLED_PROPERTY = "cagrid.gridgrouper.wsrf.registration.legacy.on"; public static final String LEGACY_WSRF_REGISTRATION_ENABLED_PROMPT = "Please specify whether or not to enable index service registration of the legacy WSRF endpoint"; public static final String WSRF_REGISTRATION_URL_PROMPT = "Please specify the URL of the index service"; public static final String WSRF_REGISTRATION_URL_PROPERTY = "cagrid.gridgrouper.wsrf.registration.index.url"; private String truststorePassword; private Boolean configureLegacyWSRF; private File grouperEtcDir; private String keystorePassword; private String hostname; private String legacyHostname; private String keystoreAlias; private String keyPassword; private String legacyKeystorePassword; private String legacyKeystoreAlias; private String legacyKeyPassword; private String databaseURL; private String databaseUser; private String databasePassword; private GrouperConfigHelper helper = null; public Bootstrapper(File propertiesFile) throws Exception { super(propertiesFile); } public Bootstrapper(Properties properties) throws Exception { super(properties); } @Override public void execute() throws Exception { System.out.println("*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*"); System.out.println("* GridGrouper Bootstrapper *"); System.out.println("*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*"); System.out.println(""); grouperEtcDir = new File(getServiceMixEtc().getAbsolutePath() + File.separator + GROUPER_SERVICE_DIR); grouperEtcDir.mkdirs(); initDatabase(); configureTruststore(); createWSRFKeystore(); configureLegacyWSRFCredentials(); configureGrouper(); configureWSRFService(); addAdmins(); } private void addAdmins() throws Exception { getHelper(); boolean addAdmin = getBooleanValue("Would you like to add an administrator to Grid Grouper (true|false)", "no.property"); GridSourceAdapter guss = new GridSourceAdapter("grid", "Grid Grouper: Grid Source Adapter"); GridGrouper gg = new GridGrouper(); while (addAdmin) { String adminIdentity = getValue("Enter the identity of the admin you with to add to Grid Grouper", "no.property"); Subject admin = guss.getSubject(adminIdentity); gg.getAdminGroup().addMember(admin); addAdmin = getBooleanValue("Would you like to add another administrator to Grid Grouper (true|false)", "no.property"); } } private GrouperConfigHelper getHelper() { if (this.helper == null) { GrouperConfigHelper helper = new GrouperConfigHelper(); helper.setHibernateConnectionUrl(getDatabaseURL()); helper.setHibernateConnectionUsername(getDatabaseUser()); helper.setHibernateConnectionPassword(getDatabasePassword()); } return this.helper; } private void initDatabase() { String val = getValue(DB_INIT_PROMPT, DB_INIT_PROPERTY); if (val.equalsIgnoreCase("true")) { getHelper(); RegistryInstall.main(new String[0]); RegistryReset.reset(); // jdbc:mysql://localhost:3306/langella_grouper } } private void configureGrouper() throws Exception { Properties props = new Properties(); props.setProperty(DB_URL_PROPERTY, getDatabaseURL()); props.setProperty(DB_USER_PROPERTY, getDatabaseUser()); props.setProperty(DB_PASSWORD_PROPERTY, getDatabasePassword()); File config = new File(getServiceMixEtc(), GROUPER_CFG); props.store(new FileOutputStream(config), "Grouper Service Configuration saved by bootstrapper on " + new Date()); } public String getDatabaseURL() { if (databaseURL == null) { this.databaseURL = getValue(DB_URL_PROMPT, DB_URL_PROPERTY); } return databaseURL; } public String getDatabaseUser() { if (databaseUser == null) { this.databaseUser = getValue(DB_USER_PROMPT, DB_USER_PROPERTY); } return databaseUser; } public String getDatabasePassword() { if (this.databasePassword == null) { this.databasePassword = getValue(DB_PASSWORD_PROMPT, DB_PASSWORD_PROPERTY); if (StringUtils.isBlank(this.databasePassword)) { databasePassword = ""; } } return databasePassword; } private void configureWSRFService() throws Exception { Properties props = new Properties(); props.setProperty(WSRF_HOSTNAME_PROPERTY, getHostname()); props.setProperty(WSRF_TRUSTSTORE_PATH_PROPERTY, WSRF_TRUSTSTORE_PATH); props.setProperty(WSRF_TRUSTSTORE_PASSWORD_PROPERTY, getTruststorePassword()); props.setProperty(WSRF_KEYSTORE_PATH_PROPERTY, WSRF_KEYSTORE_PATH); props.setProperty(WSRF_KEYSTORE_PASSWORD_PROPERTY, getKeystorePassword()); props.setProperty(WSRF_KEYSTORE_ALIAS_PROPERTY, getKeystoreAlias()); props.setProperty(WSRF_KEY_PASSWORD_PROPERTY, getKeyPassword()); String port = getValue(WSRF_PORT_PROMPT, WSRF_PORT_PROPERTY); props.setProperty(WSRF_PORT_PROPERTY, port); String url = "https://" + getHostname() + ":" + port + "/gridgrouper"; props.setProperty(WSRF_URL_PROPERTY, url); boolean enableRegistration = getBooleanValue(WSRF_REGISTRATION_ENABLED_PROMPT, WSRF_REGISTRATION_ENABLED_PROPERTY); props.setProperty(WSRF_REGISTRATION_ENABLED_PROPERTY, Boolean.valueOf(enableRegistration).toString()); boolean enableLegacyRegistration = false; if (this.configureLegacyWSRF()) { props.setProperty(LEGACY_WSRF_TRUSTSTORE_PATH_PROPERTY, LEGACY_WSRF_TRUSTSTORE_PATH); props.setProperty(LEGACY_WSRF_TRUSTSTORE_PASSWORD_PROPERTY, getTruststorePassword()); props.setProperty(LEGACY_WSRF_HOSTNAME_PROPERTY, getLegacyHostname()); props.setProperty(LEGACY_WSRF_KEYSTORE_PATH_PROPERTY, LEGACY_WSRF_KEYSTORE_PATH); props.setProperty(LEGACY_WSRF_KEYSTORE_PASSWORD_PROPERTY, getLegacyKeystorePassword()); props.setProperty(LEGACY_WSRF_KEYSTORE_ALIAS_PROPERTY, getLegacyKeystoreAlias()); props.setProperty(LEGACY_WSRF_KEY_PASSWORD_PROPERTY, getLegacyKeyPassword()); String legacyPort = getValue(LEGACY_WSRF_PORT_PROMPT, LEGACY_WSRF_PORT_PROPERTY); props.setProperty(LEGACY_WSRF_PORT_PROPERTY, legacyPort); String legacyURL = "https://" + getLegacyHostname() + ":" + legacyPort + "/wsrf/services/cagrid/GridGrouper"; props.setProperty(LEGACY_WSRF_URL_PROPERTY, legacyURL); enableLegacyRegistration = getBooleanValue(LEGACY_WSRF_REGISTRATION_ENABLED_PROMPT, LEGACY_WSRF_REGISTRATION_ENABLED_PROPERTY); props.setProperty(LEGACY_WSRF_REGISTRATION_ENABLED_PROPERTY, Boolean.valueOf(enableLegacyRegistration).toString()); } else { props.setProperty(LEGACY_WSRF_REGISTRATION_ENABLED_PROPERTY, "false"); } if (enableRegistration || enableLegacyRegistration) { props.setProperty(WSRF_REGISTRATION_URL_PROPERTY, getValue(WSRF_REGISTRATION_URL_PROMPT, WSRF_REGISTRATION_URL_PROPERTY)); } File wsrfConfig = new File(getServiceMixEtc(), GROUPER_WSRF_CFG); props.store(new FileOutputStream(wsrfConfig), "GridGrouper WSRF Service Configuration saved by bootstrapper on " + new Date()); } public void configureLegacyWSRFCredentials() throws Exception { if (configureLegacyWSRF()) { String hostCertificate = getValue(LEGACY_WSRF_CERTIFICATE_PROMPT, LEGACY_WSRF_CERTIFICATE_PROPERTY); X509Certificate cert = CertUtil.loadCertificate(new File(hostCertificate)); String key = getValue(LEGACY_WSRF_KEY_PROMPT, LEGACY_WSRF_KEY_PROPERTY); PrivateKey pkey = KeyUtil.loadPrivateKey(new File(key), null); java.security.cert.Certificate[] hostCertChain = { cert }; KeyStore hks = KeyStore.getInstance("jks"); hks.load(null); String alias = getLegacyKeystoreAlias(); String keyPassword = getLegacyKeyPassword(); String password = getLegacyKeystorePassword(); hks.setKeyEntry(alias, pkey, keyPassword.toCharArray(), hostCertChain); File hostPath = new File(this.grouperEtcDir.getAbsolutePath() + File.separator + LEGACY_WSRF_KEYSTORE_FILE_NAME); FileOutputStream out = new FileOutputStream(hostPath); hks.store(out, password.toCharArray()); out.close(); System.out.println("Legacy keystore created for " + cert.getSubjectDN() + " at " + hostPath.getAbsolutePath()); } } public boolean configureLegacyWSRF() { if (configureLegacyWSRF == null) { configureLegacyWSRF = Boolean.valueOf(getValue(CONFIGURE_LEGACY_WSRF_PROMPT, CONFIGURE_LEGACY_WSRF_PROPERTY)); } return configureLegacyWSRF; } public void createWSRFKeystore() throws Exception { String hostCertificate = getValue(WSRF_CERTIFICATE_PROMPT, WSRF_CERTIFICATE_PROPERTY); X509Certificate cert = CertUtil.loadCertificate(new File(hostCertificate)); String key = getValue(WSRF_KEY_PROMPT, WSRF_KEY_PROPERTY); PrivateKey pkey = KeyUtil.loadPrivateKey(new File(key), null); java.security.cert.Certificate[] hostCertChain = { cert }; KeyStore hks = KeyStore.getInstance("jks"); hks.load(null); String alias = getKeystoreAlias(); String keyPassword = getKeyPassword(); String password = getKeystorePassword(); hks.setKeyEntry(alias, pkey, keyPassword.toCharArray(), hostCertChain); File hostPath = new File(this.grouperEtcDir.getAbsolutePath() + File.separator + WSRF_KEYSTORE_FILE_NAME); FileOutputStream out = new FileOutputStream(hostPath); hks.store(out, password.toCharArray()); out.close(); System.out.println("WSRF keystore created for " + cert.getSubjectDN() + " at " + hostPath.getAbsolutePath()); } public String getHostname() { if (hostname == null) { hostname = getValue(WSRF_HOSTNAME_PROMPT, WSRF_HOSTNAME_PROPERTY); } return hostname; } public String getLegacyHostname() { if (legacyHostname == null) { legacyHostname = getValue(LEGACY_WSRF_HOSTNAME_PROMPT, LEGACY_WSRF_HOSTNAME_PROPERTY); } return legacyHostname; } public String getKeystorePassword() { if (keystorePassword == null) { keystorePassword = getValue(WSRF_KEYSTORE_PASSWORD_PROMPT, WSRF_KEYSTORE_PASSWORD_PROPERTY); } return keystorePassword; } public String getKeystoreAlias() { if (keystoreAlias == null) { keystoreAlias = getValue(WSRF_KEYSTORE_ALIAS_PROMPT, WSRF_KEYSTORE_ALIAS_PROPERTY); } return keystoreAlias; } public String getKeyPassword() { if (this.keyPassword == null) { this.keyPassword = getValue(WSRF_KEY_PASSWORD_PROMPT, WSRF_KEY_PASSWORD_PROPERTY); } return this.keyPassword; } public String getLegacyKeystorePassword() { if (legacyKeystorePassword == null) { legacyKeystorePassword = getValue(LEGACY_WSRF_KEYSTORE_PASSWORD_PROMPT, LEGACY_WSRF_KEYSTORE_PASSWORD_PROPERTY); } return keystorePassword; } public String getLegacyKeystoreAlias() { if (legacyKeystoreAlias == null) { legacyKeystoreAlias = getValue(LEGACY_WSRF_KEYSTORE_ALIAS_PROMPT, LEGACY_WSRF_KEYSTORE_ALIAS_PROPERTY); } return legacyKeystoreAlias; } public String getLegacyKeyPassword() { if (this.legacyKeyPassword == null) { this.legacyKeyPassword = getValue(LEGACY_WSRF_KEY_PASSWORD_PROMPT, LEGACY_WSRF_KEY_PASSWORD_PROPERTY); } return this.legacyKeyPassword; } private void configureTruststore() throws Exception { File f = new File(this.grouperEtcDir.getAbsolutePath() + File.separator + TRUSTSTORE_FILE_NAME); this.copyTrustStore(f.getAbsolutePath(), getTruststorePassword()); System.out.println("Truststore created for GridGrouper at " + f.getAbsolutePath()); } public String getTruststorePassword() { if (truststorePassword == null) { truststorePassword = getValue(WSRF_TRUSTSTORE_PASSWORD_PROMPT, WSRF_TRUSTSTORE_PASSWORD_PROPERTY); } return truststorePassword; } public static void main(String[] args) { try { Bootstrapper main = new Bootstrapper(new File(PROPERTIES_FILE)); main.execute(); } catch (Exception e) { e.printStackTrace(); } } }