From 63446804f4954bfedd50d8c692bde0fab13aa1ec Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Sun, 25 Jan 2015 21:39:11 +0000 Subject: [PATCH] Working CMS Kernel git-svn-id: https://svn.argeo.org/commons/trunk@7697 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../.settings/org.eclipse.pde.core.prefs | 1 - org.argeo.cms/META-INF/spring/backend.xml | 32 ---- org.argeo.cms/META-INF/spring/osgi.xml | 22 --- org.argeo.cms/bnd.bnd | 23 ++- org.argeo.cms/build.properties | 1 + org.argeo.cms/pom.xml | 5 + .../org/argeo/cms/AbstractCmsEntryPoint.java | 13 +- .../argeo/cms/internal/kernel/Activator.java | 22 +++ .../cms/internal/kernel/JackrabbitNode.java | 133 +++++++++++++++ .../internal/kernel/JackrabbitNodeTypes.java | 5 + .../org/argeo/cms/internal/kernel/Kernel.java | 78 +++++++++ .../cms/internal/kernel/KernelConstants.java | 18 ++ .../cms/internal/kernel/KernelUtils.java | 43 +++++ .../cms/internal/kernel/NodeHttpFilter.java | 158 ++++++++++++++++++ .../cms/internal/kernel/NodeSecurity.java | 91 ++++++++++ .../kernel/jackrabbit-node.properties | 16 ++ .../cms/internal/kernel/repository-h2.xml | 79 +++++++++ .../cms/internal/kernel/repository-memory.xml | 52 ++++++ .../internal/kernel/repository-postgresql.xml | 77 +++++++++ 19 files changed, 803 insertions(+), 66 deletions(-) delete mode 100644 org.argeo.cms/META-INF/spring/backend.xml delete mode 100644 org.argeo.cms/META-INF/spring/osgi.xml create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNode.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeTypes.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttpFilter.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/jackrabbit-node.properties create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml diff --git a/org.argeo.cms/.settings/org.eclipse.pde.core.prefs b/org.argeo.cms/.settings/org.eclipse.pde.core.prefs index f29e940a0..4b0893777 100644 --- a/org.argeo.cms/.settings/org.eclipse.pde.core.prefs +++ b/org.argeo.cms/.settings/org.eclipse.pde.core.prefs @@ -1,3 +1,2 @@ eclipse.preferences.version=1 pluginProject.extensions=false -resolve.requirebundle=false diff --git a/org.argeo.cms/META-INF/spring/backend.xml b/org.argeo.cms/META-INF/spring/backend.xml deleted file mode 100644 index c32676f6b..000000000 --- a/org.argeo.cms/META-INF/spring/backend.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - /org/argeo/cms/cms.cnd - - - - - - - - - - - - cmsRepository - - - - \ No newline at end of file diff --git a/org.argeo.cms/META-INF/spring/osgi.xml b/org.argeo.cms/META-INF/spring/osgi.xml deleted file mode 100644 index 48609a1e4..000000000 --- a/org.argeo.cms/META-INF/spring/osgi.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index 48343c42d..825c5957f 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -1,10 +1,15 @@ +Bundle-Activator: org.argeo.cms.internal.kernel.Activator Import-Package: org.springframework.core,\ - org.springframework.dao,\ - org.eclipse.core.commands,\ - org.eclipse.swt,\ - org.eclipse.jface.window,\ - javax.jcr.security,\ - org.eclipse.swt.widgets;version="0.0.0",\ - org.eclipse.rap.*;resolution:=optional,\ - org.argeo.jackrabbit.*;resolution:=optional,\ - * +org.springframework.dao,\ +org.eclipse.core.commands,\ +org.eclipse.swt,\ +org.eclipse.jface.window,\ +javax.jcr.security,\ +org.xml.sax;version="0.0.0",\ +org.eclipse.swt.widgets;version="0.0.0",\ +org.argeo.jcr,\ +org.h2;resolution:=optional,\ +org.springframework.context,\ +org.apache.jackrabbit.api,\ +org.apache.jackrabbit.commons,\ +* diff --git a/org.argeo.cms/build.properties b/org.argeo.cms/build.properties index 34d2e4d2d..cee30655b 100644 --- a/org.argeo.cms/build.properties +++ b/org.argeo.cms/build.properties @@ -2,3 +2,4 @@ source.. = src/ output.. = bin/ bin.includes = META-INF/,\ . +additional.bundles = org.apache.jackrabbit.data diff --git a/org.argeo.cms/pom.xml b/org.argeo.cms/pom.xml index f0585b06f..c01e0161d 100644 --- a/org.argeo.cms/pom.xml +++ b/org.argeo.cms/pom.xml @@ -16,6 +16,11 @@ org.argeo.server.jcr 2.1.13-SNAPSHOT + + org.argeo.commons + org.argeo.server.jackrabbit + 2.1.13-SNAPSHOT + org.argeo.commons diff --git a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java index 6043980e9..6722d7b86 100644 --- a/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java +++ b/org.argeo.cms/src/org/argeo/cms/AbstractCmsEntryPoint.java @@ -19,12 +19,14 @@ import org.eclipse.rap.rwt.client.service.BrowserNavigationEvent; import org.eclipse.rap.rwt.client.service.BrowserNavigationListener; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; +import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; /** Manages history and navigation */ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint implements CmsSession { private final Log log = LogFactory.getLog(AbstractCmsEntryPoint.class); + private static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; private Repository repository; private String workspace; @@ -39,8 +41,15 @@ public abstract class AbstractCmsEntryPoint extends AbstractEntryPoint private BrowserNavigation history; public AbstractCmsEntryPoint(Repository repository, String workspace) { - if (SecurityContextHolder.getContext().getAuthentication() == null) - logAsAnonymous(); + if (SecurityContextHolder.getContext().getAuthentication() == null) { + SecurityContext contextFromSessionObject = (SecurityContext) RWT + .getRequest().getSession() + .getAttribute(SPRING_SECURITY_CONTEXT_KEY); + if (contextFromSessionObject != null) + SecurityContextHolder.setContext(contextFromSessionObject); + else + logAsAnonymous(); + } this.repository = repository; this.workspace = workspace; 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 new file mode 100644 index 000000000..4d166eaf6 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -0,0 +1,22 @@ +package org.argeo.cms.internal.kernel; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + private Kernel kernel; + + @Override + public void start(BundleContext context) throws Exception { + assert kernel == null; + kernel = new Kernel(context); + kernel.init(); + } + + @Override + public void stop(BundleContext context) throws Exception { + kernel.destroy(); + kernel = null; + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNode.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNode.java new file mode 100644 index 000000000..e36f71356 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNode.java @@ -0,0 +1,133 @@ +package org.argeo.cms.internal.kernel; + +import java.io.File; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Properties; + +import javax.jcr.Repository; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jackrabbit.core.RepositoryImpl; +import org.apache.jackrabbit.core.config.RepositoryConfig; +import org.apache.jackrabbit.core.config.RepositoryConfigurationParser; +import org.argeo.ArgeoException; +import org.argeo.jackrabbit.JackrabbitWrapper; +import org.argeo.jcr.ArgeoJcrConstants; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.xml.sax.InputSource; + +/** Data storage */ +class JackrabbitNode extends JackrabbitWrapper { + private static Log log = LogFactory.getLog(JackrabbitNode.class); + + private ServiceRegistration repositoryReg; + + public JackrabbitNode(BundleContext bundleContext) { + setBundleContext(bundleContext); + createNode(); + setCndFiles(Arrays.asList(KernelConstants.DEFAULT_CNDS)); + prepareDataModel(); + } + + public void publish() { + Hashtable regProps = new Hashtable(); + regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, + ArgeoJcrConstants.ALIAS_NODE); + repositoryReg = getBundleContext().registerService(Repository.class, + this, regProps); + } + + public void destroy() { + repositoryReg.unregister(); + ((RepositoryImpl) getRepository()).shutdown(); + } + + Dictionary getDefaults() { + return KernelUtils.asDictionary(getClass().getClassLoader(), + "/org/argeo/cms/internal/kernel/jackrabbit-node.properties"); + } + + InputSource getConfigurationXml(JackrabbitNodeTypes type) { + ClassLoader cl = getClass().getClassLoader(); + InputStream in = cl + .getResourceAsStream("/org/argeo/cms/internal/kernel/repository-h2.xml"); + return new InputSource(in); + } + + Properties getDefaultConfigurationProperties() { + Properties configurationProperties = new Properties(); + configurationProperties.setProperty(KernelConstants.REPO_DBUSER, "sa"); + configurationProperties + .setProperty(KernelConstants.REPO_DBPASSWORD, ""); + configurationProperties.setProperty(KernelConstants.REPO_MAX_POOL_SIZE, + "10"); + configurationProperties.setProperty( + KernelConstants.REPO_DEFAULT_WORKSPACE, "main"); + return configurationProperties; + } + + private void createNode() { + Thread.currentThread().setContextClassLoader( + getClass().getClassLoader()); + + File osgiInstanceDir = KernelUtils + .getOsgiInstanceDir(getBundleContext()); + File homeDir = new File(osgiInstanceDir, "node"); + + // H2 + String dburl = "jdbc:h2:" + homeDir.getPath() + "/h2/repository"; + Properties configurationProperties = getDefaultConfigurationProperties(); + configurationProperties.setProperty(KernelConstants.REPO_DBURL, dburl); + configurationProperties.put( + RepositoryConfigurationParser.REPOSITORY_HOME_VARIABLE, + homeDir.getAbsolutePath()); + // InputSource configurationXml = getConfigurationXml(null); + + // jackrabbitContainer.setHomeDirectory(homeDir); + // jackrabbitContainer.setConfigurationProperties(configurationProperties); + // jackrabbitContainer.setConfigurationXml(configurationXml); + + // jackrabbitContainer.init(); + + RepositoryImpl repository = createJackrabbitRepository( + configurationProperties, getConfigurationXml(null)); + + setRepository(repository); + } + + private RepositoryImpl createJackrabbitRepository(Properties vars, + InputSource config) { + File homeDirectory = null; + long begin = System.currentTimeMillis(); + InputStream configurationIn = null; + RepositoryImpl repository; + try { + RepositoryConfig repositoryConfig = RepositoryConfig.create(config, + vars); + + // + // Actual repository creation + // + repository = RepositoryImpl.create(repositoryConfig); + + double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; + if (log.isTraceEnabled()) + log.trace("Created Jackrabbit repository in " + duration + + " s, home: " + homeDirectory); + + return repository; + } catch (Exception e) { + throw new ArgeoException("Cannot create Jackrabbit repository " + + homeDirectory, e); + } finally { + IOUtils.closeQuietly(configurationIn); + } + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeTypes.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeTypes.java new file mode 100644 index 000000000..1a84caef3 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/JackrabbitNodeTypes.java @@ -0,0 +1,5 @@ +package org.argeo.cms.internal.kernel; + +enum JackrabbitNodeTypes { + NOT_CONFIGURED, h2, postgresql, memory; +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java new file mode 100644 index 000000000..c6a1630ae --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -0,0 +1,78 @@ +package org.argeo.cms.internal.kernel; + +import javax.jcr.RepositoryFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoException; +import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory; +import org.argeo.security.core.InternalAuthentication; +import org.osgi.framework.BundleContext; +import org.springframework.security.core.context.SecurityContextHolder; + +/** + * Argeo CMS Kernel. Responsible for : + *
    + *
  • security
  • + *
  • provisioning
  • + *
  • transaction
  • + *
  • logging
  • + *
  • local and remote file systems access
  • + *
  • OS access
  • + *
