- Introduce WebCmsSession
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 15 Jul 2016 10:53:14 +0000 (10:53 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 15 Jul 2016 10:53:14 +0000 (10:53 +0000)
- Make web login more robust by refactoring login modules
- Reactivate kernel keystore

git-svn-id: https://svn.argeo.org/commons/trunk@9040 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

15 files changed:
org.argeo.cms/src/org/argeo/cms/auth/AuthConstants.java
org.argeo.cms/src/org/argeo/cms/auth/HttpLoginModule.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/auth/HttpSessionId.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/auth/NodeUserLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/UserAdminLoginModule.java
org.argeo.cms/src/org/argeo/cms/auth/WebCmsSession.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/PkiUtils.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/WebCmsSessionImpl.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/internal/kernel/jaas.cfg
org.argeo.server.jcr/src/org/argeo/jackrabbit/JackrabbitDataModel.java
org.argeo.server.jcr/src/org/argeo/jcr/docbook/DocBookNames.java [new file with mode: 0644]
pom.xml

index 26b96d43c842a66bf63d94ffa3d433a6d50a3e2b..d58d7421cd30f576625a674953b5785135992980 100644 (file)
@@ -1,5 +1,7 @@
 package org.argeo.cms.auth;
 
+import org.osgi.service.http.HttpContext;
+
 /** Public properties of the CMS Kernel */
 public interface AuthConstants {
        // LOGIN CONTEXTS
@@ -12,11 +14,17 @@ public interface AuthConstants {
        public final static String ROLE_KERNEL = "OU=node";
        public final static String ROLES_BASEDN = "ou=roles,ou=node";
        public final static String ROLE_ADMIN = "cn=admin," + ROLES_BASEDN;
-       public final static String ROLE_GROUP_ADMIN = "cn=groupAdmin,"
-                       + ROLES_BASEDN;
+       public final static String ROLE_GROUP_ADMIN = "cn=groupAdmin," + ROLES_BASEDN;
        public final static String ROLE_USER_ADMIN = "cn=userAdmin," + ROLES_BASEDN;
        // Special system groups that cannot be edited:
        // user U anonymous = everyone
        public final static String ROLE_USER = "cn=user," + ROLES_BASEDN;
        public final static String ROLE_ANONYMOUS = "cn=anonymous," + ROLES_BASEDN;
+
+       // SHARED STATE KEYS
+       // compatible with com.sun.security.auth.module.*LoginModule
+       public static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
+       public static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
+       public static final String SHARED_STATE_AUTHORIZATION = HttpContext.AUTHORIZATION;
+
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpLoginModule.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpLoginModule.java
new file mode 100644 (file)
index 0000000..91a2d09
--- /dev/null
@@ -0,0 +1,186 @@
+package org.argeo.cms.auth;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.kernel.Activator;
+import org.argeo.cms.internal.kernel.WebCmsSessionImpl;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.useradmin.Authorization;
+
+public class HttpLoginModule implements LoginModule, AuthConstants {
+       private final static Log log = LogFactory.getLog(HttpLoginModule.class);
+
+       private Subject subject = null;
+       private CallbackHandler callbackHandler = null;
+       private Map<String, Object> sharedState = null;
+
+       private HttpServletRequest request = null;
+
+       private BundleContext bc;
+
+       @SuppressWarnings("unchecked")
+       @Override
+       public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+                       Map<String, ?> options) {
+               bc = Activator.getBundleContext();
+               this.subject = subject;
+               this.callbackHandler = callbackHandler;
+               this.sharedState = (Map<String, Object>) sharedState;
+       }
+
+       @Override
+       public boolean login() throws LoginException {
+               HttpRequestCallback httpCallback = new HttpRequestCallback();
+               try {
+                       callbackHandler.handle(new Callback[] { httpCallback });
+               } catch (IOException e) {
+                       throw new LoginException("Cannot handle http callback: " + e.getMessage());
+               } catch (UnsupportedCallbackException e) {
+                       return false;
+               }
+               request = httpCallback.getRequest();
+               if (request == null)
+                       return false;
+               Authorization authorization = checkHttp();
+               if (authorization == null)
+                       return false;
+               sharedState.put(SHARED_STATE_AUTHORIZATION, authorization);
+               return true;
+       }
+
+       private Authorization checkHttp() {
+               Authorization authorization = null;
+               if (request != null) {
+                       authorization = (Authorization) request.getAttribute(HttpContext.AUTHORIZATION);
+                       if (authorization == null) {
+                               String sessionId = request.getSession().getId();
+                               authorization = (Authorization) request.getSession().getAttribute(HttpContext.AUTHORIZATION);
+                               if (authorization == null) {
+                                       Collection<ServiceReference<WebCmsSession>> sr;
+                                       try {
+                                               sr = bc.getServiceReferences(WebCmsSession.class,
+                                                               "(" + WebCmsSession.CMS_SESSION_ID + "=" + sessionId + ")");
+                                       } catch (InvalidSyntaxException e) {
+                                               throw new CmsException("Cannot get CMS session for id " + sessionId, e);
+                                       }
+                                       if (sr.size() == 1) {
+                                               WebCmsSession cmsSession = bc.getService(sr.iterator().next());
+                                               authorization = cmsSession.getAuthorization();
+                                               if (log.isTraceEnabled())
+                                                       log.trace("Retrieved authorization from " + cmsSession);
+                                       }
+                               }
+                       }
+               }
+               return authorization;
+       }
+
+       @Override
+       public boolean commit() throws LoginException {
+               Authorization authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION);
+               if (authorization == null)
+                       return false;
+               if (request == null)
+                       return false;
+               String sessionId = request.getSession().getId();
+               if (authorization.getName() != null) {
+                       request.setAttribute(HttpContext.REMOTE_USER, authorization.getName());
+                       request.setAttribute(HttpContext.AUTHORIZATION, authorization);
+
+                       HttpSession httpSession = request.getSession();
+                       if (httpSession.getAttribute(HttpContext.AUTHORIZATION) == null) {
+
+                               Collection<ServiceReference<WebCmsSession>> sr;
+                               try {
+                                       sr = bc.getServiceReferences(WebCmsSession.class,
+                                                       "(" + WebCmsSession.CMS_SESSION_ID + "=" + sessionId + ")");
+                               } catch (InvalidSyntaxException e) {
+                                       throw new CmsException("Cannot get CMS session for id " + sessionId, e);
+                               }
+                               ServiceReference<WebCmsSession> cmsSessionRef;
+                               if (sr.size() == 1) {
+                                       cmsSessionRef = sr.iterator().next();
+                               } else if (sr.size() == 0) {
+                                       Hashtable<String, String> props = new Hashtable<>();
+                                       props.put(WebCmsSession.CMS_DN, authorization.getName());
+                                       props.put(WebCmsSession.CMS_SESSION_ID, sessionId);
+                                       WebCmsSessionImpl cmsSessionImpl = new WebCmsSessionImpl(sessionId, authorization);
+                                       ServiceRegistration<WebCmsSession> cmSessionReg = bc.registerService(WebCmsSession.class,
+                                                       cmsSessionImpl, props);
+                                       cmsSessionImpl.setServiceRegistration(cmSessionReg);
+                                       cmsSessionRef = cmSessionReg.getReference();
+                                       if (log.isDebugEnabled())
+                                               log.debug("Initialized " + cmsSessionImpl + " for " + authorization.getName());
+                               } else
+                                       throw new CmsException(sr.size() + " CMS sessions registered for " + sessionId);
+
+                               WebCmsSession cmsSession = bc.getService(cmsSessionRef);
+                               cmsSession.addHttpSession(request);
+                               if (log.isTraceEnabled())
+                                       log.trace("Added " + request.getServletPath() + " to " + cmsSession + " (" + request.getRequestURI()
+                                                       + ")");
+                               httpSession.setAttribute(HttpContext.AUTHORIZATION, authorization);
+                       }
+               }
+               if (subject.getPrivateCredentials(HttpSessionId.class).size() == 0)
+                       subject.getPrivateCredentials().add(new HttpSessionId(sessionId));
+               else {
+                       String storedSessionId = subject.getPrivateCredentials(HttpSessionId.class).iterator().next().getValue();
+                       if (storedSessionId.equals(sessionId))
+                               throw new LoginException(
+                                               "Subject already logged with session " + storedSessionId + " (not " + sessionId + ")");
+               }
+               return true;
+       }
+
+       @Override
+       public boolean abort() throws LoginException {
+               return false;
+       }
+
+       @Override
+       public boolean logout() throws LoginException {
+               String sessionId;
+               if (subject.getPrivateCredentials(HttpSessionId.class).size() == 1)
+                       sessionId = subject.getPrivateCredentials(HttpSessionId.class).iterator().next().getValue();
+               else
+                       return false;
+               Collection<ServiceReference<WebCmsSession>> srs;
+               try {
+                       srs = bc.getServiceReferences(WebCmsSession.class,
+                                       "(" + WebCmsSession.CMS_SESSION_ID + "=" + sessionId + ")");
+               } catch (InvalidSyntaxException e) {
+                       throw new CmsException("Cannot retrieve CMS session #" + sessionId, e);
+               }
+
+               for (Iterator<ServiceReference<WebCmsSession>> it = srs.iterator(); it.hasNext();) {
+                       ServiceReference<WebCmsSession> sr = it.next();
+                       WebCmsSession cmsSession = bc.getService(sr);
+                       cmsSession.cleanUp();
+                       if (log.isDebugEnabled())
+                               log.debug("Cleaned up " + cmsSession);
+               }
+               return true;
+       }
+
+}
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionId.java b/org.argeo.cms/src/org/argeo/cms/auth/HttpSessionId.java
new file mode 100644 (file)
index 0000000..9f972de
--- /dev/null
@@ -0,0 +1,33 @@
+package org.argeo.cms.auth;
+
+import org.argeo.cms.CmsException;
+
+public class HttpSessionId {
+       private final String value;
+
+       public HttpSessionId(String value) {
+               if (value == null)
+                       throw new CmsException("value cannot be null");
+               this.value = value;
+       }
+
+       public String getValue() {
+               return value;
+       }
+
+       @Override
+       public int hashCode() {
+               return value.hashCode();
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               return obj instanceof HttpSessionId && ((HttpSessionId) obj).getValue().equals(value);
+       }
+
+       @Override
+       public String toString() {
+               return "HttpSessionId #" + value;
+       }
+
+}
index 5dce3c61da1f8a46f3f19b00ebd975e3236632bf..79714b16aa845084646eece27479dec61a7e9e82 100644 (file)
@@ -3,7 +3,6 @@ package org.argeo.cms.auth;
 import java.security.Principal;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -24,11 +23,11 @@ import org.argeo.cms.CmsException;
 import org.argeo.cms.internal.auth.ImpliedByPrincipal;
 import org.osgi.service.useradmin.Authorization;
 
-public class NodeUserLoginModule implements LoginModule {
+public class NodeUserLoginModule implements LoginModule, AuthConstants {
        private Subject subject;
+       private Map<String, Object> sharedState = null;
 
-       private final static LdapName ROLE_KERNEL_NAME, ROLE_ADMIN_NAME,
-                       ROLE_ANONYMOUS_NAME, ROLE_USER_NAME;
+       private final static LdapName ROLE_KERNEL_NAME, ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME;
        private final static List<LdapName> RESERVED_ROLES;
        private final static X500Principal ROLE_ANONYMOUS_PRINCIPAL;
        static {
@@ -37,13 +36,10 @@ public class NodeUserLoginModule implements LoginModule {
                        ROLE_ADMIN_NAME = new LdapName(AuthConstants.ROLE_ADMIN);
                        ROLE_USER_NAME = new LdapName(AuthConstants.ROLE_USER);
                        ROLE_ANONYMOUS_NAME = new LdapName(AuthConstants.ROLE_ANONYMOUS);
-                       RESERVED_ROLES = Collections.unmodifiableList(Arrays
-                                       .asList(new LdapName[] { ROLE_KERNEL_NAME, ROLE_ADMIN_NAME,
-                                                       ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
-                                                       new LdapName(AuthConstants.ROLE_GROUP_ADMIN),
-                                                       new LdapName(AuthConstants.ROLE_USER_ADMIN) }));
-                       ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(
-                                       ROLE_ANONYMOUS_NAME.toString());
+                       RESERVED_ROLES = Collections.unmodifiableList(Arrays.asList(new LdapName[] { ROLE_KERNEL_NAME,
+                                       ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, new LdapName(AuthConstants.ROLE_GROUP_ADMIN),
+                                       new LdapName(AuthConstants.ROLE_USER_ADMIN) }));
+                       ROLE_ANONYMOUS_PRINCIPAL = new X500Principal(ROLE_ANONYMOUS_NAME.toString());
                } catch (InvalidNameException e) {
                        throw new Error("Cannot initialize login module class", e);
                }
@@ -51,19 +47,24 @@ public class NodeUserLoginModule implements LoginModule {
 
        private Authorization authorization;
 
+       @SuppressWarnings("unchecked")
        @Override
-       public void initialize(Subject subject, CallbackHandler callbackHandler,
-                       Map<String, ?> sharedState, Map<String, ?> options) {
+       public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+                       Map<String, ?> options) {
                this.subject = subject;
+               this.sharedState = (Map<String, Object>) sharedState;
        }
 
        @Override
        public boolean login() throws LoginException {
-               Iterator<Authorization> auth = subject.getPrivateCredentials(
-                               Authorization.class).iterator();
-               if (!auth.hasNext())
+               authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION);
+               if (authorization == null)
                        throw new FailedLoginException("No authorization available");
-               authorization = auth.next();
+               // Iterator<Authorization> auth = subject.getPrivateCredentials(
+               // Authorization.class).iterator();
+               // if (!auth.hasNext())
+               // throw new FailedLoginException("No authorization available");
+               // authorization = auth.next();
                return true;
        }
 
@@ -71,6 +72,9 @@ public class NodeUserLoginModule implements LoginModule {
        public boolean commit() throws LoginException {
                if (authorization == null)
                        throw new LoginException("Authorization should not be null");
+               // required for display name:
+               subject.getPrivateCredentials().add(authorization);
+
                Set<Principal> principals = subject.getPrincipals();
                try {
                        String authName = authorization.getName();
@@ -88,8 +92,7 @@ public class NodeUserLoginModule implements LoginModule {
                                checkUserName(name);
                                userPrincipal = new X500Principal(name.toString());
                                principals.add(userPrincipal);
-                               principals.add(new ImpliedByPrincipal(ROLE_USER_NAME,
-                                               userPrincipal));
+                               principals.add(new ImpliedByPrincipal(ROLE_USER_NAME, userPrincipal));
                        }
 
                        // Add roles provided by authorization
@@ -99,11 +102,9 @@ public class NodeUserLoginModule implements LoginModule {
                                        // skip
                                } else {
                                        checkImpliedPrincipalName(roleName);
-                                       principals.add(new ImpliedByPrincipal(roleName.toString(),
-                                                       userPrincipal));
+                                       principals.add(new ImpliedByPrincipal(roleName.toString(), userPrincipal));
                                        if (roleName.equals(ROLE_ADMIN_NAME))
-                                               principals.add(new AdminPrincipal(
-                                                               SecurityConstants.ADMIN_ID));
+                                               principals.add(new AdminPrincipal(SecurityConstants.ADMIN_ID));
                                }
                        }
 
@@ -124,15 +125,11 @@ public class NodeUserLoginModule implements LoginModule {
                if (subject == null)
                        throw new LoginException("Subject should not be null");
                // Argeo
-               subject.getPrincipals().removeAll(
-                               subject.getPrincipals(X500Principal.class));
-               subject.getPrincipals().removeAll(
-                               subject.getPrincipals(ImpliedByPrincipal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(X500Principal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(ImpliedByPrincipal.class));
                // Jackrabbit
-               subject.getPrincipals().removeAll(
-                               subject.getPrincipals(AdminPrincipal.class));
-               subject.getPrincipals().removeAll(
-                               subject.getPrincipals(AnonymousPrincipal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(AdminPrincipal.class));
+               subject.getPrincipals().removeAll(subject.getPrincipals(AnonymousPrincipal.class));
                cleanUp();
                return true;
        }
@@ -148,8 +145,7 @@ public class NodeUserLoginModule implements LoginModule {
        }
 
        private void checkImpliedPrincipalName(LdapName roleName) {
-               if (ROLE_USER_NAME.equals(roleName)
-                               || ROLE_ANONYMOUS_NAME.equals(roleName)
+               if (ROLE_USER_NAME.equals(roleName) || ROLE_ANONYMOUS_NAME.equals(roleName)
                                || ROLE_KERNEL_NAME.equals(roleName))
                        throw new CmsException(roleName + " cannot be listed as role");
        }
index 2faee6fa1157a5ed0c0e6a2af3da0bbefec9b6ae..29eb8bf49c28282a4c67fbaa8038a501aa819b7f 100644 (file)
@@ -1,10 +1,8 @@
 package org.argeo.cms.auth;
 
 import java.io.IOException;
-import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 
 import javax.security.auth.Subject;
 import javax.security.auth.callback.Callback;
@@ -17,39 +15,39 @@ import javax.security.auth.login.CredentialNotFoundException;
 import javax.security.auth.login.FailedLoginException;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.spi.LoginModule;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.argeo.ArgeoException;
 import org.argeo.cms.internal.kernel.Activator;
 import org.argeo.eclipse.ui.specific.UiContext;
 import org.osgi.framework.BundleContext;
-import org.osgi.service.http.HttpContext;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
 
 public class UserAdminLoginModule implements LoginModule, AuthConstants {
-       private final static Log log = LogFactory
-                       .getLog(UserAdminLoginModule.class);
-
-       private Subject subject;
+       // private final static Log log =
+       // LogFactory.getLog(UserAdminLoginModule.class);
+       //
+       // private Subject subject;
        private CallbackHandler callbackHandler;
+       private Map<String, Object> sharedState = null;
+
        private boolean isAnonymous = false;
 
-       private HttpServletRequest request = null;
+       // private HttpServletRequest request = null;
+       private BundleContext bc;
 
+       @SuppressWarnings("unchecked")
        @Override
-       public void initialize(Subject subject, CallbackHandler callbackHandler,
-                       Map<String, ?> sharedState, Map<String, ?> options) {
+       public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+                       Map<String, ?> options) {
                try {
-                       this.subject = subject;
+                       bc = Activator.getBundleContext();
+                       // this.subject = subject;
                        this.callbackHandler = callbackHandler;
+                       this.sharedState = (Map<String, Object>) sharedState;
                        if (options.containsKey("anonymous"))
-                               isAnonymous = Boolean.parseBoolean(options.get("anonymous")
-                                               .toString());
+                               isAnonymous = Boolean.parseBoolean(options.get("anonymous").toString());
                } catch (Exception e) {
                        throw new ArgeoException("Cannot initialize login module", e);
                }
@@ -57,39 +55,29 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
 
        @Override
        public boolean login() throws LoginException {
-               BundleContext bc = Activator.getBundleContext();
-               UserAdmin userAdmin = bc.getService(bc
-                               .getServiceReference(UserAdmin.class));
+               UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
                Authorization authorization = null;
                if (isAnonymous) {
                        authorization = userAdmin.getAuthorization(null);
                } else {
-                       HttpRequestCallback httpCallback = new HttpRequestCallback();
+                       // HttpRequestCallback httpCallback = new HttpRequestCallback();
                        // ask for username and password
                        NameCallback nameCallback = new NameCallback("User");
-                       PasswordCallback passwordCallback = new PasswordCallback(
-                                       "Password", false);
+                       PasswordCallback passwordCallback = new PasswordCallback("Password", false);
                        LanguageCallback langCallback = new LanguageCallback();
                        try {
-                               callbackHandler.handle(new Callback[] { httpCallback,
-                                               nameCallback, passwordCallback, langCallback });
+                               callbackHandler.handle(new Callback[] { nameCallback, passwordCallback, langCallback });
                        } catch (IOException e) {
-                               throw new LoginException("Cannot handle http callback: "
-                                               + e.getMessage());
+                               throw new LoginException("Cannot handle callback: " + e.getMessage());
                        } catch (ThreadDeath e) {
-                               throw new ThreadDeathLoginException(
-                                               "Callbackhandler thread died", e);
+                               throw new ThreadDeathLoginException("Callbackhandler thread died", e);
                        } catch (UnsupportedCallbackException e) {
                                return false;
                        }
-                       request = httpCallback.getRequest();
-                       if (request != null) {
-                               authorization = (Authorization) request
-                                               .getAttribute(HttpContext.AUTHORIZATION);
-                               if (authorization == null)
-                                       authorization = (Authorization) request.getSession()
-                                                       .getAttribute(HttpContext.AUTHORIZATION);
-                       }
+
+                       // check http
+                       // request = httpCallback.getRequest();
+                       // authorization = checkHttp();
 
                        // i18n
                        Locale locale = langCallback.getLocale();
@@ -97,20 +85,20 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
                                locale = Locale.getDefault();
                        UiContext.setLocale(locale);
 
+                       authorization = (Authorization) sharedState.get(SHARED_STATE_AUTHORIZATION);
+
                        if (authorization == null) {
                                // create credentials
                                final String username = nameCallback.getName();
                                if (username == null || username.trim().equals("")) {
                                        // authorization = userAdmin.getAuthorization(null);
-                                       throw new CredentialNotFoundException(
-                                                       "No credentials provided");
+                                       throw new CredentialNotFoundException("No credentials provided");
                                } else {
                                        char[] password = {};
                                        if (passwordCallback.getPassword() != null)
                                                password = passwordCallback.getPassword();
                                        else
-                                               throw new CredentialNotFoundException(
-                                                               "No credentials provided");
+                                               throw new CredentialNotFoundException("No credentials provided");
 
                                        User user = userAdmin.getUser(null, username);
                                        if (user == null)
@@ -120,60 +108,124 @@ public class UserAdminLoginModule implements LoginModule, AuthConstants {
                                        // return false;
 
                                        // Log and monitor new login
-                                       if (log.isDebugEnabled())
-                                               log.debug("Logged in to CMS with username [" + username+"]");
+                                       // if (log.isDebugEnabled())
+                                       // log.debug("Logged in to CMS with username [" + username +
+                                       // "]");
 
                                        authorization = userAdmin.getAuthorization(user);
                                }
                        }
-                       // } else {
-                       // authorization = userAdmin.getAuthorization(null);
-                       // }
                }
-               subject.getPrivateCredentials().add(authorization);
+               if (!sharedState.containsKey(SHARED_STATE_AUTHORIZATION))
+                       sharedState.put(SHARED_STATE_AUTHORIZATION, authorization);
+               // subject.getPrivateCredentials().add(authorization);
                return true;
        }
 
+       // private Authorization checkHttp() {
+       // Authorization authorization = null;
+       // if (request != null) {
+       // authorization = (Authorization)
+       // request.getAttribute(HttpContext.AUTHORIZATION);
+       // if (authorization == null) {
+       // String sessionId = request.getSession().getId();
+       // authorization = (Authorization)
+       // request.getSession().getAttribute(HttpContext.AUTHORIZATION);
+       // if (authorization == null) {
+       // Collection<ServiceReference<CmsSession>> sr;
+       // try {
+       // sr = bc.getServiceReferences(CmsSession.class,
+       // "(" + CmsSession.CMS_SESSION_ID + "=" + sessionId + ")");
+       // } catch (InvalidSyntaxException e) {
+       // throw new CmsException("Cannot get CMS session for id " + sessionId, e);
+       // }
+       // if (sr.size() == 1) {
+       // CmsSession cmsSession = bc.getService(sr.iterator().next());
+       // authorization = cmsSession.getAuthorization();
+       // if (log.isTraceEnabled())
+       // log.trace("Retrieved authorization from " + cmsSession);
+       // }
+       // }
+       // }
+       // }
+       // return authorization;
+       // }
+
        @Override
        public boolean commit() throws LoginException {
-               Authorization authorization = subject
-                               .getPrivateCredentials(Authorization.class).iterator().next();
-               if (request != null && authorization.getName() != null) {
-                       request.setAttribute(HttpContext.REMOTE_USER,
-                                       authorization.getName());
-                       request.setAttribute(HttpContext.AUTHORIZATION, authorization);
-                       request.getSession().setAttribute(HttpContext.AUTHORIZATION,
-                                       authorization);
-                       subject.getPrivateCredentials().add(request.getSession());
-               }
+               // Authorization authorization =
+               // subject.getPrivateCredentials(Authorization.class).iterator().next();
+               // if (request != null && authorization.getName() != null) {
+               // request.setAttribute(HttpContext.REMOTE_USER,
+               // authorization.getName());
+               // request.setAttribute(HttpContext.AUTHORIZATION, authorization);
+               //
+               // HttpSession httpSession = request.getSession();
+               // if (httpSession.getAttribute(HttpContext.AUTHORIZATION) == null) {
+               //
+               // String sessionId = request.getSession().getId();
+               // Collection<ServiceReference<CmsSession>> sr;
+               // try {
+               // sr = bc.getServiceReferences(CmsSession.class,
+               // "(" + CmsSession.CMS_SESSION_ID + "=" + sessionId + ")");
+               // } catch (InvalidSyntaxException e) {
+               // throw new CmsException("Cannot get CMS session for id " + sessionId,
+               // e);
+               // }
+               // CmsSession cmsSession;
+               // if (sr.size() == 1) {
+               // cmsSession = bc.getService(sr.iterator().next());
+               // } else if (sr.size() == 0) {
+               // Hashtable<String, String> props = new Hashtable<>();
+               // props.put(CmsSession.CMS_DN, authorization.getName());
+               // props.put(CmsSession.CMS_SESSION_ID, sessionId);
+               // cmsSession = new CmsSessionImpl(sessionId, authorization);
+               // bc.registerService(CmsSession.class, cmsSession, props);
+               // if (log.isDebugEnabled())
+               // log.debug("Initialized " + cmsSession + " for " +
+               // authorization.getName());
+               // } else
+               // throw new CmsException(sr.size() + " CMS sessions registered for " +
+               // sessionId);
+               // cmsSession.addHttpSession(request);
+               // if (log.isTraceEnabled())
+               // log.trace("Added " + request.getServletPath() + " to " + cmsSession +
+               // " (" + request.getRequestURI()
+               // + ")");
+               // httpSession.setAttribute(HttpContext.AUTHORIZATION, authorization);
+               // }
+               // subject.getPrivateCredentials().add(request.getSession());
+               // }
                return true;
        }
 
        @Override
        public boolean abort() throws LoginException {
-               cleanUp();
+               // cleanUp();
                return true;
        }
 
        @Override
        public boolean logout() throws LoginException {
-               Set<HttpSession> httpSession = subject
-                               .getPrivateCredentials(HttpSession.class);
-               Iterator<HttpSession> it = httpSession.iterator();
-               while (it.hasNext()) {
-                       HttpSession sess = it.next();
-                       sess.setAttribute(HttpContext.AUTHORIZATION, null);
-                       // sess.setMaxInactiveInterval(1);// invalidate session
-               }
-               subject.getPrivateCredentials().removeAll(httpSession);
-               cleanUp();
+               // Set<HttpSession> httpSession =
+               // subject.getPrivateCredentials(HttpSession.class);
+               // Iterator<HttpSession> it = httpSession.iterator();
+               // while (it.hasNext()) {
+               // HttpSession sess = it.next();
+               // sess.setAttribute(HttpContext.AUTHORIZATION, null);
+               // // sess.setMaxInactiveInterval(1);// invalidate session
+               //
+               // // TODO log out CMS session
+               // }
+               // subject.getPrivateCredentials().removeAll(httpSession);
+               //
+               // cleanUp();
                return true;
        }
 
-       private void cleanUp() {
-               subject.getPrivateCredentials().removeAll(
-                               subject.getPrivateCredentials(Authorization.class));
-               subject = null;
-       }
+       // private void cleanUp() {
+       // subject.getPrivateCredentials().removeAll(subject.getPrivateCredentials(Authorization.class));
+       // subject = null;
+       // }
 
 }
diff --git a/org.argeo.cms/src/org/argeo/cms/auth/WebCmsSession.java b/org.argeo.cms/src/org/argeo/cms/auth/WebCmsSession.java
new file mode 100644 (file)
index 0000000..5352223
--- /dev/null
@@ -0,0 +1,18 @@
+package org.argeo.cms.auth;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.osgi.service.useradmin.Authorization;
+
+public interface WebCmsSession {
+       public final static String CMS_DN = "cms.dn";
+       public final static String CMS_SESSION_ID = "cms.sessionId";
+
+       public String getId();
+
+       public Authorization getAuthorization();
+
+       public void addHttpSession(HttpServletRequest request);
+
+       public void cleanUp();
+}
index 199356198e259e7eee547609b0d56cfad04b655b..a1988a2181487abf43a1f51676f9deb8da694c09 100644 (file)
@@ -256,6 +256,26 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                props.put("contextName", "user");
                bc.registerService(ApplicationConfiguration.class, userUi, props);
 
+               // Bundle rapWorkbenchBundle =
+               // findBundle("org.eclipse.rap.ui.workbench");
+               // if (rapWorkbenchBundle != null)
+               // try {
+               // Class<?> clss = rapWorkbenchBundle
+               // .loadClass("org.eclipse.rap.ui.internal.servlet.WorkbenchApplicationConfiguration");
+               //
+               // Hashtable<String, String> rapWorkbenchProps = new Hashtable<String,
+               // String>();
+               // rapWorkbenchProps.put("contextName", "ui");
+               // ApplicationConfiguration workbenchApplicationConfiguration =
+               // (ApplicationConfiguration) clss
+               // .newInstance();
+               // bc.registerService(ApplicationConfiguration.class,
+               // workbenchApplicationConfiguration,
+               // rapWorkbenchProps);
+               // } catch (Exception e) {
+               // log.error("Cannot initalize RAP workbench", e);
+               // }
+
                // Kernel thread
                kernelThread = new KernelThread(this);
                kernelThread.setContextClassLoader(Kernel.class.getClassLoader());
@@ -425,6 +445,14 @@ final class Kernel implements KernelHeader, KernelConstants, ServiceListener {
                return bc.getService(configurationAdmin);
        }
 
+       /** Can be null */
+       Bundle findBundle(String symbolicName) {
+               for (Bundle b : bc.getBundles())
+                       if (b.getSymbolicName().equals(symbolicName))
+                               return b;
+               return null;
+       }
+
        private void initTransactionManager() {
                bitronix.tm.Configuration tmConf = TransactionManagerServices.getConfiguration();
                tmConf.setServerId(getFrameworkProp(FRAMEWORK_UUID));
index e06afa829fd45fcb39b900587a38dfc91f2a4680..b179ec0451b65094c3d01ca1618226b4d33e4891 100644 (file)
@@ -46,6 +46,7 @@ public interface KernelConstants {
        final static String DEFAULT_SECURITY_KEY = "argeo";
        final static String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
        final static String LOGIN_CONTEXT_KERNEL = "KERNEL";
+       final static String LOGIN_CONTEXT_HARDENED_KERNEL = "HARDENED_KERNEL";
 
        // DAV
        final static String WEBDAV_CONFIG = "/org/argeo/cms/internal/kernel/webdav-config.xml";
index bb33daecf0602339a95596dbc8fba7e297b70a41..87ba070243cab111170fac0ad83e47436a2fbf8b 100644 (file)
@@ -18,11 +18,15 @@ import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 import javax.security.auth.x500.X500Principal;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.auth.AuthConstants;
 
 /** Low-level kernel security */
 class NodeSecurity implements KernelConstants {
+       private final static Log log = LogFactory.getLog(NodeSecurity.class);
+
        public final static int HARDENED = 3;
        public final static int STAGING = 2;
        public final static int DEV = 1;
@@ -36,10 +40,8 @@ class NodeSecurity implements KernelConstants {
 
        public NodeSecurity() {
                // Configure JAAS first
-               URL url = getClass().getClassLoader().getResource(
-                               KernelConstants.JAAS_CONFIG);
-               System.setProperty("java.security.auth.login.config",
-                               url.toExternalForm());
+               URL url = getClass().getClassLoader().getResource(KernelConstants.JAAS_CONFIG);
+               System.setProperty("java.security.auth.login.config", url.toExternalForm());
                // log.debug("JASS config: " + url.toExternalForm());
                // disable Jetty autostart
                // System.setProperty("org.eclipse.equinox.http.jetty.autostart",
@@ -47,34 +49,43 @@ class NodeSecurity implements KernelConstants {
 
                firstInit = !new File(getOsgiInstanceDir(), DIR_NODE).exists();
 
-               this.keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(),
-                               "node.p12");
-               this.kernelSubject = logInKernel();
+               this.keyStoreFile = new File(KernelUtils.getOsgiInstanceDir(), "node.p12");
+               createKeyStoreIfNeeded();
+               if (keyStoreFile.exists())
+                       this.kernelSubject = logInHardenedKernel();
+               else
+                       this.kernelSubject = logInKernel();
        }
 
        private Subject logInKernel() {
                final Subject kernelSubject = new Subject();
-               // createKeyStoreIfNeeded();
+               try {
+                       LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
+                       kernelLc.login();
+               } catch (LoginException e) {
+                       throw new CmsException("Cannot log in kernel", e);
+               }
+               return kernelSubject;
+       }
+
+       private Subject logInHardenedKernel() {
+               final Subject kernelSubject = new Subject();
+               createKeyStoreIfNeeded();
 
                CallbackHandler cbHandler = new CallbackHandler() {
 
                        @Override
-                       public void handle(Callback[] callbacks) throws IOException,
-                                       UnsupportedCallbackException {
+                       public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
                                // alias
-                               ((NameCallback) callbacks[1])
-                                               .setName(AuthConstants.ROLE_KERNEL);
+                               ((NameCallback) callbacks[1]).setName(AuthConstants.ROLE_KERNEL);
                                // store pwd
-                               ((PasswordCallback) callbacks[2]).setPassword("changeit"
-                                               .toCharArray());
+                               ((PasswordCallback) callbacks[2]).setPassword("changeit".toCharArray());
                                // key pwd
-                               ((PasswordCallback) callbacks[3]).setPassword("changeit"
-                                               .toCharArray());
+                               ((PasswordCallback) callbacks[3]).setPassword("changeit".toCharArray());
                        }
                };
                try {
-                       LoginContext kernelLc = new LoginContext(
-                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject,
+                       LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_HARDENED_KERNEL, kernelSubject,
                                        cbHandler);
                        kernelLc.login();
                } catch (LoginException e) {
@@ -86,8 +97,7 @@ class NodeSecurity implements KernelConstants {
        void destroy() {
                // Logout kernel
                try {
-                       LoginContext kernelLc = new LoginContext(
-                                       KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
+                       LoginContext kernelLc = new LoginContext(KernelConstants.LOGIN_CONTEXT_KERNEL, kernelSubject);
                        kernelLc.logout();
                } catch (LoginException e) {
                        throw new CmsException("Cannot log out kernel", e);
@@ -110,28 +120,31 @@ class NodeSecurity implements KernelConstants {
 
        public void setSecurityLevel(int newValue) {
                if (newValue != STAGING || newValue != DEV)
-                       throw new CmsException("Invalid value for security level "
-                                       + newValue);
+                       throw new CmsException("Invalid value for security level " + newValue);
                if (newValue >= securityLevel)
                        throw new CmsException(
-                                       "Impossible to increase security level (from "
-                                                       + securityLevel + " to " + newValue + ")");
+                                       "Impossible to increase security level (from " + securityLevel + " to " + newValue + ")");
                securityLevel = newValue;
        }
 
        private void createKeyStoreIfNeeded() {
+               // for (Provider provider : Security.getProviders())
+               // System.out.println(provider.getName());
+
                char[] ksPwd = "changeit".toCharArray();
                char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length);
                if (!keyStoreFile.exists()) {
                        try {
                                keyStoreFile.getParentFile().mkdirs();
                                KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd);
-                               PkiUtils.generateSelfSignedCertificate(keyStore,
-                                               new X500Principal(AuthConstants.ROLE_KERNEL), keyPwd);
+                               PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal(AuthConstants.ROLE_KERNEL), keyPwd);
                                PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore);
+                               if (log.isDebugEnabled())
+                                       log.debug("Created keystore " + keyStoreFile);
                        } catch (Exception e) {
-                               throw new CmsException("Cannot create key store "
-                                               + keyStoreFile, e);
+                               if (keyStoreFile.length() == 0)
+                                       keyStoreFile.delete();
+                               log.error("Cannot create keystore " + keyStoreFile, e);
                        }
                }
        }
index d8b39cdbc2238b039f7f9ac115061acaedd4a596..f36fc89f5710b29f323354540ae964a4494a33f5 100644 (file)
@@ -8,6 +8,7 @@ import java.security.KeyPair;
 import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.SecureRandom;
+import java.security.Security;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.Date;
@@ -18,6 +19,7 @@ import org.argeo.ArgeoException;
 import org.bouncycastle.cert.X509v3CertificateBuilder;
 import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
 import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.operator.ContentSigner;
 import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
 
@@ -25,47 +27,39 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  * Utilities around private keys and certificate, mostly wrapping BouncyCastle
  * implementations.
  */
-public class PkiUtils {
+class PkiUtils {
        private final static String SECURITY_PROVIDER;
        static {
-               // Security.addProvider(new BouncyCastleProvider());
+               Security.addProvider(new BouncyCastleProvider());
                SECURITY_PROVIDER = "BC";
        }
 
-       public static X509Certificate generateSelfSignedCertificate(
-                       KeyStore keyStore, X500Principal x500Principal, char[] keyPassword) {
+       public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal,
+                       char[] keyPassword) {
                try {
-                       KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA",
-                                       SECURITY_PROVIDER);
+                       KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
                        kpGen.initialize(1024, new SecureRandom());
                        KeyPair pair = kpGen.generateKeyPair();
                        Date notBefore = new Date(System.currentTimeMillis() - 10000);
-                       Date notAfter = new Date(
-                                       System.currentTimeMillis() + 24L * 3600 * 1000);
+                       Date notAfter = new Date(System.currentTimeMillis() + 24L * 3600 * 1000);
                        BigInteger serial = BigInteger.valueOf(System.currentTimeMillis());
-                       X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
-                                       x500Principal, serial, notBefore, notAfter, x500Principal,
-                                       pair.getPublic());
-                       ContentSigner sigGen = new JcaContentSignerBuilder(
-                                       "SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
+                       X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(x500Principal, serial, notBefore,
+                                       notAfter, x500Principal, pair.getPublic());
+                       ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(SECURITY_PROVIDER)
                                        .build(pair.getPrivate());
-                       X509Certificate cert = new JcaX509CertificateConverter()
-                                       .setProvider(SECURITY_PROVIDER).getCertificate(
-                                                       certGen.build(sigGen));
+                       X509Certificate cert = new JcaX509CertificateConverter().setProvider(SECURITY_PROVIDER)
+                                       .getCertificate(certGen.build(sigGen));
                        cert.checkValidity(new Date());
                        cert.verify(cert.getPublicKey());
 
-                       keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(),
-                                       keyPassword, new Certificate[] { cert });
+                       keyStore.setKeyEntry(x500Principal.getName(), pair.getPrivate(), keyPassword, new Certificate[] { cert });
                        return cert;
                } catch (Exception e) {
-                       throw new ArgeoException("Cannot generate self-signed certificate",
-                                       e);
+                       throw new ArgeoException("Cannot generate self-signed certificate", e);
                }
        }
 
-       public static KeyStore getKeyStore(File keyStoreFile,
-                       char[] keyStorePassword) {
+       public static KeyStore getKeyStore(File keyStoreFile, char[] keyStorePassword) {
                try {
                        KeyStore store = KeyStore.getInstance("PKCS12", SECURITY_PROVIDER);
                        if (keyStoreFile.exists()) {
@@ -81,8 +75,7 @@ public class PkiUtils {
                }
        }
 
-       public static void saveKeyStore(File keyStoreFile, char[] keyStorePassword,
-                       KeyStore keyStore) {
+       public static void saveKeyStore(File keyStoreFile, char[] keyStorePassword, KeyStore keyStore) {
                try {
                        try (FileOutputStream fis = new FileOutputStream(keyStoreFile)) {
                                keyStore.store(fis, keyStorePassword);
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/WebCmsSessionImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/WebCmsSessionImpl.java
new file mode 100644 (file)
index 0000000..f5203c9
--- /dev/null
@@ -0,0 +1,89 @@
+package org.argeo.cms.internal.kernel;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.cms.auth.WebCmsSession;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.useradmin.Authorization;
+
+public class WebCmsSessionImpl implements WebCmsSession {
+       private final static Log log = LogFactory.getLog(WebCmsSessionImpl.class);
+
+       private final String id;
+       private final Authorization authorization;
+
+       private List<SubHttpSession> subHttpSessions = new ArrayList<>();
+
+       private ServiceRegistration<WebCmsSession> serviceRegistration;
+
+       public WebCmsSessionImpl(String id, Authorization authorization) {
+               this.id = id;
+               this.authorization = authorization;
+       }
+
+       public void cleanUp() {
+               for (SubHttpSession subSession : subHttpSessions)
+                       subSession.cleanUp();
+               serviceRegistration.unregister();
+       }
+
+       @Override
+       public Authorization getAuthorization() {
+               return authorization;
+       }
+
+       @Override
+       public void addHttpSession(HttpServletRequest request) {
+               subHttpSessions.add(new SubHttpSession(request));
+       }
+
+       public String getId() {
+               return id;
+       }
+
+       public void setServiceRegistration(ServiceRegistration<WebCmsSession> serviceRegistration) {
+               this.serviceRegistration = serviceRegistration;
+       }
+
+       public String toString() {
+               return "CMS Session #" + id;
+       }
+
+       static class SubHttpSession {
+               private final HttpSession httpSession;
+               private final String sessionId;
+               private final String originalURI;
+               private final String servletPath;
+
+               private final Date start = new Date();
+
+               public SubHttpSession(HttpServletRequest request) {
+                       this.httpSession = request.getSession();
+                       this.sessionId = httpSession.getId();
+                       this.originalURI = request.getRequestURI();
+                       this.servletPath = request.getServletPath();
+               }
+
+               public Date getStart() {
+                       return start;
+               }
+
+               public void cleanUp() {
+                       try {
+                               httpSession.setAttribute(HttpContext.AUTHORIZATION, null);
+                               httpSession.setMaxInactiveInterval(1);
+                       } catch (Exception e) {
+                               log.warn("Could not clean up " + sessionId, e);
+                       }
+               }
+
+       }
+}
index 539aeb9e6b3b9ea3e065d9413c8772071716ecf9..2e63d52e10eed427654e317b2676d00bd9bef832 100644 (file)
@@ -1,4 +1,5 @@
 USER {
+    org.argeo.cms.auth.HttpLoginModule requisite;
     org.argeo.cms.auth.UserAdminLoginModule requisite;
     org.argeo.cms.auth.NodeUserLoginModule requisite;
 };
index b342d18bd21b00a1200472d16c06b9317c993f38..2e102c7121fde50769c08b234e41a3d7c80d9bcb 100644 (file)
@@ -38,7 +38,7 @@ import org.osgi.service.packageadmin.PackageAdmin;
 public class JackrabbitDataModel {
        private final static Log log = LogFactory.getLog(JackrabbitDataModel.class);
        private final static String DIGEST_ALGORITHM = "MD5";
-       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" };
+       final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd", "/org/argeo/jcr/docbook/docbook.cnd" };
 
        // data model
        /** Node type definitions in CND format */
diff --git a/org.argeo.server.jcr/src/org/argeo/jcr/docbook/DocBookNames.java b/org.argeo.server.jcr/src/org/argeo/jcr/docbook/DocBookNames.java
new file mode 100644 (file)
index 0000000..f4edb12
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.jcr.docbook;
+
+public interface DocBookNames {
+       public final static String DBK_ = "dbk:";
+       public final static String DBK_PARA = DBK_ + "para";
+       public final static String DBK_SECTION = DBK_ + "section";
+}
diff --git a/pom.xml b/pom.xml
index 66f01c11ef42f9a8fa1f5c8b76daa7e9c2345a44..3481788f23329af16269bd6adc14896d02251c3f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -16,6 +16,7 @@
                <argeo.rpm.stagingRepository>/srv/rpmfactory/argeo-osgi-2-staging/7/x86_64</argeo.rpm.stagingRepository>
                <!-- encoding, see http://is.gd/mvn_source_encoding -->
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+               <project.scm.id>code.argeo.org</project.scm.id>
        </properties>
        <modules>
                <!-- Base -->