org.joda.time.*;resolution:=optional,\
org.springframework.context,\
org.springframework.core.io,\
+org.apache.jackrabbit.webdav.server,\
+org.apache.jackrabbit.webdav.jcr,\
*
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.HashMap;
-import java.util.Locale;
import java.util.Map;
-import java.util.ResourceBundle;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.Session;
import javax.jcr.nodetype.NodeType;
import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.x500.X500Principal;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.ArgeoException;
-import org.argeo.cms.auth.ArgeoLoginContext;
-import org.argeo.cms.auth.LoginRequiredException;
-import org.argeo.cms.i18n.Msg;
+import org.argeo.cms.auth.AuthConstants;
import org.argeo.jcr.JcrUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.AbstractEntryPoint;
HttpServletRequest httpRequest = RWT.getRequest();
final HttpSession httpSession = httpRequest.getSession();
AccessControlContext acc = (AccessControlContext) httpSession
- .getAttribute(KernelHeader.ACCESS_CONTROL_CONTEXT);
+ .getAttribute(AuthConstants.ACCESS_CONTROL_CONTEXT);
if (acc != null
&& Subject.getSubject(acc).getPrincipals(X500Principal.class)
.size() == 1) {
// Initial login
try {
- new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_USER, subject)
+ new LoginContext(AuthConstants.LOGIN_CONTEXT_USER, subject)
.login();
} catch (LoginException e) {
// if (log.isTraceEnabled())
// log.trace("Cannot authenticate user", e);
try {
- new ArgeoLoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS,
+ new LoginContext(AuthConstants.LOGIN_CONTEXT_ANONYMOUS,
subject).login();
} catch (LoginException eAnonymous) {
throw new ArgeoException("Cannot initialize subject",
*/
protected Node getDefaultNode(Session session) throws RepositoryException {
if (!session.hasPermission(defaultPath, "read")) {
- if (session.getUserID().equals("anonymous"))
- throw new LoginRequiredException();
+ if (session.getUserID().equals(AuthConstants.ROLE_ANONYMOUS))
+ // TODO throw a special exception
+ throw new CmsException("Login required");
else
throw new CmsException("Unauthorized");
}
} catch (Exception e) {
try {
// TODO find a less hacky way to log out
- new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_ANONYMOUS,
+ new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_ANONYMOUS,
subject).logout();
- new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_ANONYMOUS,
+ new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_ANONYMOUS,
subject).login();
} catch (LoginException eAnonymous) {
throw new ArgeoException(
+++ /dev/null
-package org.argeo.cms;
-
-/** Public properties of the CMS Kernel */
-public interface KernelHeader {
- final static String SECURITY_PROVIDER = "BC";// Bouncy Castle
-
- // LOGIN CONTEXTS
- final static String LOGIN_CONTEXT_USER = "USER";
- final static String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
- final static String LOGIN_CONTEXT_SYSTEM = "SYSTEM";
- final static String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
-
- // HTTP
- final static String ACCESS_CONTROL_CONTEXT = "org.argeo.node.accessControlContext";
-
- // RESERVED ROLES
- 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_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;
-
- // RESERVED USERNAMES
- public final static String USERNAME_ADMIN = "root";
- public final static String USERNAME_DEMO = "demo";
- @Deprecated
- public final static String USERNAME_ANONYMOUS = "anonymous";
-}
+++ /dev/null
-package org.argeo.cms.auth;
-
-import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.login.LoginContext;
-import javax.security.auth.login.LoginException;
-
-/**
- * Integrates JAAS with the Argeo platform, by using the Argeo CMS bundle
- * classloader as context classloader.
- */
-public class ArgeoLoginContext extends LoginContext {
- private static ThreadLocal<ClassLoader> currentContextClassLoader = new ThreadLocal<ClassLoader>() {
- @Override
- protected ClassLoader initialValue() {
- return Thread.currentThread().getContextClassLoader();
- }
-
- @Override
- public void set(ClassLoader value) {
- throw new IllegalAccessError("Current class loader is read-only");
- }
- };
-
- public ArgeoLoginContext(String name, Subject subject,
- CallbackHandler callbackHandler) throws LoginException {
- super(setContextClassLoaderForName(name), subject, callbackHandler);
- // reset current context classloader
- Thread.currentThread().setContextClassLoader(
- currentContextClassLoader.get());
- currentContextClassLoader.remove();
- }
-
- public ArgeoLoginContext(String name, Subject subject)
- throws LoginException {
- super(setContextClassLoaderForName(name), subject);
- // reset current context classloader
- Thread.currentThread().setContextClassLoader(
- currentContextClassLoader.get());
- currentContextClassLoader.remove();
- }
-
- /**
- * Set the context classloader
- *
- * @return the passed name, in order to chain calls in the constructor
- */
- private static String setContextClassLoaderForName(String name) {
- // store current context class loader;
- currentContextClassLoader.get();
- Thread.currentThread().setContextClassLoader(
- ArgeoLoginContext.class.getClassLoader());
- return name;
- }
-
- @Override
- public void login() throws LoginException {
- super.login();
- }
-
- @Override
- public void logout() throws LoginException {
- super.logout();
- }
-}
--- /dev/null
+package org.argeo.cms.auth;
+
+/** Public properties of the CMS Kernel */
+public interface AuthConstants {
+ // LOGIN CONTEXTS
+ final static String LOGIN_CONTEXT_USER = "USER";
+ final static String LOGIN_CONTEXT_ANONYMOUS = "ANONYMOUS";
+ final static String LOGIN_CONTEXT_SYSTEM = "SYSTEM";
+ final static String LOGIN_CONTEXT_SINGLE_USER = "SINGLE_USER";
+
+ // HTTP
+ final static String ACCESS_CONTROL_CONTEXT = "org.argeo.node.accessControlContext";
+
+ // RESERVED ROLES
+ 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_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
+ public final static String BUNDLE_CONTEXT_KEY = "org.argeo.security.bundleContext";
+ public final static String AUTHORIZATION_KEY = "org.argeo.security.authorization";
+}
+++ /dev/null
-package org.argeo.cms.auth;
-
-import javax.security.auth.login.LoginException;
-
-public class LoginCanceledException extends LoginException {
- private static final long serialVersionUID = 8289162094013471043L;
-
-}
+++ /dev/null
-package org.argeo.cms.auth;
-
-import org.argeo.cms.CmsException;
-
-/** Throwing this exception triggers redirection to a login page. */
-public class LoginRequiredException extends CmsException {
- private static final long serialVersionUID = 7009402894657958151L;
-
- public LoginRequiredException() {
- super("Login is required");
- }
-
- public LoginRequiredException(String message, Throwable e) {
- super(message, e);
- }
-
- public LoginRequiredException(String message) {
- super(message);
- }
-
-}
--- /dev/null
+package org.argeo.cms.auth;
+
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.cms.internal.kernel.Activator;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.service.useradmin.Authorization;
+
+/** Populates the shared state with this node context. */
+public class NodeContextLoginModule implements LoginModule, AuthConstants {
+ private Subject subject;
+ private Map<String, Object> sharedState;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ 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 {
+ sharedState.put(AuthConstants.BUNDLE_CONTEXT_KEY, Activator.getBundleContext());
+ Display display = Display.getCurrent();
+ if (display != null) {
+ Authorization authorization = (Authorization) display
+ .getData(AuthConstants.AUTHORIZATION_KEY);
+ if (authorization != null)
+ sharedState.put(AuthConstants.AUTHORIZATION_KEY, authorization);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ Display display = Display.getCurrent();
+ if (display != null) {
+ Authorization authorization = subject
+ .getPrivateCredentials(Authorization.class).iterator()
+ .next();
+ display.setData(AuthConstants.AUTHORIZATION_KEY, authorization);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ sharedState.remove(AuthConstants.BUNDLE_CONTEXT_KEY);
+ sharedState.remove(AuthConstants.AUTHORIZATION_KEY);
+ Display display = Display.getCurrent();
+ if (display != null)
+ display.setData(AuthConstants.AUTHORIZATION_KEY, null);
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ sharedState.remove(AuthConstants.BUNDLE_CONTEXT_KEY);
+ sharedState.remove(AuthConstants.AUTHORIZATION_KEY);
+ Display display = Display.getCurrent();
+ if (display != null)
+ display.setData(AuthConstants.AUTHORIZATION_KEY, null);
+ return true;
+ }
+
+}
--- /dev/null
+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;
+
+import javax.naming.InvalidNameException;
+import javax.naming.ldap.LdapName;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.jackrabbit.core.security.AnonymousPrincipal;
+import org.apache.jackrabbit.core.security.SecurityConstants;
+import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.auth.ImpliedByPrincipal;
+import org.osgi.service.useradmin.Authorization;
+
+public class NodeUserLoginModule implements LoginModule {
+ private Subject subject;
+
+ 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 {
+ try {
+ ROLE_KERNEL_NAME = new LdapName(AuthConstants.ROLE_KERNEL);
+ 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());
+ } catch (InvalidNameException e) {
+ throw new Error("Cannot initialize login module class", e);
+ }
+ }
+
+ private Authorization authorization;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
+ Map<String, ?> sharedState, Map<String, ?> options) {
+ this.subject = subject;
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ Iterator<Authorization> auth = subject.getPrivateCredentials(
+ Authorization.class).iterator();
+ if (!auth.hasNext())
+ return false;
+ authorization = auth.next();
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ if (authorization != null) {
+ Set<Principal> principals = subject.getPrincipals();
+ try {
+ String authName = authorization.getName();
+
+ // determine user's principal
+ final LdapName name;
+ final Principal userPrincipal;
+ if (authName == null) {
+ name = ROLE_ANONYMOUS_NAME;
+ userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
+ principals.add(userPrincipal);
+ principals.add(new AnonymousPrincipal());
+ } else {
+ name = new LdapName(authName);
+ checkUserName(name);
+ userPrincipal = new X500Principal(name.toString());
+ principals.add(userPrincipal);
+ principals.add(new ImpliedByPrincipal(ROLE_USER_NAME,
+ userPrincipal));
+ }
+
+ // Add roles provided by authorization
+ for (String role : authorization.getRoles()) {
+ LdapName roleName = new LdapName(role);
+ if (roleName.equals(name)) {
+ // skip
+ } else {
+ checkImpliedPrincipalName(roleName);
+ principals.add(new ImpliedByPrincipal(roleName
+ .toString(), userPrincipal));
+ if (roleName.equals(ROLE_ADMIN_NAME))
+ principals.add(new AdminPrincipal(
+ SecurityConstants.ADMIN_ID));
+ }
+ }
+
+ return true;
+ } catch (InvalidNameException e) {
+ throw new CmsException("Cannot commit", e);
+ }
+ } else
+ return false;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ cleanUp();
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ // TODO better deal with successive logout
+ if (subject == null)
+ return true;
+ // TODO make it less brutal
+ subject.getPrincipals().removeAll(
+ subject.getPrincipals(X500Principal.class));
+ subject.getPrincipals().removeAll(
+ subject.getPrincipals(ImpliedByPrincipal.class));
+ subject.getPrincipals().removeAll(
+ subject.getPrincipals(AdminPrincipal.class));
+ subject.getPrincipals().removeAll(
+ subject.getPrincipals(AnonymousPrincipal.class));
+ cleanUp();
+ return true;
+ }
+
+ private void cleanUp() {
+ subject = null;
+ authorization = null;
+ }
+
+ private void checkUserName(LdapName name) {
+ if (RESERVED_ROLES.contains(name))
+ throw new CmsException(name + " is a reserved name");
+ }
+
+ private void checkImpliedPrincipalName(LdapName 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");
+ }
+}
--- /dev/null
+package org.argeo.cms.auth;
+
+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.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.CredentialNotFoundException;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.ArgeoException;
+import org.osgi.framework.BundleContext;
+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 Subject subject;
+ private Map<String, Object> sharedState;
+ private CallbackHandler callbackHandler;
+ private boolean isAnonymous = false;
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
+ Map<String, ?> sharedState, Map<String, ?> options) {
+ try {
+ this.subject = subject;
+ this.sharedState = (Map<String, Object>) sharedState;
+ this.callbackHandler = callbackHandler;
+ if (options.containsKey("anonymous"))
+ 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 = (BundleContext) sharedState
+ .get(AuthConstants.BUNDLE_CONTEXT_KEY);
+ UserAdmin userAdmin = bc.getService(bc
+ .getServiceReference(UserAdmin.class));
+ Authorization authorization = (Authorization) sharedState
+ .get(AuthConstants.AUTHORIZATION_KEY);
+ if (authorization == null)
+ if (!isAnonymous) {
+ // ask for username and password
+ NameCallback nameCallback = new NameCallback("User");
+ PasswordCallback passwordCallback = new PasswordCallback(
+ "Password", false);
+
+ // handle callbacks
+ try {
+ callbackHandler.handle(new Callback[] { nameCallback,
+ passwordCallback });
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot handle callbacks", e);
+ }
+
+ // create credentials
+ final String username = nameCallback.getName();
+ if (username == null || username.trim().equals(""))
+ throw new CredentialNotFoundException(
+ "No credentials provided");
+
+ char[] password = {};
+ if (passwordCallback.getPassword() != null)
+ password = passwordCallback.getPassword();
+ else
+ throw new CredentialNotFoundException(
+ "No credentials provided");
+
+ User user = userAdmin.getUser(null, username);
+ if (user == null)
+ return false;
+ if (!user.hasCredential(null, password))
+ return false;
+ authorization = userAdmin.getAuthorization(user);
+ } else {
+ authorization = userAdmin.getAuthorization(null);
+ }
+ subject.getPrivateCredentials().add(authorization);
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ cleanUp();
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ cleanUp();
+ return true;
+ }
+
+ private void cleanUp() {
+ subject.getPrivateCredentials().removeAll(
+ subject.getPrivateCredentials(Authorization.class));
+ subject = null;
+ }
+
+}
import org.apache.jackrabbit.core.security.SecurityConstants;
import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
public class KernelLoginModule implements LoginModule {
private Subject subject;
if (names.isEmpty() || names.size() > 1)
throw new LoginException("Kernel must have been named");
X500Principal name = names.iterator().next();
- if (!KernelHeader.ROLE_KERNEL.equals(name.getName()))
+ if (!AuthConstants.ROLE_KERNEL.equals(name.getName()))
throw new LoginException("Kernel must be named named "
- + KernelHeader.ROLE_KERNEL);
+ + AuthConstants.ROLE_KERNEL);
// Private certificate
Set<X500PrivateCredential> privateCerts = subject
.getPrivateCredentials(X500PrivateCredential.class);
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.cms.internal.auth;
+
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.security.Privilege;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
+
+/**
+ * Manages data expected by the Argeo security model, such as user home and
+ * profile.
+ */
+public class SimpleJcrSecurityModel implements JcrSecurityModel {
+ private final static Log log = LogFactory
+ .getLog(SimpleJcrSecurityModel.class);
+ // ArgeoNames not implemented as interface in order to ease derivation by
+ // Jackrabbit bundles
+
+ /** The home base path. */
+ private String homeBasePath = "/home";
+ private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH;
+
+ @Override
+ public void init(Session adminSession) throws RepositoryException {
+ JcrUtils.mkdirs(adminSession, homeBasePath);
+ JcrUtils.mkdirs(adminSession, peopleBasePath);
+ adminSession.save();
+
+ JcrUtils.addPrivilege(adminSession, homeBasePath,
+ AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, peopleBasePath,
+ AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL);
+ }
+
+ public synchronized Node sync(Session session, String username,
+ List<String> roles) {
+ // TODO check user name validity (e.g. should not start by ROLE_)
+
+ try {
+ Node userHome = UserJcrUtils.getUserHome(session, username);
+ if (userHome == null) {
+ String homePath = generateUserPath(homeBasePath, username);
+ userHome = JcrUtils.mkdirs(session, homePath);
+ // userHome = JcrUtils.mkfolders(session, homePath);
+ userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+ userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, homePath, username);
+ JcrUtils.addPrivilege(session, homePath, username,
+ Privilege.JCR_ALL);
+ } else {
+ // for backward compatibility with pre 1.0 security model
+ if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) {
+ userHome.getNode(ArgeoNames.ARGEO_PROFILE).remove();
+ userHome.getSession().save();
+ }
+ }
+
+ // Remote roles
+ if (roles != null) {
+ // writeRemoteRoles(userHome, roles);
+ }
+
+ Node userProfile = UserJcrUtils.getUserProfile(session, username);
+ // new user
+ if (userProfile == null) {
+ String personPath = generateUserPath(peopleBasePath, username);
+ Node personBase = JcrUtils.mkdirs(session, personPath);
+ userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE);
+ userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+ userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
+ userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED,
+ true);
+ userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED,
+ true);
+ userProfile.setProperty(
+ ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, userProfile.getPath(),
+ username);
+ JcrUtils.addPrivilege(session, userProfile.getPath(), username,
+ Privilege.JCR_READ);
+ }
+
+ // Remote roles
+ if (roles != null) {
+ writeRemoteRoles(userProfile, roles);
+ }
+ return userProfile;
+ } catch (RepositoryException e) {
+ JcrUtils.discardQuietly(session);
+ throw new ArgeoException("Cannot sync node security model for "
+ + username, e);
+ }
+ }
+
+ /** Generate path for a new user home */
+ protected String generateUserPath(String base, String username) {
+ int atIndex = username.indexOf('@');
+ if (atIndex > 0) {
+ String domain = username.substring(0, atIndex);
+ String name = username.substring(atIndex + 1);
+ return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
+ + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
+ + name;
+ } else if (atIndex == 0 || atIndex == (username.length() - 1)) {
+ throw new ArgeoException("Unsupported username " + username);
+ } else {
+ return base + '/' + JcrUtils.firstCharsToPath(username, 2) + '/'
+ + username;
+ }
+ }
+
+ /** Write remote roles used by remote access in the home directory */
+ protected void writeRemoteRoles(Node userHome, List<String> roles)
+ throws RepositoryException {
+ boolean writeRoles = false;
+ if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+ Value[] remoteRoles = userHome.getProperty(
+ ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+ if (remoteRoles.length != roles.size())
+ writeRoles = true;
+ else
+ for (int i = 0; i < remoteRoles.length; i++)
+ if (!remoteRoles[i].getString().equals(roles.get(i)))
+ writeRoles = true;
+ } else
+ writeRoles = true;
+
+ if (writeRoles) {
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkout(userHome.getPath());
+ String[] roleIds = roles.toArray(new String[roles.size()]);
+ userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds);
+ JcrUtils.updateLastModified(userHome);
+ userHome.getSession().save();
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkin(userHome.getPath());
+ if (log.isDebugEnabled())
+ log.debug("Wrote remote roles " + roles + " for "
+ + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
+ }
+
+ }
+
+ public void setHomeBasePath(String homeBasePath) {
+ this.homeBasePath = homeBasePath;
+ }
+
+}
+++ /dev/null
-package org.argeo.cms.internal.auth;
-
-import java.security.Principal;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.security.auth.Subject;
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.login.CredentialNotFoundException;
-import javax.security.auth.login.LoginException;
-import javax.security.auth.spi.LoginModule;
-import javax.security.auth.x500.X500Principal;
-
-import org.apache.jackrabbit.core.security.AnonymousPrincipal;
-import org.apache.jackrabbit.core.security.SecurityConstants;
-import org.apache.jackrabbit.core.security.principal.AdminPrincipal;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
-import org.argeo.cms.internal.kernel.Activator;
-import org.osgi.framework.BundleContext;
-import org.osgi.service.useradmin.Authorization;
-import org.osgi.service.useradmin.User;
-import org.osgi.service.useradmin.UserAdmin;
-
-public class UserAdminLoginModule implements LoginModule {
- private Subject subject;
- private CallbackHandler callbackHandler;
- private boolean isAnonymous = false;
-
- 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 {
- try {
- ROLE_KERNEL_NAME = new LdapName(KernelHeader.ROLE_KERNEL);
- ROLE_ADMIN_NAME = new LdapName(KernelHeader.ROLE_ADMIN);
- ROLE_USER_NAME = new LdapName(KernelHeader.ROLE_USER);
- ROLE_ANONYMOUS_NAME = new LdapName(KernelHeader.ROLE_ANONYMOUS);
- RESERVED_ROLES = Collections.unmodifiableList(Arrays
- .asList(new LdapName[] { ROLE_KERNEL_NAME, ROLE_ADMIN_NAME,
- ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
- new LdapName(KernelHeader.ROLE_GROUP_ADMIN),
- new LdapName(KernelHeader.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;
-
- @Override
- public void initialize(Subject subject, CallbackHandler callbackHandler,
- Map<String, ?> sharedState, Map<String, ?> options) {
- try {
- this.subject = subject;
- this.callbackHandler = callbackHandler;
- if (options.containsKey("anonymous"))
- isAnonymous = Boolean.parseBoolean(options.get("anonymous")
- .toString());
- // String ldifFile = options.get("ldifFile").toString();
- // InputStream in = new URL(ldifFile).openStream();
- // userAdmin = new LdifUserAdmin(in);
- } catch (Exception e) {
- throw new CmsException("Cannot initialize login module", e);
- }
- }
-
- @Override
- public boolean login() throws LoginException {
- // TODO use a callback in order to get the bundle context
- BundleContext bc = Activator.getBundleContext();
- UserAdmin userAdmin = bc.getService(bc
- .getServiceReference(UserAdmin.class));
- final User user;
-
- if (!isAnonymous) {
- // ask for username and password
- NameCallback nameCallback = new NameCallback("User");
- PasswordCallback passwordCallback = new PasswordCallback(
- "Password", false);
- // handle callbacks
- try {
- callbackHandler.handle(new Callback[] { nameCallback,
- passwordCallback });
- } catch (Exception e) {
- throw new CmsException("Cannot handle callbacks", e);
- }
-
- // create credentials
- final String username = nameCallback.getName();
- if (username == null || username.trim().equals(""))
- throw new CredentialNotFoundException("No credentials provided");
-
- char[] password = {};
- if (passwordCallback.getPassword() != null)
- password = passwordCallback.getPassword();
- else
- throw new CredentialNotFoundException("No credentials provided");
-
- user = userAdmin.getUser(null, username);
- if (user == null)
- return false;
- if (!user.hasCredential(null, password))
- return false;
- } else
- // anonymous
- user = null;
- this.authorization = userAdmin.getAuthorization(user);
- return true;
- }
-
- @Override
- public boolean commit() throws LoginException {
- if (authorization != null) {
- Set<Principal> principals = subject.getPrincipals();
- try {
- String authName = authorization.getName();
-
- // determine user's principal
- final LdapName name;
- final Principal userPrincipal;
- if (authName == null) {
- name = ROLE_ANONYMOUS_NAME;
- userPrincipal = ROLE_ANONYMOUS_PRINCIPAL;
- principals.add(userPrincipal);
- principals.add(new AnonymousPrincipal());
- } else {
- name = new LdapName(authName);
- checkUserName(name);
- userPrincipal = new X500Principal(name.toString());
- principals.add(userPrincipal);
- principals.add(new ImpliedByPrincipal(ROLE_USER_NAME,
- userPrincipal));
- }
-
- // Add roles provided by authorization
- for (String role : authorization.getRoles()) {
- LdapName roleName = new LdapName(role);
- if (roleName.equals(name)) {
- // skip
- } else {
- checkImpliedPrincipalName(roleName);
- principals.add(new ImpliedByPrincipal(roleName
- .toString(), userPrincipal));
- if (roleName.equals(ROLE_ADMIN_NAME))
- principals.add(new AdminPrincipal(
- SecurityConstants.ADMIN_ID));
- }
- }
-
- return true;
- } catch (InvalidNameException e) {
- throw new CmsException("Cannot commit", e);
- }
- } else
- return false;
- }
-
- @Override
- public boolean abort() throws LoginException {
- cleanUp();
- return true;
- }
-
- @Override
- public boolean logout() throws LoginException {
- // TODO better deal with successive logout
- if (subject == null)
- return true;
- // TODO make it less brutal
- subject.getPrincipals().removeAll(
- subject.getPrincipals(X500Principal.class));
- subject.getPrincipals().removeAll(
- subject.getPrincipals(ImpliedByPrincipal.class));
- cleanUp();
- return true;
- }
-
- private void cleanUp() {
- subject = null;
- authorization = null;
- }
-
- private void checkUserName(LdapName name) {
- if (RESERVED_ROLES.contains(name))
- throw new CmsException(name + " is a reserved name");
- }
-
- private void checkImpliedPrincipalName(LdapName 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");
- }
-}
--- /dev/null
+package org.argeo.cms.internal.kernel;
+
+import static org.argeo.cms.auth.AuthConstants.ACCESS_CONTROL_CONTEXT;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URL;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.cert.X509Certificate;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.jackrabbit.server.SessionProvider;
+import org.apache.jackrabbit.server.remoting.davex.JcrRemotingServlet;
+import org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.JcrUtils;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.osgi.service.useradmin.Authorization;
+
+/**
+ * Intercepts and enriches http access, mainly focusing on security and
+ * transactionality.
+ */
+class DataHttp implements KernelConstants, ArgeoJcrConstants {
+ private final static Log log = LogFactory.getLog(DataHttp.class);
+
+ private final static String ATTR_AUTH = "auth";
+ private final static String HEADER_AUTHORIZATION = "Authorization";
+ private final static String HEADER_WWW_AUTHENTICATE = "WWW-Authenticate";
+
+ // private final AuthenticationManager authenticationManager;
+ private final HttpService httpService;
+
+ // FIXME Make it more unique
+ private String httpAuthRealm = "Argeo";
+
+ // WebDav / JCR remoting
+ private OpenInViewSessionProvider sessionProvider;
+
+ DataHttp(HttpService httpService, JackrabbitNode node) {
+ this.httpService = httpService;
+ sessionProvider = new OpenInViewSessionProvider();
+ registerRepositoryServlets(ALIAS_NODE, node);
+ }
+
+ public void destroy() {
+ unregisterRepositoryServlets(ALIAS_NODE);
+ }
+
+ void registerRepositoryServlets(String alias, Repository repository) {
+ try {
+ registerWebdavServlet(alias, repository, true);
+ registerWebdavServlet(alias, repository, false);
+ registerRemotingServlet(alias, repository, true);
+ registerRemotingServlet(alias, repository, false);
+ } catch (Exception e) {
+ throw new CmsException(
+ "Could not register servlets for repository " + alias, e);
+ }
+ }
+
+ void unregisterRepositoryServlets(String alias) {
+ // FIXME unregister servlets
+ }
+
+ void registerWebdavServlet(String alias, Repository repository,
+ boolean anonymous) throws NamespaceException, ServletException {
+ WebdavServlet webdavServlet = new WebdavServlet(repository,
+ sessionProvider);
+ String pathPrefix = anonymous ? WEBDAV_PUBLIC : WEBDAV_PRIVATE;
+ String path = pathPrefix + "/" + alias;
+ Properties ip = new Properties();
+ ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_CONFIG, WEBDAV_CONFIG);
+ ip.setProperty(WebdavServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
+ // httpService.registerFilter(path, anonymous ? new AnonymousFilter()
+ // : new DavFilter(), null, null);
+ // Cast to servlet because of a weird behaviour in Eclipse
+ httpService.registerServlet(path, (Servlet) webdavServlet, ip,
+ new DataHttpContext(anonymous));
+ }
+
+ void registerRemotingServlet(String alias, Repository repository,
+ boolean anonymous) throws NamespaceException, ServletException {
+ String pathPrefix = anonymous ? REMOTING_PUBLIC : REMOTING_PRIVATE;
+ RemotingServlet remotingServlet = new RemotingServlet(repository,
+ sessionProvider);
+ String path = pathPrefix + "/" + alias;
+ Properties ip = new Properties();
+ ip.setProperty(JcrRemotingServlet.INIT_PARAM_RESOURCE_PATH_PREFIX, path);
+
+ // Looks like a bug in Jackrabbit remoting init
+ ip.setProperty(RemotingServlet.INIT_PARAM_HOME,
+ KernelUtils.getOsgiInstanceDir() + "/tmp/jackrabbit");
+ ip.setProperty(RemotingServlet.INIT_PARAM_TMP_DIRECTORY, "remoting");
+ // in order to avoid annoying warning.
+ ip.setProperty(RemotingServlet.INIT_PARAM_PROTECTED_HANDLERS_CONFIG, "");
+ // Cast to servlet because of a weird behaviour in Eclipse
+ // httpService.registerFilter(path, anonymous ? new AnonymousFilter()
+ // : new DavFilter(), null, null);
+ httpService.registerServlet(path, (Servlet) remotingServlet, ip,
+ new DataHttpContext(anonymous));
+ }
+
+ // private Boolean isSessionAuthenticated(HttpSession httpSession) {
+ // SecurityContext contextFromSession = (SecurityContext) httpSession
+ // .getAttribute(SPRING_SECURITY_CONTEXT_KEY);
+ // return contextFromSession != null;
+ // }
+
+ private void requestBasicAuth(HttpSession httpSession,
+ HttpServletResponse response) {
+ response.setStatus(401);
+ response.setHeader(HEADER_WWW_AUTHENTICATE, "basic realm=\""
+ + httpAuthRealm + "\"");
+ httpSession.setAttribute(ATTR_AUTH, Boolean.TRUE);
+ }
+
+ private CallbackHandler basicAuth(String authHeader) {
+ if (authHeader != null) {
+ StringTokenizer st = new StringTokenizer(authHeader);
+ if (st.hasMoreTokens()) {
+ String basic = st.nextToken();
+ if (basic.equalsIgnoreCase("Basic")) {
+ try {
+ // TODO manipulate char[]
+ String credentials = new String(Base64.decodeBase64(st
+ .nextToken()), "UTF-8");
+ // log.debug("Credentials: " + credentials);
+ int p = credentials.indexOf(":");
+ if (p != -1) {
+ final String login = credentials.substring(0, p)
+ .trim();
+ final char[] password = credentials
+ .substring(p + 1).trim().toCharArray();
+
+ return new CallbackHandler() {
+ public void handle(Callback[] callbacks) {
+ for (Callback cb : callbacks) {
+ if (cb instanceof NameCallback)
+ ((NameCallback) cb).setName(login);
+ else if (cb instanceof PasswordCallback)
+ ((PasswordCallback) cb)
+ .setPassword(password);
+ }
+ }
+ };
+ } else {
+ throw new CmsException(
+ "Invalid authentication token");
+ }
+ } catch (Exception e) {
+ throw new CmsException(
+ "Couldn't retrieve authentication", e);
+ }
+ }
+ }
+ }
+ throw new CmsException("Couldn't retrieve authentication");
+ }
+
+ private X509Certificate extractCertificate(HttpServletRequest req) {
+ X509Certificate[] certs = (X509Certificate[]) req
+ .getAttribute("javax.servlet.request.X509Certificate");
+ if (null != certs && certs.length > 0) {
+ return certs[0];
+ }
+ return null;
+ }
+
+ private Subject subjectFromRequest(HttpServletRequest request) {
+ HttpSession httpSession = request.getSession();
+ Authorization authorization = (Authorization) request
+ .getAttribute(HttpContext.AUTHORIZATION);
+ if (authorization == null)
+ throw new CmsException("Not authenticated");
+ AccessControlContext acc = (AccessControlContext) httpSession
+ .getAttribute(AuthConstants.ACCESS_CONTROL_CONTEXT);
+ Subject subject = Subject.getSubject(acc);
+ return subject;
+ }
+
+ private class DataHttpContext implements HttpContext {
+ private final boolean anonymous;
+
+ DataHttpContext(boolean anonymous) {
+ this.anonymous = anonymous;
+ }
+
+ @Override
+ public boolean handleSecurity(HttpServletRequest request,
+ HttpServletResponse response) throws IOException {
+ final Subject subject;
+
+ if (anonymous) {
+ subject = KernelUtils.anonymousLogin();
+ Authorization authorization = subject
+ .getPrivateCredentials(Authorization.class).iterator()
+ .next();
+ request.setAttribute(AUTHORIZATION, authorization);
+ return true;
+ }
+
+ final HttpSession httpSession = request.getSession();
+ AccessControlContext acc = (AccessControlContext) httpSession
+ .getAttribute(AuthConstants.ACCESS_CONTROL_CONTEXT);
+ if (acc != null) {
+ subject = Subject.getSubject(acc);
+ } else {
+ // Process basic auth
+ String basicAuth = request.getHeader(HEADER_AUTHORIZATION);
+ if (basicAuth != null) {
+ CallbackHandler token = basicAuth(basicAuth);
+ try {
+ LoginContext lc = new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_USER, token);
+ lc.login();
+ subject = lc.getSubject();
+ } catch (LoginException e) {
+ throw new CmsException("Could not login", e);
+ }
+ Subject.doAs(subject, new PrivilegedAction<Void>() {
+ public Void run() {
+ // add security context to session
+ httpSession.setAttribute(ACCESS_CONTROL_CONTEXT,
+ AccessController.getContext());
+ return null;
+ }
+ });
+ } else {
+ requestBasicAuth(httpSession, response);
+ return false;
+ }
+ }
+ // authenticate request
+ Authorization authorization = subject
+ .getPrivateCredentials(Authorization.class).iterator()
+ .next();
+ request.setAttribute(AUTHORIZATION, authorization);
+ return true;
+ }
+
+ @Override
+ public URL getResource(String name) {
+ return Activator.getBundleContext().getBundle().getResource(name);
+ }
+
+ @Override
+ public String getMimeType(String name) {
+ return null;
+ }
+
+ }
+
+ /**
+ * Implements an open session in view patter: a new JCR session is created
+ * for each request
+ */
+ private class OpenInViewSessionProvider implements SessionProvider,
+ Serializable {
+ private static final long serialVersionUID = 2270957712453841368L;
+
+ public Session getSession(HttpServletRequest request, Repository rep,
+ String workspace) throws javax.jcr.LoginException,
+ ServletException, RepositoryException {
+ return login(request, rep, workspace);
+ }
+
+ protected Session login(HttpServletRequest request,
+ Repository repository, String workspace)
+ throws RepositoryException {
+ if (log.isTraceEnabled())
+ log.trace("Login to workspace "
+ + (workspace == null ? "<default>" : workspace)
+ + " in web session " + request.getSession().getId());
+ return repository.login(workspace);
+ }
+
+ public void releaseSession(Session session) {
+ JcrUtils.logoutQuietly(session);
+ if (log.isTraceEnabled())
+ log.trace("Logged out remote JCR session " + session);
+ }
+ }
+
+ private class WebdavServlet extends SimpleWebdavServlet {
+ private static final long serialVersionUID = -4687354117811443881L;
+ private final Repository repository;
+
+ public WebdavServlet(Repository repository,
+ SessionProvider sessionProvider) {
+ this.repository = repository;
+ setSessionProvider(sessionProvider);
+ }
+
+ public Repository getRepository() {
+ return repository;
+ }
+
+ @Override
+ protected void service(final HttpServletRequest request,
+ final HttpServletResponse response) throws ServletException,
+ IOException {
+ try {
+ Subject subject = subjectFromRequest(request);
+ Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ WebdavServlet.super.service(request, response);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new CmsException("Cannot process webdav request",
+ e.getException());
+ }
+ }
+ }
+
+ private class RemotingServlet extends JcrRemotingServlet {
+ private static final long serialVersionUID = 4605238259548058883L;
+ private final Repository repository;
+ private final SessionProvider sessionProvider;
+
+ public RemotingServlet(Repository repository,
+ SessionProvider sessionProvider) {
+ this.repository = repository;
+ this.sessionProvider = sessionProvider;
+ }
+
+ @Override
+ protected Repository getRepository() {
+ return repository;
+ }
+
+ @Override
+ protected SessionProvider getSessionProvider() {
+ return sessionProvider;
+ }
+
+ @Override
+ protected void service(final HttpServletRequest request,
+ final HttpServletResponse response) throws ServletException,
+ IOException {
+ try {
+ Subject subject = subjectFromRequest(request);
+ Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
+ @Override
+ public Void run() throws Exception {
+ RemotingServlet.super.service(request, response);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new CmsException("Cannot process JCR remoting request",
+ e.getException());
+ }
+ }
+ }
+}
import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
-import java.util.Properties;
import javax.jcr.Repository;
import javax.jcr.RepositoryFactory;
+import javax.jcr.Session;
import javax.security.auth.Subject;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
-import org.osgi.service.http.HttpService;
+import org.osgi.service.useradmin.UserAdmin;
import org.osgi.util.tracker.ServiceTracker;
/**
ThreadGroup threadGroup = new ThreadGroup(Kernel.class.getSimpleName());
JackrabbitNode node;
-
+ private NodeUserAdmin userAdmin;
private SimpleTransactionManager transactionManager;
private OsgiJackrabbitRepositoryFactory repositoryFactory;
- private NodeHttp nodeHttp;
+ private DataHttp nodeHttp;
private KernelThread kernelThread;
public Kernel() {
- nodeSecurity = new NodeSecurity(bundleContext);
+ nodeSecurity = new NodeSecurity();
}
final void init() {
repositoryFactory = new OsgiJackrabbitRepositoryFactory();
// Authentication
- nodeSecurity.getUserAdmin().setTransactionManager(
- transactionManager);
+ Session adminSession = node.login();
+ userAdmin = new NodeUserAdmin(adminSession);
+ userAdmin.setTransactionManager(transactionManager);
+ bundleContext.registerService(UserAdmin.class, userAdmin,
+ userAdmin.currentState());
// Equinox dependency
// ExtendedHttpService httpService = waitForHttpService();
TransactionSynchronizationRegistry.class,
transactionManager.getTransactionSynchronizationRegistry(),
null);
- nodeSecurity.publish();
node.publish(repositoryFactory);
bundleContext.registerService(RepositoryFactory.class,
repositoryFactory, null);
if (nodeHttp != null)
nodeHttp.destroy();
- // if (nodeSecurity != null)
- // nodeSecurity.destroy();
+ if (userAdmin != null)
+ userAdmin.destroy();
if (node != null)
node.destroy();
}
private void addHttpService(ServiceReference<?> sr) {
-// for (String key : sr.getPropertyKeys())
-// log.debug(key + "=" + sr.getProperty(key));
+ // for (String key : sr.getPropertyKeys())
+ // log.debug(key + "=" + sr.getProperty(key));
ExtendedHttpService httpService = (ExtendedHttpService) bundleContext
.getService(sr);
// TODO find constants
Object httpPort = sr.getProperty("http.port");
Object httpsPort = sr.getProperty("https.port");
- nodeHttp = new NodeHttp(httpService, node);
+ nodeHttp = new DataHttp(httpService, node);
if (log.isDebugEnabled())
log.debug("HTTP " + httpPort
+ (httpsPort != null ? " - HTTPS " + httpsPort : ""));
import org.apache.commons.logging.Log;
import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
/** Package utilities */
class KernelUtils implements KernelConstants {
Subject subject = new Subject();
LoginContext lc;
try {
- lc = new LoginContext(KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject);
+ lc = new LoginContext(AuthConstants.LOGIN_CONTEXT_ANONYMOUS, subject);
lc.login();
return subject;
} catch (LoginException e) {
import java.util.Collections;
import java.util.List;
+import javax.security.auth.x500.X500Principal;
+
import org.osgi.service.useradmin.Authorization;
class NodeAuthorization implements Authorization {
public NodeAuthorization(String name, String displayName,
Collection<String> systemRoles, String[] roles) {
- this.name = name;
+ this.name = new X500Principal(name).getName();
this.displayName = displayName;
this.systemRoles = Collections.unmodifiableList(new ArrayList<String>(
systemRoles));
package org.argeo.cms.internal.kernel;
-import static org.argeo.cms.KernelHeader.ACCESS_CONTROL_CONTEXT;
+import static org.argeo.cms.auth.AuthConstants.ACCESS_CONTROL_CONTEXT;
import java.io.IOException;
import java.security.AccessControlContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
import org.argeo.jackrabbit.servlet.OpenInViewSessionProvider;
import org.argeo.jackrabbit.servlet.RemotingServlet;
import org.argeo.jackrabbit.servlet.WebdavServlet;
* Intercepts and enriches http access, mainly focusing on security and
* transactionality.
*/
+@Deprecated
class NodeHttp implements KernelConstants, ArgeoJcrConstants {
private final static Log log = LogFactory.getLog(NodeHttp.class);
ServletException {
AccessControlContext acc = (AccessControlContext) httpSession
- .getAttribute(KernelHeader.ACCESS_CONTROL_CONTEXT);
+ .getAttribute(AuthConstants.ACCESS_CONTROL_CONTEXT);
final Subject subject;
if (acc != null) {
subject = Subject.getSubject(acc);
CallbackHandler token = basicAuth(basicAuth);
try {
LoginContext lc = new LoginContext(
- KernelHeader.LOGIN_CONTEXT_USER, token);
+ AuthConstants.LOGIN_CONTEXT_USER, token);
lc.login();
subject = lc.getSubject();
} catch (LoginException e) {
import java.io.File;
import java.io.IOException;
import java.net.URL;
-import java.nio.file.ProviderNotFoundException;
import java.security.KeyStore;
import java.security.Provider;
import java.security.Security;
import java.util.Arrays;
-import java.util.Hashtable;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
import org.argeo.security.crypto.PkiUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.useradmin.UserAdmin;
/** Authentication and user management. */
class NodeSecurity {
+ final static String SECURITY_PROVIDER = "BC";// Bouncy Castle
+
private final static Log log;
static {
log = LogFactory.getLog(NodeSecurity.class);
log.error("Provider " + provider.getName()
+ " already installed and could not be set as default");
Provider defaultProvider = Security.getProviders()[0];
- if (!defaultProvider.getName().equals(KernelHeader.SECURITY_PROVIDER))
+ if (!defaultProvider.getName().equals(SECURITY_PROVIDER))
log.error("Provider name is " + defaultProvider.getName()
- + " but it should be " + KernelHeader.SECURITY_PROVIDER);
+ + " but it should be " + SECURITY_PROVIDER);
}
- private final BundleContext bundleContext;
- private final NodeUserAdmin userAdmin;
private final Subject kernelSubject;
- private ServiceRegistration<UserAdmin> userAdminReg;
-
- public NodeSecurity(BundleContext bundleContext) {
+ public NodeSecurity() {
// Configure JAAS first
URL url = getClass().getClassLoader().getResource(
KernelConstants.JAAS_CONFIG);
System.setProperty("java.security.auth.login.config",
url.toExternalForm());
- this.bundleContext = bundleContext;
this.kernelSubject = logKernel();
- userAdmin = new NodeUserAdmin();
}
private Subject logKernel() {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
// alias
- ((NameCallback) callbacks[1]).setName(KernelHeader.ROLE_KERNEL);
+ ((NameCallback) callbacks[1]).setName(AuthConstants.ROLE_KERNEL);
// store pwd
((PasswordCallback) callbacks[2]).setPassword("changeit"
.toCharArray());
return kernelSubject;
}
- public void publish() {
- userAdminReg = bundleContext.registerService(UserAdmin.class,
- userAdmin, userAdmin.currentState());
- }
-
void destroy() {
- userAdmin.destroy();
- userAdminReg.unregister();
-
// Logout kernel
try {
LoginContext kernelLc = new LoginContext(
throw new CmsException("Cannot log in kernel", e);
}
- Security.removeProvider(KernelHeader.SECURITY_PROVIDER);
- }
-
- public NodeUserAdmin getUserAdmin() {
- return userAdmin;
+ Security.removeProvider(SECURITY_PROVIDER);
}
public Subject getKernelSubject() {
keyStoreFile.getParentFile().mkdirs();
KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd);
PkiUtils.generateSelfSignedCertificate(keyStore,
- new X500Principal(KernelHeader.ROLE_KERNEL), keyPwd);
+ new X500Principal(AuthConstants.ROLE_KERNEL), keyPwd);
PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore);
} catch (Exception e) {
throw new CmsException("Cannot create key store "
import java.util.Map;
import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.security.Privilege;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.transaction.TransactionManager;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
import org.argeo.cms.CmsException;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.jcr.ArgeoJcrConstants;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.ArgeoTypes;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
import org.argeo.osgi.useradmin.LdapUserAdmin;
import org.argeo.osgi.useradmin.LdifUserAdmin;
import org.argeo.osgi.useradmin.UserAdminConf;
final static LdapName ROLES_BASE;
static {
try {
- ROLES_BASE = new LdapName(KernelHeader.ROLES_BASEDN);
+ ROLES_BASE = new LdapName(AuthConstants.ROLES_BASEDN);
} catch (InvalidNameException e) {
throw new UserDirectoryException("Cannot initialize "
+ NodeUserAdmin.class, e);
private UserAdmin nodeRoles = null;
private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
- public NodeUserAdmin() {
+ /** The home base path. */
+ private String homeBasePath = "/home";
+ private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH;
+ private Session adminSession;
+
+ public NodeUserAdmin(Session adminSession) {
+ this.adminSession = adminSession;
File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
File nodeBaseDir = new File(osgiInstanceDir, "node");
nodeBaseDir.mkdirs();
+ u.getScheme() + "] enabled.");
}
- // NOde roles
+ // Node roles
String nodeRolesUri = KernelUtils
.getFrameworkProp(KernelConstants.ROLES_URI);
- String baseNodeRoleDn = KernelHeader.ROLES_BASEDN;
+ String baseNodeRoleDn = AuthConstants.ROLES_BASEDN;
if (nodeRolesUri == null) {
File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
if (!nodeRolesFile.exists())
addUserAdmin(baseNodeRoleDn, (UserAdmin) nodeRoles);
if (log.isTraceEnabled())
log.trace("Node roles enabled.");
+
+ // JCR
+ initJcr(adminSession);
}
Dictionary<String, ?> currentState() {
@Override
public Authorization getAuthorization(User user) {
- if (user == null) {
+ if (user == null) {// anonymous
return nodeRoles.getAuthorization(null);
}
UserAdmin userAdmin = findUserAdmin(user.getName());
.getRole(role));
systemRoles.addAll(Arrays.asList(auth.getRoles()));
}
- return new NodeAuthorization(rawAuthorization.getName(),
- rawAuthorization.toString(), systemRoles,
- rawAuthorization.getRoles());
+ Authorization authorization = new NodeAuthorization(
+ rawAuthorization.getName(), rawAuthorization.toString(),
+ systemRoles, rawAuthorization.getRoles());
+ syncJcr(adminSession, authorization);
+ return authorization;
}
//
// USER ADMIN AGGREGATOR
//
public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
- if (baseDn.equals(KernelHeader.ROLES_BASEDN)) {
+ if (baseDn.equals(AuthConstants.ROLES_BASEDN)) {
nodeRoles = userAdmin;
return;
}
}
public synchronized void removeUserAdmin(String baseDn) {
- if (baseDn.equals(KernelHeader.ROLES_BASEDN))
+ if (baseDn.equals(AuthConstants.ROLES_BASEDN))
throw new UserDirectoryException("Node roles cannot be removed.");
LdapName base;
try {
.setTransactionManager(transactionManager);
}
}
+
+ /*
+ * JCR
+ */
+ private void initJcr(Session adminSession) {
+ try {
+ JcrUtils.mkdirs(adminSession, homeBasePath);
+ JcrUtils.mkdirs(adminSession, peopleBasePath);
+ adminSession.save();
+
+ JcrUtils.addPrivilege(adminSession, homeBasePath,
+ AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
+ JcrUtils.addPrivilege(adminSession, peopleBasePath,
+ AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL);
+ adminSession.save();
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot initialize node user admin", e);
+ }
+ }
+
+ private Node syncJcr(Session session, Authorization authorization) {
+ // TODO check user name validity (e.g. should not start by ROLE_)
+ String username = authorization.getName();
+ String[] roles = authorization.getRoles();
+ try {
+ Node userHome = UserJcrUtils.getUserHome(session, username);
+ if (userHome == null) {
+ String homePath = generateUserPath(homeBasePath, username);
+ if (session.itemExists(homePath))// duplicate user id
+ userHome = session.getNode(homePath).getParent()
+ .addNode(JcrUtils.lastPathElement(homePath));
+ else
+ userHome = JcrUtils.mkdirs(session, homePath);
+ // userHome = JcrUtils.mkfolders(session, homePath);
+ userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+ userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, homePath, username);
+ JcrUtils.addPrivilege(session, homePath, username,
+ Privilege.JCR_ALL);
+ }
+
+ Node userProfile = UserJcrUtils.getUserProfile(session, username);
+ // new user
+ if (userProfile == null) {
+ String personPath = generateUserPath(peopleBasePath, username);
+ Node personBase;
+ if (session.itemExists(personPath))// duplicate user id
+ personBase = session.getNode(personPath).getParent()
+ .addNode(JcrUtils.lastPathElement(personPath));
+ else
+ personBase = JcrUtils.mkdirs(session, personPath);
+ userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE);
+ userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+ userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
+ userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED,
+ true);
+ userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED,
+ true);
+ userProfile.setProperty(
+ ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true);
+ session.save();
+
+ JcrUtils.clearAccessControList(session, userProfile.getPath(),
+ username);
+ JcrUtils.addPrivilege(session, userProfile.getPath(), username,
+ Privilege.JCR_READ);
+ }
+
+ // Remote roles
+ if (roles != null) {
+ writeRemoteRoles(userProfile, roles);
+ }
+ adminSession.save();
+ return userProfile;
+ } catch (RepositoryException e) {
+ JcrUtils.discardQuietly(session);
+ throw new ArgeoException("Cannot sync node security model for "
+ + username, e);
+ }
+ }
+
+ /** Generate path for a new user home */
+ private String generateUserPath(String base, String username) {
+ LdapName dn;
+ try {
+ dn = new LdapName(username);
+ } catch (InvalidNameException e) {
+ throw new ArgeoException("Invalid name " + username, e);
+ }
+ String userId = dn.getRdn(dn.size() - 1).getValue().toString();
+ int atIndex = userId.indexOf('@');
+ if (atIndex > 0) {
+ String domain = userId.substring(0, atIndex);
+ String name = userId.substring(atIndex + 1);
+ return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
+ + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
+ + name;
+ } else if (atIndex == 0 || atIndex == (userId.length() - 1)) {
+ throw new ArgeoException("Unsupported username " + userId);
+ } else {
+ return base + '/' + JcrUtils.firstCharsToPath(userId, 2) + '/'
+ + userId;
+ }
+ }
+
+ /** Write remote roles used by remote access in the home directory */
+ private void writeRemoteRoles(Node userHome, String[] roles)
+ throws RepositoryException {
+ boolean writeRoles = false;
+ if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+ Value[] remoteRoles = userHome.getProperty(
+ ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+ if (remoteRoles.length != roles.length)
+ writeRoles = true;
+ else
+ for (int i = 0; i < remoteRoles.length; i++)
+ if (!remoteRoles[i].getString().equals(roles[i]))
+ writeRoles = true;
+ } else
+ writeRoles = true;
+
+ if (writeRoles) {
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkout(userHome.getPath());
+ userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roles);
+ JcrUtils.updateLastModified(userHome);
+ userHome.getSession().save();
+ userHome.getSession().getWorkspace().getVersionManager()
+ .checkin(userHome.getPath());
+ if (log.isDebugEnabled())
+ log.debug("Wrote remote roles " + roles + " for "
+ + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
+ }
+
+ }
+
}
USER {
- org.argeo.cms.internal.auth.UserAdminLoginModule requisite;
-};
-
-OLD_USER {
- org.argeo.cms.internal.auth.EndUserLoginModule requisite;
- org.springframework.security.authentication.jaas.SecurityContextLoginModule requisite;
+ org.argeo.cms.auth.NodeContextLoginModule requisite;
+ org.argeo.cms.auth.UserAdminLoginModule requisite;
+ org.argeo.cms.auth.NodeUserLoginModule requisite;
};
ANONYMOUS {
- org.argeo.cms.internal.auth.UserAdminLoginModule requisite anonymous=true;
-};
-
-OLD_ANONYMOUS {
- org.argeo.cms.internal.auth.AnonymousLoginModule requisite;
- org.springframework.security.authentication.jaas.SecurityContextLoginModule requisite;
+ org.argeo.cms.auth.NodeContextLoginModule requisite;
+ org.argeo.cms.auth.UserAdminLoginModule requisite anonymous=true;
+ org.argeo.cms.auth.NodeUserLoginModule requisite;
};
SYSTEM {
org.argeo.cms.internal.auth.KernelLoginModule requisite;
};
-OLD_SYSTEM {
- org.argeo.cms.internal.auth.SystemLoginModule requisite;
- org.springframework.security.authentication.jaas.SecurityContextLoginModule requisite;
-};
-
KEYRING {
org.argeo.security.crypto.KeyringLoginModule required;
};
Jackrabbit {
org.argeo.security.jackrabbit.SystemJackrabbitLoginModule requisite;
};
-
package org.argeo.cms.util;
-import static org.argeo.cms.KernelHeader.ACCESS_CONTROL_CONTEXT;
-import static org.argeo.cms.KernelHeader.LOGIN_CONTEXT_ANONYMOUS;
-import static org.argeo.cms.KernelHeader.LOGIN_CONTEXT_USER;
+import static org.argeo.cms.auth.AuthConstants.ACCESS_CONTROL_CONTEXT;
+import static org.argeo.cms.auth.AuthConstants.LOGIN_CONTEXT_ANONYMOUS;
+import static org.argeo.cms.auth.AuthConstants.LOGIN_CONTEXT_USER;
import java.io.IOException;
import java.security.AccessController;
import org.argeo.cms.CmsException;
import org.argeo.cms.CmsMsg;
-import org.argeo.cms.CmsView;
import org.argeo.cms.CmsStyles;
-import org.argeo.cms.KernelHeader;
-import org.argeo.cms.auth.ArgeoLoginContext;
+import org.argeo.cms.CmsView;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.security.SecurityUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
super(source.getDisplay(), SWT.NO_TRIM | SWT.BORDER | SWT.ON_TOP);
setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU);
- // Authentication authentication = SecurityContextHolder.getContext()
- // .getAuthentication();
- // if (authentication == null)
- // throw new CmsException("No authentication available");
-
- String username = CurrentUserUtils.getUsername();
- if (username.equalsIgnoreCase(KernelHeader.ROLE_ANONYMOUS)) {
+ String username = SecurityUtils.getUsername(CmsUtils.getCmsView().getSubject());
+ if (username.equalsIgnoreCase(AuthConstants.ROLE_ANONYMOUS)) {
username = null;
anonymousUi();
} else {
c.setLayout(new GridLayout());
c.setLayoutData(CmsUtils.fillAll());
- // String username = SecurityContextHolder.getContext()
- // .getAuthentication().getName();
- //
- // Label l = new Label(c, SWT.NONE);
- // l.setData(RWT.CUSTOM_VARIANT, CMS_USER_MENU_ITEM);
- // l.setData(RWT.MARKUP_ENABLED, true);
- // l.setLayoutData(CmsUtils.fillWidth());
- // l.setText("<b>" + username + "</b>");
-
specificUserUi(c);
Label l = new Label(c, SWT.NONE);
});
}
- // protected String getUsername() {
- // // String username = SecurityContextHolder.getContext()
- // // .getAuthentication().getName();
- // return CurrentUserUtils.getUsername();
- // }
-
/** To be overridden */
protected void specificUserUi(Composite parent) {
}
protected void login() {
- CmsView cmsSession = (CmsView) getDisplay().getData(
- CmsView.KEY);
+ CmsView cmsSession = (CmsView) getDisplay().getData(CmsView.KEY);
Subject subject = cmsSession.getSubject();
try {
//
// LOGIN
//
- new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).logout();
- LoginContext loginContext = new ArgeoLoginContext(
- LOGIN_CONTEXT_USER, subject, this);
+ new LoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).logout();
+ LoginContext loginContext = new LoginContext(LOGIN_CONTEXT_USER,
+ subject, this);
loginContext.login();
// save context in session
});
} catch (LoginException e1) {
try {
- new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
+ new LoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
} catch (LoginException e) {
throw new CmsException("Cannot authenticate anonymous", e1);
}
}
protected void logout() {
- final CmsView cmsSession = (CmsView) getDisplay().getData(
- CmsView.KEY);
+ final CmsView cmsSession = (CmsView) getDisplay().getData(CmsView.KEY);
Subject subject = cmsSession.getSubject();
try {
//
// LOGOUT
//
- new ArgeoLoginContext(LOGIN_CONTEXT_USER, subject).logout();
- new ArgeoLoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
+ new LoginContext(LOGIN_CONTEXT_USER, subject).logout();
+ new LoginContext(LOGIN_CONTEXT_ANONYMOUS, subject).login();
HttpServletRequest httpRequest = RWT.getRequest();
HttpSession httpSession = httpRequest.getSession();
import org.argeo.cms.CmsMsg;
import org.argeo.cms.CmsStyles;
-import org.argeo.cms.KernelHeader;
+import org.argeo.cms.auth.AuthConstants;
+import org.argeo.security.SecurityUtils;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
@Override
public Control createUi(Composite parent, Node context) {
- // String username = SecurityContextHolder.getContext()
- // .getAuthentication().getName();
- String username = CurrentUserUtils.getUsername();
- if (username.equalsIgnoreCase(KernelHeader.ROLE_ANONYMOUS))
+ String username = SecurityUtils.getUsername(CmsUtils.getCmsView()
+ .getSubject());
+ if (username.equalsIgnoreCase(AuthConstants.ROLE_ANONYMOUS))
setLabel(CmsMsg.login.lead());
- else
- setLabel(username);
+ else {
+ setLabel(SecurityUtils.getDisplayName(CmsUtils.getCmsView()
+ .getSubject()));
+ }
Label link = (Label) ((Composite) super.createUi(parent, context))
.getChildren()[0];
link.addMouseListener(new UserMenuLinkController());
char[] pwd = password.getText().toCharArray();
SimpleCredentials sc = new SimpleCredentials(
username.getText(), pwd);
- session = repository.login(sc);
+ session = repository.login(sc, "main");
MessageDialog.openInformation(getParentShell(), "Success",
"Connection to '" + uri.getText() + "' successful");
}
public void login() {
try {
- defaultSession = repositoryLogin(null);
+ defaultSession = repositoryLogin("main");
String[] wkpNames = defaultSession.getWorkspace()
.getAccessibleWorkspaceNames();
for (String wkpName : wkpNames) {
+++ /dev/null
-package org.argeo.osgi.auth;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.spi.LoginModule;
-
-import org.osgi.framework.BundleContext;
-
-/** Allows a {@link LoginModule} to as for a {@link BundleContext} */
-public class BundleContextCallback implements Callback {
- private BundleContext bundleContext;
-
- public BundleContext getBundleContext() {
- return bundleContext;
- }
-
- public void setBundleContext(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
-}
+++ /dev/null
-package org.argeo.osgi.auth;
-
-import java.io.IOException;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-
-import org.osgi.framework.BundleContext;
-
-public class BundleContextCallbackHandler implements CallbackHandler {
- private final BundleContext bundleContext;
-
- public BundleContextCallbackHandler(BundleContext bundleContext) {
- this.bundleContext = bundleContext;
- }
-
- @Override
- public void handle(Callback[] callbacks) throws IOException,
- UnsupportedCallbackException {
- for (Callback callback : callbacks) {
- if (!(callback instanceof BundleContextCallback))
- throw new UnsupportedCallbackException(callback);
- ((BundleContextCallback) callback).setBundleContext(bundleContext);
- }
-
- }
-
-}
import javax.security.auth.x500.X500Principal;
import org.argeo.ArgeoException;
+import org.osgi.service.useradmin.Authorization;
/** Static utilities */
public final class SecurityUtils {
* anonymous
*/
public static String getCurrentThreadUsername() {
- return getUsername();
- }
-
- public final static String getUsername() {
Subject subject = Subject.getSubject(AccessController.getContext());
if (subject == null)
return null;
+ return getUsername(subject);
+ }
+
+ public final static String getUsername(Subject subject) {
+ // Subject subject = Subject.getSubject(AccessController.getContext());
+ // if (subject == null)
+ // return null;
if (subject.getPrincipals(X500Principal.class).size() != 1)
return null;
Principal principal = subject.getPrincipals(X500Principal.class)
}
+ public final static String getDisplayName(Subject subject) {
+ return getAuthorization(subject).toString();
+ }
+
+ public final static Authorization getAuthorization(Subject subject) {
+ return subject.getPrivateCredentials(Authorization.class).iterator()
+ .next();
+ }
+
public final static Set<String> roles() {
Set<String> roles = Collections.synchronizedSet(new HashSet<String>());
Subject subject = Subject.getSubject(AccessController.getContext());
Import-Package: org.argeo.eclipse.spring,\
org.argeo.eclipse.ui.specific,\
org.argeo.cms,\
+org.argeo.cms.auth,\
org.argeo.security.ui,\
*
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.ArgeoException;
-import org.argeo.cms.KernelHeader;
-import org.argeo.cms.auth.ArgeoLoginContext;
+import org.argeo.cms.auth.AuthConstants;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.application.EntryPoint;
import org.eclipse.swt.widgets.Display;
final LoginContext loginContext;
try {
- loginContext = new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_ANONYMOUS, subject);
+ loginContext = new LoginContext(AuthConstants.LOGIN_CONTEXT_ANONYMOUS,
+ subject);
loginContext.login();
} catch (LoginException e1) {
throw new ArgeoException("Cannot initialize login context", e1);
*/
package org.argeo.security.ui.rap;
-import static org.argeo.cms.KernelHeader.ACCESS_CONTROL_CONTEXT;
+import static org.argeo.cms.auth.AuthConstants.ACCESS_CONTROL_CONTEXT;
import java.security.AccessControlContext;
import java.security.AccessController;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.ArgeoException;
-import org.argeo.cms.KernelHeader;
-import org.argeo.cms.auth.ArgeoLoginContext;
+import org.argeo.cms.auth.AuthConstants;
import org.argeo.cms.widgets.auth.DefaultLoginDialog;
import org.argeo.eclipse.ui.dialogs.ErrorFeedback;
import org.argeo.util.LocaleUtils;
HttpServletRequest httpRequest = RWT.getRequest();
final HttpSession httpSession = httpRequest.getSession();
AccessControlContext acc = (AccessControlContext) httpSession
- .getAttribute(KernelHeader.ACCESS_CONTROL_CONTEXT);
+ .getAttribute(AuthConstants.ACCESS_CONTROL_CONTEXT);
final Subject subject;
if (acc != null
try {
CallbackHandler callbackHandler = new DefaultLoginDialog(
display.getActiveShell());
- loginContext = new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_USER, subject,
+ loginContext = new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_USER, subject,
callbackHandler);
} catch (LoginException e1) {
throw new ArgeoException("Cannot initialize login context", e1);
if (log.isTraceEnabled())
log.trace("Display disposed");
try {
- LoginContext loginContext = new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_USER, subject);
+ LoginContext loginContext = new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_USER, subject);
loginContext.logout();
} catch (LoginException e) {
log.error("Error when logging out", e);
private void fullLogout(Subject subject, String username) {
try {
- LoginContext loginContext = new ArgeoLoginContext(
- KernelHeader.LOGIN_CONTEXT_USER, subject);
+ LoginContext loginContext = new LoginContext(
+ AuthConstants.LOGIN_CONTEXT_USER, subject);
loginContext.logout();
HttpServletRequest httpRequest = RWT.getRequest();
HttpSession httpSession = httpRequest.getSession();
public class SecureRapActivator implements BundleActivator {
public final static String ID = "org.argeo.security.ui.rap";
- private BundleContext bundleContext;
- private static SecureRapActivator activator = null;
+ private static BundleContext bundleContext;
- public void start(BundleContext bundleContext) throws Exception {
- activator = this;
- this.bundleContext = bundleContext;
+ public void start(BundleContext bc) throws Exception {
+ bundleContext = bc;
}
public void stop(BundleContext context) throws Exception {
bundleContext = null;
- activator = null;
}
- public BundleContext getBundleContext() {
+ public static BundleContext getBundleContext() {
return bundleContext;
}
-
- public static SecureRapActivator getActivator() {
- return activator;
- }
}
*/
public class CurrentUser {
public final static String getUsername() {
- return SecurityUtils.getUsername();
+ return SecurityUtils.getCurrentThreadUsername();
}
public final static Set<String> roles() {