+++ /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.node.security.DataAdminPrincipal;
-
-/** Logs a system process as data admin */
-public class DataAdminLoginModule implements LoginModule {
- private Subject subject;
-
- @Override
- public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
- Map<String, ?> options) {
- this.subject = subject;
- }
-
- @Override
- public boolean login() throws LoginException {
- // TODO check permission?
- return true;
- }
-
- @Override
- public boolean commit() throws LoginException {
- subject.getPrincipals().add(new DataAdminPrincipal());
- return true;
- }
-
- @Override
- public boolean abort() throws LoginException {
- return true;
- }
-
- @Override
- public boolean logout() throws LoginException {
- subject.getPrincipals().removeAll(subject.getPrincipals(DataAdminPrincipal.class));
- return true;
- }
-}
import org.argeo.cms.internal.kernel.Activator;
import org.argeo.ident.IdentClient;
+/** Use an ident service to identify. */
public class IdentLoginModule implements LoginModule {
private final static Log log = LogFactory.getLog(IdentLoginModule.class);
- private Subject subject = null;
private CallbackHandler callbackHandler = null;
private Map<String, Object> sharedState = null;
+ @SuppressWarnings("unchecked")
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
Map<String, ?> options) {
- this.subject = subject;
this.callbackHandler = callbackHandler;
this.sharedState = (Map<String, Object>) sharedState;
}
}
@Override
- protected void processNewSession(Session session) {
+ protected void processNewSession(Session session, String workspaceName) {
String username = session.getUserID();
if (username == null || username.toString().equals(""))
return;
return;
Session adminSession = KernelUtils.openAdminSession(getRepository(), session.getWorkspace().getName());
try {
- syncJcr(adminSession, username);
+ syncJcr(adminSession, username, workspaceName);
checkedUsers.add(username);
} finally {
JcrUtils.logoutQuietly(adminSession);
}
}
- private void syncJcr(Session session, String username) {
+ protected synchronized void syncJcr(Session adminSession, String username, String workspaceName) {
+ // only in the default workspace
+ if (workspaceName != null)
+ return;
+ // skip system users
+ if (username.endsWith(NodeConstants.ROLES_BASEDN))
+ return;
+
try {
- Node userHome = NodeUtils.getUserHome(session, username);
+ Node userHome = NodeUtils.getUserHome(adminSession, username);
if (userHome == null) {
String homePath = generateUserPath(username);
- if (session.itemExists(homePath))// duplicate user id
- userHome = session.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath));
+ if (adminSession.itemExists(homePath))// duplicate user id
+ userHome = adminSession.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath));
else
- userHome = JcrUtils.mkdirs(session, homePath);
+ userHome = JcrUtils.mkdirs(adminSession, homePath);
// userHome = JcrUtils.mkfolders(session, homePath);
userHome.addMixin(NodeTypes.NODE_USER_HOME);
userHome.addMixin(NodeType.MIX_CREATED);
userHome.setProperty(NodeNames.LDAP_UID, username);
- session.save();
+ adminSession.save();
- JcrUtils.clearAccessControList(session, homePath, username);
- JcrUtils.addPrivilege(session, homePath, username, Privilege.JCR_ALL);
+ JcrUtils.clearAccessControList(adminSession, homePath, username);
+ JcrUtils.addPrivilege(adminSession, homePath, username, Privilege.JCR_ALL);
}
- if (session.hasPendingChanges())
- session.save();
+ if (adminSession.hasPendingChanges())
+ adminSession.save();
} catch (RepositoryException e) {
- JcrUtils.discardQuietly(session);
+ JcrUtils.discardQuietly(adminSession);
throw new CmsException("Cannot sync node security model for " + username, e);
}
}
import org.osgi.service.useradmin.Authorization;
+@Deprecated
class NodeAuthorization implements Authorization {
private final String name;
private final String displayName;
import org.argeo.cms.CmsException;
import org.argeo.cms.internal.http.CmsSessionProvider;
import org.argeo.cms.internal.http.DataHttpContext;
-import org.argeo.cms.internal.http.HtmlServlet;
import org.argeo.cms.internal.http.HttpUtils;
import org.argeo.cms.internal.http.LinkServlet;
import org.argeo.cms.internal.http.PrivateHttpContext;
};
DATA_ADMIN {
- org.argeo.cms.auth.DataAdminLoginModule requisite;
+ org.argeo.node.DataAdminLoginModule requisite;
};
NODE {
keyTab="${osgi.instance.area}node/krb5.keytab"
useKeyTab=true
storeKey=true;
- org.argeo.cms.auth.DataAdminLoginModule requisite;
+ org.argeo.node.DataAdminLoginModule requisite;
};
KEYRING {
};
DATA_ADMIN {
- org.argeo.cms.auth.DataAdminLoginModule requisite;
+ org.argeo.node.DataAdminLoginModule requisite;
};
NODE {
- org.argeo.cms.auth.DataAdminLoginModule requisite;
+ org.argeo.node.DataAdminLoginModule requisite;
};
KEYRING {
else
throw e;
}
- processNewSession(session);
+ processNewSession(session, workspaceName);
return session;
}
}
/** Called after a session has been created, does nothing by default. */
- protected void processNewSession(Session session) {
+ protected void processNewSession(Session session, String workspaceName) {
}
/** Wraps access to the repository, making sure it is available. */
}
/**
- * Logs in to the default workspace, creates the required workspace, logs
- * out, logs in to the required workspace.
+ * Logs in to the default workspace, creates the required workspace, logs out,
+ * logs in to the required workspace.
*/
protected Session createWorkspaceAndLogsIn(Credentials credentials, String workspaceName)
throws RepositoryException {
--- /dev/null
+package org.argeo.node;
+
+import java.util.Map;
+
+import javax.security.auth.AuthPermission;
+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.node.security.DataAdminPrincipal;
+
+/**
+ * Log-in a system process as data admin. Protection is via
+ * {@link AuthPermission} on this login module, so if it can be accessed it will
+ * always succeed.
+ */
+public class DataAdminLoginModule implements LoginModule {
+ private Subject subject;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+ Map<String, ?> options) {
+ this.subject = subject;
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ subject.getPrincipals().add(new DataAdminPrincipal());
+ return true;
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ subject.getPrincipals().removeAll(subject.getPrincipals(DataAdminPrincipal.class));
+ return true;
+ }
+}
*/
package org.argeo.node;
+import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import javax.jcr.query.qom.QueryObjectModelFactory;
import javax.jcr.query.qom.Selector;
import javax.jcr.query.qom.StaticOperand;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
/** Utilities related to Argeo model in JCR */
public class NodeUtils {
/**
* Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#CN} in order to simplify it and
- * protect against future API changes.
+ * {@link NodeConstants#CN} in order to simplify it and protect against future
+ * API changes.
*/
public static Repository getRepositoryByAlias(RepositoryFactory repositoryFactory, String alias) {
try {
/**
* Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#LABELED_URI} in order to simplify it and
- * protect against future API changes.
+ * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
+ * future API changes.
*/
public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri) {
return getRepositoryByUri(repositoryFactory, uri, null);
/**
* Wraps the call to the repository factory based on parameter
- * {@link NodeConstants#LABELED_URI} in order to simplify it and
- * protect against future API changes.
+ * {@link NodeConstants#LABELED_URI} in order to simplify it and protect against
+ * future API changes.
*/
public static Repository getRepositoryByUri(RepositoryFactory repositoryFactory, String uri, String alias) {
try {
}
}
- private NodeUtils() {
- }
-
/**
* Returns the home node of the user or null if none was found.
*
- * @param session
- * the session to use in order to perform the search, this can be
- * a session with a different user ID than the one searched,
- * typically when a system or admin session is used.
- * @param username
- * the username of the user
+ * @param session the session to use in order to perform the search, this can
+ * be a session with a different user ID than the one searched,
+ * typically when a system or admin session is used.
+ * @param username the username of the user
*/
public static Node getUserHome(Session session, String username) {
try {
/**
* Returns the home node of the user or null if none was found.
*
- * @param session
- * the session to use in order to perform the search, this can be
- * a session with a different user ID than the one searched,
- * typically when a system or admin session is used.
- * @param cn
- * the name of the group
+ * @param session the session to use in order to perform the search, this can be
+ * a session with a different user ID than the one searched,
+ * typically when a system or admin session is used.
+ * @param cn the name of the group
*/
public static Node getGroupHome(Session session, String cn) {
try {
* Queries one single node.
*
* @return one single node or null if none was found
- * @throws ArgeoJcrException
- * if more than one node was found
+ * @throws ArgeoJcrException if more than one node was found
*/
private static Node querySingleNode(Query query) {
NodeIterator nodeIterator;
return getUserHome(session, userID);
}
+ /**
+ * Translate the path to this node into a path containing the name of the
+ * repository and the name of the workspace.
+ */
public static String getDataPath(String cn, Node node) throws RepositoryException {
assert node != null;
StringBuilder buf = new StringBuilder(NodeConstants.PATH_DATA);
return buf.append('/').append(cn).append('/').append(node.getSession().getWorkspace().getName())
.append(node.getPath()).toString();
}
+
+ /**
+ * Open a JCR session with full read/write rights on the data, as
+ * {@link NodeConstants#ROLE_USER_ADMIN}, using the
+ * {@link NodeConstants#LOGIN_CONTEXT_DATA_ADMIN} login context. For security
+ * hardened deployement, use {@link AuthPermission} on this login context.
+ */
+ public static Session openDataAdminSession(Repository repository, String workspaceName) {
+ ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
+ LoginContext loginContext;
+ try {
+ loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN);
+ loginContext.login();
+ } catch (LoginException e1) {
+ throw new RuntimeException("Could not login as data admin", e1);
+ } finally {
+ Thread.currentThread().setContextClassLoader(currentCl);
+ }
+ return Subject.doAs(loginContext.getSubject(), new PrivilegedAction<Session>() {
+
+ @Override
+ public Session run() {
+ try {
+ return repository.login(workspaceName);
+ } catch (RepositoryException e) {
+ throw new RuntimeException("Cannot open data admin session", e);
+ }
+ }
+
+ });
+ }
+
+ /** Singleton. */
+ private NodeUtils() {
+ }
+
}