import java.util.Locale;
-import javax.security.auth.login.CredentialNotFoundException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletRequest;
// try pre-auth
loginContext = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, loginShell);
loginContext.login();
- } catch (CredentialNotFoundException e) {
+ } catch (LoginException e) {
loginShell.createUi();
loginShell.open();
while (!loginShell.getShell().isDisposed()) {
- // try {
if (!display.readAndDispatch())
display.sleep();
- // } catch (Exception e1) {
- // try {
- // Thread.sleep(3000);
- // } catch (InterruptedException e2) {
- // // silent
- // }
- // ErrorFeedback.show("Login failed", e1);
- // return -1;
- // }
}
- } catch (LoginException e) {
- throw new CmsException("Cannot log in", e);
}
if (CurrentUser.getUsername() == null)
protected HttpServletRequest getRequest() {
return RWT.getRequest();
}
-
-
protected CmsLoginShell createCmsLoginShell() {
return new CmsLoginShell(this) {
throw new CmsException("Cannot log out", e);
}
}
-
-
-
- // @Override
- // public final Subject getSubject() {
- // return subject;
- // }
-
-// @Override
-// public void registerCallbackHandler(CallbackHandler callbackHandler) {
-// throw new UnsupportedOperationException();
-//
-// }
@Override
public void exception(Throwable e) {
public UxContext getUxContext() {
return uxContext;
}
-
-}
+}
\ No newline at end of file
import org.argeo.node.NodeConstants;
/** Public properties of the CMS Kernel */
-@Deprecated
interface AuthConstants {
+
+ static final String SHARED_STATE_USERNAME = "javax.security.auth.login.name";
+ static final String SHARED_STATE_PASSWORD = "javax.security.auth.login.password";
+
// LOGIN CONTEXTS
/**
* @deprecated Use {@link NodeConstants#LOGIN_CONTEXT_USER} instead
--- /dev/null
+package org.argeo.cms.auth;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.naming.ldap.LdapName;
+
+import org.osgi.service.useradmin.User;
+
+/**
+ * A special user type used during authentication in order to provide the
+ * credentials required for scoping the user admin.
+ */
+class AuthenticatingUser implements User {
+ private final String name;
+ private final Dictionary<String, Object> credentials;
+
+ public AuthenticatingUser(LdapName name) {
+ this.name = name.toString();
+ this.credentials = new Hashtable<>();
+ }
+
+ public AuthenticatingUser(String name, Dictionary<String, Object> credentials) {
+ this.name = name;
+ this.credentials = credentials;
+ }
+
+ public AuthenticatingUser(String name, char[] password) {
+ this.name = name;
+ credentials = new Hashtable<>();
+ credentials.put(AuthConstants.SHARED_STATE_USERNAME, name);
+ byte[] pwd = charsToBytes(password);
+ credentials.put(AuthConstants.SHARED_STATE_PASSWORD, pwd);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public int getType() {
+ return User.USER;
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Dictionary getProperties() {
+ throw new UnsupportedOperationException();
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public Dictionary getCredentials() {
+ return credentials;
+ }
+
+ @Override
+ public boolean hasCredential(String key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ static byte[] charsToBytes(char[] chars) {
+ CharBuffer charBuffer = CharBuffer.wrap(chars);
+ ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
+ byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit());
+ Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
+ Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
+ return bytes;
+ }
+
+ static char[] bytesToChars(byte[] bytes) {
+ ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ CharBuffer charBuffer = Charset.forName("UTF-8").decode(byteBuffer);
+ char[] chars = Arrays.copyOfRange(charBuffer.array(), charBuffer.position(), charBuffer.limit());
+ Arrays.fill(charBuffer.array(), '\u0000'); // clear sensitive data
+ Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
+ return chars;
+ }
+
+
+}
--- /dev/null
+package org.argeo.cms.auth;
+
+import java.security.PrivilegedAction;
+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.kerberos.KerberosPrincipal;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.argeo.cms.CmsException;
+import org.argeo.naming.LdapAttrs;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.useradmin.Authorization;
+import org.osgi.service.useradmin.UserAdmin;
+
+public class IpaLoginModule implements LoginModule {
+ private BundleContext bc;
+ private Subject subject;
+
+ @Override
+ public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
+ Map<String, ?> options) {
+ this.subject = subject;
+ try {
+ bc = FrameworkUtil.getBundle(IpaLoginModule.class).getBundleContext();
+ assert bc != null;
+ } catch (Exception e) {
+ throw new CmsException("Cannot initialize login module", e);
+ }
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ return true;
+ }
+
+ @Override
+ public boolean commit() throws LoginException {
+ UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
+ Authorization authorization = null;
+ Set<KerberosPrincipal> kerberosPrincipals = subject.getPrincipals(KerberosPrincipal.class);
+ if (kerberosPrincipals.isEmpty()) {
+ authorization = userAdmin.getAuthorization(null);
+ } else {
+ KerberosPrincipal kerberosPrincipal = kerberosPrincipals.iterator().next();
+ LdapName dn = kerberosToIpa(kerberosPrincipal);
+ AuthenticatingUser authenticatingUser = new AuthenticatingUser(dn);
+ authorization = Subject.doAs(subject, new PrivilegedAction<Authorization>() {
+
+ @Override
+ public Authorization run() {
+ Authorization authorization = userAdmin.getAuthorization(authenticatingUser);
+ return authorization;
+ }
+
+ });
+ }
+ if (authorization == null)
+ return false;
+ CmsAuthUtils.addAuthentication(subject, authorization);
+ return true;
+ }
+
+ private LdapName kerberosToIpa(KerberosPrincipal kerberosPrincipal) {
+ String[] kname = kerberosPrincipal.getName().split("@");
+ String username = kname[0];
+ String[] dcs = kname[1].split("\\.");
+ StringBuilder sb = new StringBuilder();
+ for (String dc : dcs) {
+ sb.append(',').append(LdapAttrs.dc.name()).append('=').append(dc.toLowerCase());
+ }
+ String dn = LdapAttrs.uid + "=" + username + ",cn=users,cn=accounts" + sb;
+ try {
+ return new LdapName(dn);
+ } catch (InvalidNameException e) {
+ throw new CmsException("Badly formatted name for " + kerberosPrincipal + ": " + dn);
+ }
+ }
+
+ @Override
+ public boolean abort() throws LoginException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean logout() throws LoginException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+}
if (sharedState.containsKey(CmsAuthUtils.SHARED_STATE_NAME)
&& sharedState.containsKey(CmsAuthUtils.SHARED_STATE_PWD)) {
username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
- password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
+ password = (char[]) sharedState.get(CmsAuthUtils.SHARED_STATE_PWD);
// TODO locale?
+ AuthenticatingUser authenticatingUser = new AuthenticatingUser(username, password);
+ authorization = userAdmin.getAuthorization(authenticatingUser);
} else {
// ask for username and password
password = passwordCallback.getPassword();
else
throw new CredentialNotFoundException("No credentials provided");
+ // FIXME move Argeo specific convention from user admin to here
+ User user = userAdmin.getUser(null, username);
+ if (user == null)
+ throw new FailedLoginException("Invalid credentials");
+ if (!user.hasCredential(null, password))
+ throw new FailedLoginException("Invalid credentials");
+ // return false;
+
+ // Log and monitor new login
+ // if (log.isDebugEnabled())
+ // log.debug("Logged in to CMS with username [" + username +
+ // "]");
+
+ authorization = userAdmin.getAuthorization(user);
+ assert authorization != null;
}
- // FIXME move Argeo specific convention from user admin to here
- User user = userAdmin.getUser(null, username);
- if (user == null)
- throw new FailedLoginException("Invalid credentials");
- if (!user.hasCredential(null, password))
- throw new FailedLoginException("Invalid credentials");
- // return false;
-
- // Log and monitor new login
- // if (log.isDebugEnabled())
- // log.debug("Logged in to CMS with username [" + username +
- // "]");
-
- authorization = userAdmin.getAuthorization(user);
- assert authorization != null;
-
// }
// if
// (!sharedState.containsKey(CmsAuthUtils.SHARED_STATE_AUTHORIZATION))
import java.util.List;
import java.util.Locale;
+import javax.security.auth.login.Configuration;
+
import org.argeo.cms.CmsException;
import org.argeo.node.ArgeoLogger;
import org.argeo.node.NodeConstants;
this.logReaderService = getService(LogReaderService.class);
// this.configurationAdmin = getService(ConfigurationAdmin.class);
- initSecurity();// must be first
- initArgeoLogger();
try {
+ initSecurity();// must be first
+ initArgeoLogger();
initNode();
} catch (Exception e) {
e.printStackTrace();
}
private void initSecurity() {
- 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);
+// URL url = getClass().getClassLoader().getResource(KernelConstants.JAAS_CONFIG_IPA);
+ System.setProperty("java.security.auth.login.config", url.toExternalForm());
+ Configuration.getConfiguration();
}
private void initArgeoLogger() {
Files.write(stateUuidPath, stateUuid.getBytes());
}
nodeState = new CmsState(stateUuid);
- Dictionary<String, Object> regProps = LangUtils.dico(
- Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID);
+ Dictionary<String, Object> regProps = LangUtils.dico(Constants.SERVICE_PID, NodeConstants.NODE_STATE_PID);
regProps.put(NodeConstants.CN, stateUuid);
bc.registerService(NodeState.class, nodeState, regProps);
// Security
// String DEFAULT_SECURITY_KEY = "argeo";
String JAAS_CONFIG = "/org/argeo/cms/internal/kernel/jaas.cfg";
+ String JAAS_CONFIG_IPA = "/org/argeo/cms/internal/kernel/jaas-ipa.cfg";
// String LOGIN_CONTEXT_KERNEL = "KERNEL";
// String LOGIN_CONTEXT_HARDENED_KERNEL = "HARDENED_KERNEL";
}
// Security
- @Deprecated
static Subject anonymousLogin() {
Subject subject = new Subject();
LoginContext lc;
}
private String msg(LogEntry status) {
- StringBuilder sb = new StringBuilder(status.getMessage());
+ StringBuilder sb = new StringBuilder();
+ sb.append(status.getMessage());
ServiceReference<?> sr = status.getServiceReference();
if (sr != null) {
sb.append(' ');
--- /dev/null
+USER {
+ com.sun.security.auth.module.Krb5LoginModule required clearPass=true;
+ org.argeo.cms.auth.IpaLoginModule requisite;
+};
+
+ANONYMOUS {
+ org.argeo.cms.auth.UserAdminLoginModule requisite anonymous=true;
+};
+
+DATA_ADMIN {
+ org.argeo.cms.auth.DataAdminLoginModule requisite;
+};
+
+KEYRING {
+ org.argeo.cms.auth.KeyringLoginModule required;
+};
+
+Jackrabbit {
+ org.argeo.security.jackrabbit.SystemJackrabbitLoginModule requisite;
+};
private final static Log log = LogFactory.getLog(AbstractUserDirectory.class);
private final Hashtable<String, Object> properties;
- private final LdapName baseDn;
+ private final LdapName baseDn, userBaseDn, groupBaseDn;
private final String userObjectClass, userBase, groupObjectClass, groupBase;
private final boolean readOnly;
throw new UserDirectoryException("Badly formatted URI " + uriStr, e);
}
+ userObjectClass = UserAdminConf.userObjectClass.getValue(properties);
+ userBase = UserAdminConf.userBase.getValue(properties);
+ groupObjectClass = UserAdminConf.groupObjectClass.getValue(properties);
+ groupBase = UserAdminConf.groupBase.getValue(properties);
try {
baseDn = new LdapName(UserAdminConf.baseDn.getValue(properties));
+ userBaseDn = new LdapName(userBase + "," + baseDn);
+ groupBaseDn = new LdapName(groupBase + "," + baseDn);
} catch (InvalidNameException e) {
throw new UserDirectoryException("Badly formated base DN " + UserAdminConf.baseDn.getValue(properties), e);
}
properties.put(UserAdminConf.readOnly.name(), Boolean.toString(readOnly));
} else
readOnly = new Boolean(readOnlyStr);
-
- userObjectClass = UserAdminConf.userObjectClass.getValue(properties);
- userBase = UserAdminConf.userBase.getValue(properties);
- groupObjectClass = UserAdminConf.groupObjectClass.getValue(properties);
- groupBase = UserAdminConf.groupBase.getValue(properties);
}
/** Returns the groups this user is a direct member of. */
return externalRoles;
}
- public LdapName getBaseDn() {
- // always clone so that the property is not modified by reference
- return (LdapName) baseDn.clone();
+ protected int roleType(LdapName dn) {
+ if (dn.startsWith(groupBaseDn))
+ return Role.GROUP;
+ else if (dn.startsWith(userBaseDn))
+ return Role.USER;
+ else
+ return Role.GROUP;
}
/** dn can be null, in that case a default should be returned. */
return groupBase;
}
+ public LdapName getBaseDn() {
+ return (LdapName) baseDn.clone();
+ }
+
public Dictionary<String, Object> getProperties() {
return properties;
}
import org.apache.commons.logging.LogFactory;
import org.argeo.naming.LdapAttrs;
import org.osgi.framework.Filter;
+import org.osgi.service.useradmin.Role;
import org.osgi.service.useradmin.User;
/**
// StartTlsResponse tls = (StartTlsResponse) ctx
// .extendedOperation(new StartTlsRequest());
// tls.negotiate();
- initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
+ Object securityAuthentication = properties.get(Context.SECURITY_AUTHENTICATION);
+ if (securityAuthentication != null)
+ initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, securityAuthentication);
+ else
+ initialLdapContext.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");
Object principal = properties.get(Context.SECURITY_PRINCIPAL);
if (principal != null) {
initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, principal.toString());
}
}
- // initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL,
- // "uid=admin,ou=system");
- // initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS,
- // "secret");
} catch (Exception e) {
throw new UserDirectoryException("Cannot connect to LDAP", e);
}
log.error("Cannot destroy LDAP user admin", e);
}
}
-
-
@SuppressWarnings("unchecked")
@Override
protected AbstractUserDirectory scope(User user) {
Dictionary<String, Object> credentials = user.getCredentials();
// FIXME use arrays
- Object usernameObj = credentials.get(SHARED_STATE_USERNAME);
- Object passwordObj = credentials.get(SHARED_STATE_PASSWORD);
+ String username = (String) credentials.get(SHARED_STATE_USERNAME);
+ if (username == null)
+ username = user.getName();
+ // byte[] pwd = (byte[]) credentials.get(SHARED_STATE_PASSWORD);
+ // char[] password = DigestUtils.bytesToChars(pwd);
Dictionary<String, Object> properties = cloneProperties();
- properties.put(Context.SECURITY_PRINCIPAL, usernameObj.toString());
- properties.put(Context.SECURITY_CREDENTIALS, passwordObj.toString());
+ properties.put(Context.SECURITY_PRINCIPAL, username.toString());
+ // properties.put(Context.SECURITY_CREDENTIALS, password);
+ properties.put(Context.SECURITY_AUTHENTICATION, "GSSAPI");
return new LdapUserAdmin(properties);
}
Attributes attrs = getLdapContext().getAttributes(name);
if (attrs.size() == 0)
return null;
+ int roleType = roleType(name);
LdifUser res;
- if (attrs.get(objectClass.name()).contains(getGroupObjectClass()))
+ if (roleType == Role.GROUP)
res = new LdifGroup(this, name, attrs);
- else if (attrs.get(objectClass.name()).contains(getUserObjectClass()))
+ else if (roleType == Role.USER)
res = new LdifUser(this, name, attrs);
else
throw new UserDirectoryException("Unsupported LDAP type for " + name);
return res;
} catch (NamingException e) {
+ log.error("Cannot get role: "+e.getMessage());
return null;
}
}
if (scheme != null)
if (scheme.equals("ldap") || scheme.equals("ldaps")) {
// TODO additional checks
- String[] userInfo = u.getUserInfo().split(":");
- principal = userInfo.length > 0 ? userInfo[0] : null;
- credentials = userInfo.length > 1 ? userInfo[1] : null;
+ if (u.getUserInfo() != null) {
+ String[] userInfo = u.getUserInfo().split(":");
+ principal = userInfo.length > 0 ? userInfo[0] : null;
+ credentials = userInfo.length > 1 ? userInfo[1] : null;
+ }
} else if (scheme.equals("file")) {
} else
throw new UserDirectoryException("Unsupported scheme " + scheme);