+ */ +final class Kernel { + private final static Log log = LogFactory.getLog(Kernel.class); + + private final BundleContext bundleContext; + + private JackrabbitNode node; + private OsgiJackrabbitRepositoryFactory repositoryFactory; + private NodeSecurity nodeSecurity; + private NodeHttpFilter httpFilter; + + Kernel(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + void init() { + long begin = System.currentTimeMillis(); + InternalAuthentication initAuth = new InternalAuthentication( + KernelConstants.DEFAULT_SECURITY_KEY); + SecurityContextHolder.getContext().setAuthentication(initAuth); + + try { + node = new JackrabbitNode(bundleContext); + repositoryFactory = new OsgiJackrabbitRepositoryFactory(); + nodeSecurity = new NodeSecurity(bundleContext, node); + httpFilter = new NodeHttpFilter(bundleContext, nodeSecurity); + + // Publish services to OSGi register + nodeSecurity.publish(); + node.publish(); + bundleContext.registerService(RepositoryFactory.class, + repositoryFactory, null); + httpFilter.publish(); + } catch (Exception e) { + log.error("Cannot initialize Argeo CMS", e); + throw new ArgeoException("Cannot initialize", e); + } + + long duration = System.currentTimeMillis() - begin; + log.info("## ARGEO CMS UP in " + (duration / 1000) + "." + + (duration % 1000) + "s ##"); + } + + void destroy() { + long begin = System.currentTimeMillis(); + + httpFilter = null; + nodeSecurity.destroy(); + node.destroy(); + + long duration = System.currentTimeMillis() - begin; + log.info("## ARGEO CMS DOWN in " + (duration / 1000) + "." + + (duration % 1000) + "s ##"); + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java new file mode 100644 index 000000000..d36f7a51d --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -0,0 +1,18 @@ +package org.argeo.cms.internal.kernel; + +interface KernelConstants { + // Node + final static String REPO_HOME = "argeo.node.repo.home"; + final static String REPO_CONFIGURATION = "argeo.node.repo.configuration"; + final static String REPO_DEFAULT_WORKSPACE = "argeo.node.repo.defaultWorkspace"; + final static String REPO_DBURL = "argeo.node.repo.dburl"; + final static String REPO_DBUSER = "argeo.node.repo.dbuser"; + final static String REPO_DBPASSWORD = "argeo.node.repo.dbpassword"; + final static String REPO_MAX_POOL_SIZE = "argeo.node.repo.maxPoolSize"; + + final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", + "/org/argeo/cms/cms.cnd" }; + + // Security + final static String DEFAULT_SECURITY_KEY = "argeo"; +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java new file mode 100644 index 000000000..c3297cba8 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -0,0 +1,43 @@ +package org.argeo.cms.internal.kernel; + +import java.io.File; +import java.io.IOException; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Properties; + +import org.argeo.cms.CmsException; +import org.osgi.framework.BundleContext; + +class KernelUtils { + final static String OSGI_INSTANCE_AREA = "osgi.instance.area"; + + static Dictionary asDictionary(Properties props) { + Hashtable hashtable = new Hashtable(); + for (Object key : props.keySet()) { + hashtable.put(key.toString(), props.get(key)); + } + return hashtable; + } + + static Dictionary asDictionary(ClassLoader cl, + String resource) { + Properties props = new Properties(); + try { + props.load(cl.getResourceAsStream(resource)); + } catch (IOException e) { + throw new CmsException("Cannot load " + resource + + " from classpath", e); + } + return asDictionary(props); + } + + static File getOsgiInstanceDir(BundleContext bundleContext) { + return new File(bundleContext.getProperty(OSGI_INSTANCE_AREA) + .substring("file:".length())).getAbsoluteFile(); + } + + private KernelUtils() { + + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttpFilter.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttpFilter.java new file mode 100644 index 000000000..a32228a73 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeHttpFilter.java @@ -0,0 +1,158 @@ +package org.argeo.cms.internal.kernel; + +import java.io.IOException; +import java.util.StringTokenizer; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsException; +import org.eclipse.equinox.http.servlet.ExtendedHttpService; +import org.osgi.framework.BundleContext; +import org.osgi.service.http.HttpContext; +import org.osgi.util.tracker.ServiceTracker; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +class NodeHttpFilter implements Filter { + private final static Log log = LogFactory.getLog(NodeHttpFilter.class); + + private final static String ATTR_AUTH = "auth"; + private final static String HEADER_AUTHORIZATION = "Authorization"; + + static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; + + private ExtendedHttpService httpService; + private final AuthenticationManager authenticationManager; + + private Boolean basicAuthEnabled = false; + + NodeHttpFilter(BundleContext bundleContext, + AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + + // Equinox dependency + ServiceTracker st = new ServiceTracker( + bundleContext, ExtendedHttpService.class, null); + st.open(); + try { + httpService = st.waitForService(1000); + } catch (InterruptedException e) { + httpService = null; + } + + if (httpService == null) + throw new CmsException("Could not find " + + ExtendedHttpService.class + " service."); + } + + void publish() { + try { + HttpContext httpContext = httpService.createDefaultHttpContext(); + httpService.registerFilter("/", this, null, httpContext); + } catch (Exception e) { + throw new CmsException("Cannot register HTTP filter", e); + } + } + + @Override + public void doFilter(ServletRequest servletRequest, + ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpSession httpSession = request.getSession(); + + // Authenticate from session + SecurityContext contextFromSession = (SecurityContext) httpSession + .getAttribute(SPRING_SECURITY_CONTEXT_KEY); + if (contextFromSession != null) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } + + if (basicAuthEnabled) { + // Basic auth + String basicAuth = request.getHeader(HEADER_AUTHORIZATION); + + // for (Enumeration headerNames = request.getHeaderNames(); + // headerNames + // .hasMoreElements();) { + // String headerName = headerNames.nextElement(); + // Object headerValue = request.getHeader(headerName); + // log.debug(headerName + ": " + headerValue); + // } + + if (basicAuth == null) { + HttpServletResponse response = (HttpServletResponse) servletResponse; + response.setStatus(401); + response.setHeader("WWW-Authenticate", "basic realm=\"Auth (" + + httpSession.getCreationTime() + ")\""); + httpSession.setAttribute(ATTR_AUTH, Boolean.TRUE); + return; + } else { + UsernamePasswordAuthenticationToken token = basicAuth(basicAuth); + Authentication auth = authenticationManager.authenticate(token); + SecurityContextHolder.getContext().setAuthentication(auth); + httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, + SecurityContextHolder.getContext()); + httpSession.setAttribute(ATTR_AUTH, Boolean.FALSE); + } + } + // Assume authentication has been done and continue + filterChain.doFilter(servletRequest, servletResponse); + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + } + + @Override + public void destroy() { + } + + private UsernamePasswordAuthenticationToken basicAuth(String authHeader) { + if (authHeader != null) { + StringTokenizer st = new StringTokenizer(authHeader); + if (st.hasMoreTokens()) { + String basic = st.nextToken(); + if (basic.equalsIgnoreCase("Basic")) { + try { + String credentials = new String(Base64.decodeBase64(st + .nextToken()), "UTF-8"); + log.debug("Credentials: " + credentials); + int p = credentials.indexOf(":"); + if (p != -1) { + String login = credentials.substring(0, p).trim(); + String password = credentials.substring(p + 1) + .trim(); + + return new UsernamePasswordAuthenticationToken( + login, password); + } else { + throw new CmsException( + "Invalid authentication token"); + } + } catch (Exception e) { + throw new CmsException( + "Couldn't retrieve authentication", e); + } + } + } + } + throw new CmsException("Couldn't retrieve authentication"); + } + +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java new file mode 100644 index 000000000..7c176ea89 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -0,0 +1,91 @@ +package org.argeo.cms.internal.kernel; + +import javax.jcr.RepositoryException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsException; +import org.argeo.security.UserAdminService; +import org.argeo.security.core.InternalAuthentication; +import org.argeo.security.core.InternalAuthenticationProvider; +import org.argeo.security.jcr.SimpleJcrSecurityModel; +import org.argeo.security.jcr.jackrabbit.JackrabbitUserAdminService; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceRegistration; +import org.springframework.security.authentication.AnonymousAuthenticationProvider; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.provisioning.UserDetailsManager; + +/** Authentication and user management. */ +class NodeSecurity implements AuthenticationManager { + private final static Log log = LogFactory.getLog(NodeSecurity.class); + + private final BundleContext bundleContext; + + private final InternalAuthenticationProvider internalAuth; + private final AnonymousAuthenticationProvider anonymousAuth; + private final JackrabbitUserAdminService jackrabbitUserAdmin; + + private ServiceRegistration authenticationManagerReg; + private ServiceRegistration userAdminReg; + private ServiceRegistration userDetailsManagerReg; + + public NodeSecurity(BundleContext bundleContext, JackrabbitNode node) + throws RepositoryException { + this.bundleContext = bundleContext; + + internalAuth = new InternalAuthenticationProvider( + KernelConstants.DEFAULT_SECURITY_KEY); + anonymousAuth = new AnonymousAuthenticationProvider( + KernelConstants.DEFAULT_SECURITY_KEY); + + // user admin + jackrabbitUserAdmin = new JackrabbitUserAdminService(); + jackrabbitUserAdmin.setRepository(node); + jackrabbitUserAdmin.setSecurityModel(new SimpleJcrSecurityModel()); + jackrabbitUserAdmin.init(); + + } + + public void publish() { + authenticationManagerReg = bundleContext.registerService( + AuthenticationManager.class, this, null); + userAdminReg = bundleContext.registerService(UserAdminService.class, + jackrabbitUserAdmin, null); + userDetailsManagerReg = bundleContext.registerService( + UserDetailsManager.class, jackrabbitUserAdmin, null); + // userAdminReg = + // bundleContext.registerService(UserDetailsService.class, + // jackrabbitUserAdmin, null); + } + + void destroy() { + try { + jackrabbitUserAdmin.destroy(); + } catch (RepositoryException e) { + log.error("Error while destroying Jackrabbit useradmin"); + } + userDetailsManagerReg.unregister(); + userAdminReg.unregister(); + authenticationManagerReg.unregister(); + } + + @Override + public Authentication authenticate(Authentication authentication) + throws AuthenticationException { + Authentication auth = null; + if (authentication instanceof InternalAuthentication) + auth = internalAuth.authenticate(authentication); + else if (authentication instanceof AnonymousAuthenticationToken) + auth = anonymousAuth.authenticate(authentication); + else if (authentication instanceof UsernamePasswordAuthenticationToken) + auth = jackrabbitUserAdmin.authenticate(authentication); + if (auth == null) + throw new CmsException("Could not authenticate " + authentication); + return auth; + } +} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/jackrabbit-node.properties b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jackrabbit-node.properties new file mode 100644 index 000000000..c7ab79dbe --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/jackrabbit-node.properties @@ -0,0 +1,16 @@ +# Workspace used by the node session +argeo.node.repo.defaultWorkspace=main +#argeo.node.repo.securityWorkspace=security +argeo.node.repo.forceCndImport=true + +# Repository base directory +argeo.node.repo.home=node + +## H2 Embedded (DEFAULT) +argeo.node.repo.configuration=osgibundle:repository-h2.xml +argeo.node.repo.dburl=jdbc:h2:${osgi.instance.area}/node/h2/repository +argeo.node.repo.dbuser=sa +argeo.node.repo.dbpassword= + +# ADVANCED +argeo.node.repo.maxPoolSize=10 \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml new file mode 100644 index 000000000..583bf4c1c --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-h2.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml new file mode 100644 index 000000000..b41cfad6d --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-memory.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml new file mode 100644 index 000000000..811f0c6bc --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/repository-postgresql.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- 2.30.2