X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FActivator.java;h=d7b953b5389eae6a4cecbb5b4bbe336c3aea6131;hb=f29320f6e6aca6d3c1b1deca1276930189fd3a60;hp=1997b73ce21bd3c58043ef993a2103c9c055a07f;hpb=06acf73a99f0e3908fe8998f1ff08dee109c5562;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index 1997b73ce..d7b953b53 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -2,129 +2,179 @@ package org.argeo.cms.internal.kernel; import java.io.IOException; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.AllPermission; import java.util.Dictionary; -import java.util.Hashtable; +import java.util.List; +import java.util.Locale; + +import javax.security.auth.login.Configuration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoLogger; import org.argeo.cms.CmsException; +import org.argeo.ident.IdentClient; +import org.argeo.node.ArgeoLogger; import org.argeo.node.NodeConstants; +import org.argeo.node.NodeDeployment; +import org.argeo.node.NodeInstance; import org.argeo.node.NodeState; -import org.argeo.node.RepoConf; import org.argeo.util.LangUtils; +import org.ietf.jgss.GSSCredential; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.ServiceReference; -import org.osgi.framework.ServiceRegistration; -import org.osgi.service.cm.Configuration; -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.cm.ManagedService; +import org.osgi.service.condpermadmin.BundleLocationCondition; +import org.osgi.service.condpermadmin.ConditionInfo; import org.osgi.service.condpermadmin.ConditionalPermissionAdmin; +import org.osgi.service.condpermadmin.ConditionalPermissionInfo; +import org.osgi.service.condpermadmin.ConditionalPermissionUpdate; import org.osgi.service.log.LogReaderService; +import org.osgi.service.permissionadmin.PermissionInfo; +import org.osgi.service.useradmin.UserAdmin; +import org.osgi.util.tracker.ServiceTracker; /** - * Activates the {@link Kernel} from the provided {@link BundleContext}. Gives - * access to kernel information for the rest of the bundle (and only it) + * Activates the kernel. Gives access to kernel information for the rest of the + * bundle (and only it) */ public class Activator implements BundleActivator { - // public final static String SYSTEM_KEY_PROPERTY = - // "argeo.security.systemKey"; - private final Log log = LogFactory.getLog(Activator.class); - - // private final static String systemKey; - // static { - // System.setProperty(SYSTEM_KEY_PROPERTY, systemKey); - // } + private final static Log log = LogFactory.getLog(Activator.class); -// private static Kernel kernel; private static Activator instance; + // TODO make it configurable + private boolean hardened = false; + private BundleContext bc; - private ConditionalPermissionAdmin permissionAdmin; + private LogReaderService logReaderService; - private ConfigurationAdmin configurationAdmin; private NodeLogger logger; private CmsState nodeState; + private CmsDeployment nodeDeployment; + private CmsInstance nodeInstance; + + private ServiceTracker userAdminSt; @Override public void start(BundleContext bundleContext) throws Exception { - // try { - // kernel = new Kernel(); - // kernel.init(); - // } catch (Exception e) { - // log.error("Cannot boot kernel", e); - // } - + Runtime.getRuntime().addShutdownHook(new CmsShutdown()); instance = this; this.bc = bundleContext; - this.permissionAdmin = getService(ConditionalPermissionAdmin.class); this.logReaderService = getService(LogReaderService.class); - this.configurationAdmin = getService(ConfigurationAdmin.class); - initSecurity();// must be first - initArgeoLogger(); - initNodeState(); + try { + initSecurity(); + initArgeoLogger(); + initNode(); + + userAdminSt = new ServiceTracker<>(instance.bc, UserAdmin.class, null); + userAdminSt.open(); + if (log.isTraceEnabled()) + log.trace("Kernel bundle started"); + } catch (Throwable e) { + log.error("## FATAL: CMS activator failed", e); + } } private void initSecurity() { - URL url = getClass().getClassLoader().getResource(KernelConstants.JAAS_CONFIG); - System.setProperty("java.security.auth.login.config", url.toExternalForm()); + if (System.getProperty(KernelConstants.JAAS_CONFIG_PROP) == null) { + String jaasConfig = KernelConstants.JAAS_CONFIG; + URL url = getClass().getClassLoader().getResource(jaasConfig); + // System.setProperty(KernelConstants.JAAS_CONFIG_PROP, + // url.toExternalForm()); + KernelUtils.setJaasConfiguration(url); + } + // explicitly load JAAS configuration + Configuration.getConfiguration(); + + // code-level permissions + String osgiSecurity = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_SECURITY); + if (osgiSecurity != null && Constants.FRAMEWORK_SECURITY_OSGI.equals(osgiSecurity)) { + // TODO rather use a tracker? + ConditionalPermissionAdmin permissionAdmin = bc + .getService(bc.getServiceReference(ConditionalPermissionAdmin.class)); + if (!hardened) { + // All permissions to all bundles + ConditionalPermissionUpdate update = permissionAdmin.newConditionalPermissionUpdate(); + update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null, + new ConditionInfo[] { + new ConditionInfo(BundleLocationCondition.class.getName(), new String[] { "*" }) }, + new PermissionInfo[] { new PermissionInfo(AllPermission.class.getName(), null, null) }, + ConditionalPermissionInfo.ALLOW)); + // TODO data admin permission +// PermissionInfo dataAdminPerm = new PermissionInfo(AuthPermission.class.getName(), +// "createLoginContext." + NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, null); +// update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null, +// new ConditionInfo[] { +// new ConditionInfo(BundleLocationCondition.class.getName(), new String[] { "*" }) }, +// new PermissionInfo[] { dataAdminPerm }, ConditionalPermissionInfo.DENY)); +// update.getConditionalPermissionInfos().add(permissionAdmin.newConditionalPermissionInfo(null, +// new ConditionInfo[] { +// new ConditionInfo(BundleSignerCondition.class.getName(), new String[] { "CN=\"Eclipse.org Foundation, Inc.\", OU=IT, O=\"Eclipse.org Foundation, Inc.\", L=Nepean, ST=Ontario, C=CA" }) }, +// new PermissionInfo[] { dataAdminPerm }, ConditionalPermissionInfo.ALLOW)); + update.commit(); + } else { + SecurityProfile securityProfile = new SecurityProfile() { + }; + securityProfile.applySystemPermissions(permissionAdmin); + } + } + } private void initArgeoLogger() { logger = new NodeLogger(logReaderService); - - // register bc.registerService(ArgeoLogger.class, logger, null); } - private void initNodeState() throws IOException { - nodeState = new CmsState(); - bc.registerService(LangUtils.names(NodeState.class, ManagedService.class), nodeState, - LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID)); - - Configuration nodeConf = configurationAdmin.getConfiguration(NodeConstants.NODE_STATE_PID); - Dictionary props = nodeConf.getProperties(); - if (props == null) { - if (log.isDebugEnabled()) - log.debug("Clean node state"); - Dictionary envProps = getStatePropertiesFromEnvironment(); - nodeConf.update(envProps); + private void initNode() throws IOException { + // Node state + Path stateUuidPath = bc.getDataFile("stateUuid").toPath(); + String stateUuid; + if (Files.exists(stateUuidPath)) { + stateUuid = Files.readAllLines(stateUuidPath).get(0); } else { - // Check id state is in line with environment - Dictionary envProps = getStatePropertiesFromEnvironment(); - for (String key : LangUtils.keys(envProps)) { - Object envValue = envProps.get(key); - Object storedValue = props.get(key); - if (storedValue == null) - throw new CmsException("No state value for env " + key + "=" + envValue - + ", please clean the OSGi configuration."); - if (!storedValue.equals(envValue)) - throw new CmsException("State value for " + key + "=" + storedValue - + " is different from env value =" + envValue + ", please clean the OSGi configuration."); - } + stateUuid = bc.getProperty(Constants.FRAMEWORK_UUID); + Files.write(stateUuidPath, stateUuid.getBytes()); } - + nodeState = new CmsState(stateUuid); + Dictionary regProps = LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID); + regProps.put(NodeConstants.CN, stateUuid); + bc.registerService(NodeState.class, nodeState, regProps); + + // Node deployment + nodeDeployment = new CmsDeployment(); + bc.registerService(NodeDeployment.class, nodeDeployment, null); + + // Node instance + nodeInstance = new CmsInstance(); + bc.registerService(NodeInstance.class, nodeInstance, null); } @Override public void stop(BundleContext bundleContext) throws Exception { - nodeState.shutdown(); - - instance = null; - this.bc = null; - this.permissionAdmin = null; - this.logReaderService = null; - this.configurationAdmin = null; - -// if (kernel != null) { -// kernel.destroy(); -// kernel = null; -// } - + try { + if (nodeInstance != null) + nodeInstance.shutdown(); + if (nodeDeployment != null) + nodeDeployment.shutdown(); + if (nodeState != null) + nodeState.shutdown(); + + if (userAdminSt != null) + userAdminSt.close(); + + instance = null; + this.bc = null; + this.logReaderService = null; + // this.configurationAdmin = null; + } catch (Exception e) { + log.error("CMS activator shutdown failed", e); + } } private T getService(Class clazz) { @@ -134,28 +184,62 @@ public class Activator implements BundleActivator { return bc.getService(sr); } - protected Dictionary getStatePropertiesFromEnvironment() { - Hashtable props = new Hashtable<>(); - // i18n - copyFrameworkProp(NodeConstants.I18N_DEFAULT_LOCALE, props); - copyFrameworkProp(NodeConstants.I18N_LOCALES, props); - // user admin - copyFrameworkProp(NodeConstants.ROLES_URI, props); - copyFrameworkProp(NodeConstants.USERADMIN_URIS, props); - // data - for (RepoConf repoConf : RepoConf.values()) - copyFrameworkProp(NodeConstants.NODE_REPO_PROP_PREFIX + repoConf.name(), props); - // TODO add other environment sources - return props; + public static NodeState getNodeState() { + return instance.nodeState; } - private void copyFrameworkProp(String key, Dictionary props) { - String value = bc.getProperty(key); - if (value != null) - props.put(key, value); + public static GSSCredential getAcceptorCredentials() { + return getNodeUserAdmin().getAcceptorCredentials(); } - public static NodeState getNodeState() { - return instance.nodeState; + public static boolean isSingleUser() { + return getNodeUserAdmin().isSingleUser(); + } + + public static UserAdmin getUserAdmin() { + return (UserAdmin) getNodeUserAdmin(); } + + public static String getHttpProxySslHeader() { + return KernelUtils.getFrameworkProp(NodeConstants.HTTP_PROXY_SSL_DN); + } + + public static IdentClient getIdentClient(String remoteAddr) { + if (!IdentClient.isDefaultAuthdPassphraseFileAvailable()) + return null; + // TODO make passphrase more configurable + return new IdentClient(remoteAddr); + } + + private static NodeUserAdmin getNodeUserAdmin() { + NodeUserAdmin res; + try { + res = instance.userAdminSt.waitForService(60000); + } catch (InterruptedException e) { + throw new CmsException("Cannot retrieve Node user admin", e); + } + if (res == null) + throw new CmsException("No Node user admin found"); + + return res; + // ServiceReference sr = + // instance.bc.getServiceReference(UserAdmin.class); + // NodeUserAdmin userAdmin = (NodeUserAdmin) instance.bc.getService(sr); + // return userAdmin; + + } + + // static CmsSecurity getCmsSecurity() { + // return instance.nodeSecurity; + // } + + public String[] getLocales() { + // TODO optimize? + List locales = getNodeState().getLocales(); + String[] res = new String[locales.size()]; + for (int i = 0; i < locales.size(); i++) + res[i] = locales.get(i).toString(); + return res; + } + }