package org.argeo.cms.auth;
+import org.osgi.service.http.HttpContext;
+
/** Public properties of the CMS Kernel */
public interface AuthConstants {
// LOGIN CONTEXTS
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;
+
}
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+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;
+ }
+
+}
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;
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 {
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);
}
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;
}
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();
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
// 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));
}
}
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;
}
}
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");
}
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;
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);
}
@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();
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)
// 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;
+ // }
}
--- /dev/null
+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();
+}
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());
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));
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";
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;
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",
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) {
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);
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);
}
}
}
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;
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;
* 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()) {
}
}
- 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);
--- /dev/null
+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);
+ }
+ }
+
+ }
+}
USER {
+ org.argeo.cms.auth.HttpLoginModule requisite;
org.argeo.cms.auth.UserAdminLoginModule requisite;
org.argeo.cms.auth.NodeUserLoginModule requisite;
};
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 */
--- /dev/null
+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";
+}
<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 -->