--- /dev/null
+argeo.osgi.start.2.node=\
+org.eclipse.equinox.http.servlet,\
+org.eclipse.equinox.http.jetty,\
+org.eclipse.equinox.metatype,\
+org.eclipse.equinox.cm,\
+org.eclipse.rap.rwt.osgi
+
+argeo.osgi.start.3.node=\
+org.argeo.cms
+
+argeo.osgi.start.4.apps=\
+org.eclipse.gemini.blueprint.extender
+
+argeo.osgi.start.4.workbench=\
+org.eclipse.equinox.http.registry,\
+
+java.security.manager=
+java.security.policy=file:../../all.policy
+
+argeo.node.repo.type=h2
+
+argeo.node.useradmin.uris=os:///
+
+# HTTP
+org.osgi.service.http.port=7070
+
+# Logging
+log4j.configuration=file:../../log4j.properties
+
+# DON'T CHANGE BELOW
+org.eclipse.rap.workbenchAutostart=false
+org.eclipse.equinox.http.jetty.autostart=false
+org.osgi.framework.bootdelegation=com.sun.jndi.ldap,\
+com.sun.jndi.ldap.sasl,\
+com.sun.security.jgss,\
+com.sun.jndi.dns,\
+com.sun.nio.file,\
+com.sun.nio.sctp
import org.argeo.cms.internal.auth.CmsSessionImpl;
import org.argeo.cms.internal.auth.ImpliedByPrincipal;
import org.argeo.cms.internal.http.WebCmsSessionImpl;
+import org.argeo.cms.internal.kernel.Activator;
import org.argeo.node.NodeConstants;
import org.argeo.node.security.AnonymousPrincipal;
import org.argeo.node.security.DataAdminPrincipal;
// required for display name:
subject.getPrivateCredentials().add(authorization);
+ if (Activator.isSingleUser()) {
+ subject.getPrincipals().add(new DataAdminPrincipal());
+ }
+
Set<Principal> principals = subject.getPrincipals();
try {
String authName = authorization.getName();
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsException;
+import org.argeo.cms.internal.kernel.Activator;
import org.argeo.naming.LdapAttrs;
import org.argeo.osgi.useradmin.AuthenticatingUser;
import org.argeo.osgi.useradmin.IpaUtils;
+import org.argeo.osgi.useradmin.OsUserUtils;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.useradmin.Authorization;
private Authorization bindAuthorization = null;
+ private boolean singleUser = Activator.isSingleUser();
+
@SuppressWarnings("unchecked")
@Override
public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
username = (String) sharedState.get(CmsAuthUtils.SHARED_STATE_NAME);
certificateChain = (X509Certificate[]) sharedState.get(CmsAuthUtils.SHARED_STATE_CERTIFICATE_CHAIN);
password = null;
+ } else if (singleUser) {
+ username = OsUserUtils.getOsUsername();
+ password = null;
} else {
+
// ask for username and password
NameCallback nameCallback = new NameCallback("User");
PasswordCallback passwordCallback = new PasswordCallback("Password", false);
}
} else if (certificateChain != null) {
// TODO check CRLs/OSCP validity?
- // NB: authorization in commit() will work only if an LDAP connection password is provided
- }else {
+ // NB: authorization in commit() will work only if an LDAP connection password
+ // is provided
+ } else if (singleUser) {
+ // TODO verify IP address?
+ } else {
throw new CredentialNotFoundException("No credentials provided");
}
@Override
public boolean commit() throws LoginException {
+ if (singleUser) {
+ OsUserUtils.loginAsSystemUser(subject);
+ }
UserAdmin userAdmin = bc.getService(bc.getServiceReference(UserAdmin.class));
Authorization authorization;
if (callbackHandler == null) {// anonymous
}
public static GSSCredential getAcceptorCredentials() {
+ return getNodeUserAdmin().getAcceptorCredentials();
+ }
+
+ public static boolean isSingleUser() {
+ return getNodeUserAdmin().isSingleUser();
+ }
+
+ private static NodeUserAdmin getNodeUserAdmin() {
ServiceReference<UserAdmin> sr = instance.bc.getServiceReference(UserAdmin.class);
NodeUserAdmin userAdmin = (NodeUserAdmin) instance.bc.getService(sr);
- return userAdmin.getAcceptorCredentials();
+ return userAdmin;
+
}
// static CmsSecurity getCmsSecurity() {
u = new URI(uri);
} else
throw new CmsException("Cannot interpret " + uri + " as an uri");
- } else if (u.getScheme().equals("file")) {
+ } else if (u.getScheme().equals(UserAdminConf.SCHEME_FILE)) {
u = new File(u).getCanonicalFile().toURI();
}
} catch (Exception e) {
import org.argeo.osgi.useradmin.AggregatingUserAdmin;
import org.argeo.osgi.useradmin.LdapUserAdmin;
import org.argeo.osgi.useradmin.LdifUserAdmin;
+import org.argeo.osgi.useradmin.OsUserDirectory;
import org.argeo.osgi.useradmin.UserAdminConf;
import org.argeo.osgi.useradmin.UserDirectory;
import org.ietf.jgss.GSSCredential;
private Path nodeKeyTab = KernelUtils.getOsgiInstancePath(KernelConstants.NODE_KEY_TAB_PATH);
private GSSCredential acceptorCredentials;
+ private boolean singleUser = false;
+
public NodeUserAdmin(String systemRolesBaseDn) {
super(systemRolesBaseDn);
tmTracker = new ServiceTracker<>(bc, TransactionManager.class, null);
}
// Create
- AbstractUserDirectory userDirectory = u.getScheme().equals("ldap") ? new LdapUserAdmin(properties)
- : new LdifUserAdmin(u, properties);
+ AbstractUserDirectory userDirectory;
+ if (UserAdminConf.SCHEME_LDAP.equals(u.getScheme())) {
+ userDirectory = new LdapUserAdmin(properties);
+ } else if (UserAdminConf.SCHEME_FILE.equals(u.getScheme())) {
+ userDirectory = new LdifUserAdmin(u, properties);
+ } else if (UserAdminConf.SCHEME_OS.equals(u.getScheme())) {
+ userDirectory = new OsUserDirectory(u, properties);
+ singleUser = true;
+ } else {
+ throw new CmsException("Unsupported scheme " + u.getScheme());
+ }
Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name());
addUserDirectory(userDirectory);
return acceptorCredentials;
}
+ public boolean isSingleUser() {
+ return singleUser;
+ }
+
public final static Oid KERBEROS_OID;
static {
try {
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import static org.argeo.osgi.useradmin.UserAdminConf.propertiesAsUri;
+import static org.argeo.osgi.useradmin.UserAdminConf.uriAsProperties;
+
+import java.net.URI;
+import java.util.Dictionary;
+
+import junit.framework.TestCase;
+
+public class UserAdminConfTest extends TestCase {
+ public void testUriFormat() throws Exception {
+ // LDAP
+ URI uriIn = new URI("ldap://" + "uid=admin,ou=system:secret@localhost:10389" + "/dc=example,dc=com"
+ + "?readOnly=false&userObjectClass=person");
+ Dictionary<String, ?> props = uriAsProperties(uriIn.toString());
+ System.out.println(props);
+ assertEquals("dc=example,dc=com", props.get(UserAdminConf.baseDn.name()));
+ assertEquals("false", props.get(UserAdminConf.readOnly.name()));
+ assertEquals("person", props.get(UserAdminConf.userObjectClass.name()));
+ URI uriOut = propertiesAsUri(props);
+ System.out.println(uriOut);
+ assertEquals("/dc=example,dc=com?userObjectClass=person&readOnly=false", uriOut.toString());
+
+ // File
+ uriIn = new URI("file://some/dir/dc=example,dc=com.ldif");
+ props = uriAsProperties(uriIn.toString());
+ System.out.println(props);
+ assertEquals("dc=example,dc=com", props.get(UserAdminConf.baseDn.name()));
+
+ // Base configuration
+ uriIn = new URI("/dc=example,dc=com.ldif?readOnly=true&userBase=ou=CoWorkers,ou=People&groupBase=ou=Roles");
+ props = uriAsProperties(uriIn.toString());
+ System.out.println(props);
+ assertEquals("dc=example,dc=com", props.get(UserAdminConf.baseDn.name()));
+ assertEquals("true", props.get(UserAdminConf.readOnly.name()));
+ assertEquals("ou=CoWorkers,ou=People", props.get(UserAdminConf.userBase.name()));
+ assertEquals("ou=Roles", props.get(UserAdminConf.groupBase.name()));
+ uriOut = propertiesAsUri(props);
+ System.out.println(uriOut);
+ assertEquals("/dc=example,dc=com?userBase=ou=CoWorkers,ou=People&groupBase=ou=Roles&readOnly=true", uriOut.toString());
+
+ // OS
+ uriIn = new URI("os:///dc=example,dc=com");
+ props = uriAsProperties(uriIn.toString());
+ System.out.println(props);
+ assertEquals("dc=example,dc=com", props.get(UserAdminConf.baseDn.name()));
+ assertEquals("true", props.get(UserAdminConf.readOnly.name()));
+ uriOut = propertiesAsUri(props);
+ System.out.println(uriOut);
+ assertEquals("/dc=example,dc=com?readOnly=true", uriOut.toString());
+ }
+}
return true;
if (uri.getScheme() == null)
return false;// assume relative file to be writable
- if (uri.getScheme().equals("file")) {
+ if (uri.getScheme().equals(UserAdminConf.SCHEME_FILE)) {
File file = new File(uri);
if (file.exists())
return !file.canWrite();
else
return !file.getParentFile().canWrite();
- } else if (uri.getScheme().equals("ldap")) {
+ } else if (uri.getScheme().equals(UserAdminConf.SCHEME_LDAP)) {
if (uri.getAuthority() != null)// assume writable if authenticated
return false;
+ } else if (uri.getScheme().equals(UserAdminConf.SCHEME_OS)) {
+ return true;
}
return true;// read only by default
}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.List;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.ldap.LdapName;
+
+import org.argeo.naming.LdapAttrs;
+import org.osgi.framework.Filter;
+import org.osgi.service.useradmin.User;
+
+public class OsUserDirectory extends AbstractUserDirectory {
+ private final String osUsername = System.getProperty("user.name");
+ private final LdapName osUserDn;
+ private final LdifUser osUser;
+
+ public OsUserDirectory(URI uriArg, Dictionary<String, ?> props) {
+ super(uriArg, props);
+ try {
+ osUserDn = new LdapName(LdapAttrs.uid.name() + "=" + osUsername + "," + getUserBase() + "," + getBaseDn());
+ Attributes attributes = new BasicAttributes();
+ attributes.put(LdapAttrs.uid.name(), osUsername);
+ osUser = new LdifUser(this, osUserDn, attributes);
+ } catch (NamingException e) {
+ throw new UserDirectoryException("Cannot create system user", e);
+ }
+ }
+
+ @Override
+ protected List<LdapName> getDirectGroups(LdapName dn) {
+ return new ArrayList<>();
+ }
+
+ @Override
+ protected Boolean daoHasRole(LdapName dn) {
+ return osUserDn.equals(dn);
+ }
+
+ @Override
+ protected DirectoryUser daoGetRole(LdapName key) throws NameNotFoundException {
+ if (osUserDn.equals(key))
+ return osUser;
+ else
+ throw new NameNotFoundException("Not an OS role");
+ }
+
+ @Override
+ protected List<DirectoryUser> doGetRoles(Filter f) {
+ List<DirectoryUser> res = new ArrayList<>();
+ if (f.match(osUser.getProperties()))
+ res.add(osUser);
+ return res;
+ }
+
+ @Override
+ protected AbstractUserDirectory scope(User user) {
+ throw new UnsupportedOperationException();
+ }
+
+}
--- /dev/null
+package org.argeo.osgi.useradmin;
+
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.NoSuchAlgorithmException;
+import java.security.URIParameter;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+public class OsUserUtils {
+ private static String LOGIN_CONTEXT_USER_NIX = "USER_NIX";
+ private static String LOGIN_CONTEXT_USER_WINDOWS = "USER_WINDOWS";
+
+ public static String getOsUsername() {
+ return System.getProperty("user.name");
+ }
+
+ public static LoginContext loginAsSystemUser(Subject subject) {
+ try {
+ URL jaasConfigurationUrl = OsUserUtils.class.getClassLoader()
+ .getResource("org/argeo/osgi/useradmin/jaas-os.cfg");
+ URIParameter uriParameter = new URIParameter(jaasConfigurationUrl.toURI());
+ Configuration jaasConfiguration = Configuration.getInstance("JavaLoginConfig", uriParameter);
+ LoginContext lc = new LoginContext(isWindows() ? LOGIN_CONTEXT_USER_WINDOWS : LOGIN_CONTEXT_USER_NIX,
+ subject, null, jaasConfiguration);
+ lc.login();
+ return lc;
+ } catch (URISyntaxException | NoSuchAlgorithmException | LoginException e) {
+ throw new RuntimeException("Cannot loging as system user", e);
+ }
+ }
+
+ public static void main(String args[]) {
+ Subject subject = new Subject();
+ LoginContext loginContext = loginAsSystemUser(subject);
+ System.out.println(subject);
+ try {
+ loginContext.logout();
+ } catch (LoginException e) {
+ // silent
+ }
+ }
+
+ private static boolean isWindows() {
+ return System.getProperty("os.name").startsWith("Windows");
+ }
+
+ private OsUserUtils() {
+ }
+}
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.UnknownHostException;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
public final static String FACTORY_PID = "org.argeo.osgi.useradmin.config";
private final static Log log = LogFactory.getLog(UserAdminConf.class);
+ public final static String SCHEME_LDAP = "ldap";
+ public final static String SCHEME_FILE = "file";
+ public final static String SCHEME_OS = "os";
+ public final static String SCHEME_IPA = "ipa";
+
/** The default value. */
private Object def;
Hashtable<String, Object> res = new Hashtable<String, Object>();
URI u = new URI(uriStr);
String scheme = u.getScheme();
- if (scheme != null && scheme.equals("ipa")) {
+ if (scheme != null && scheme.equals(SCHEME_IPA)) {
u = convertIpaConfig(u);
scheme = u.getScheme();
}
String path = u.getPath();
// base DN
String bDn = path.substring(path.lastIndexOf('/') + 1, path.length());
+ if (bDn.equals("") && SCHEME_OS.equals(scheme)) {
+ bDn = getBaseDnFromHostname();
+ }
+
if (bDn.endsWith(".ldif"))
bDn = bDn.substring(0, bDn.length() - ".ldif".length());
String principal = null;
String credentials = null;
if (scheme != null)
- if (scheme.equals("ldap") || scheme.equals("ldaps")) {
+ if (scheme.equals(SCHEME_LDAP) || scheme.equals("ldaps")) {
// TODO additional checks
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 if (scheme.equals("ipa")) {
+ } else if (scheme.equals(SCHEME_FILE)) {
+ } else if (scheme.equals(SCHEME_IPA)) {
+ } else if (scheme.equals(SCHEME_OS)) {
} else
throw new UserDirectoryException("Unsupported scheme " + scheme);
Map<String, List<String>> query = NamingUtils.queryToMap(u);
}
}
res.put(baseDn.name(), bDn);
+ if (SCHEME_OS.equals(scheme))
+ res.put(readOnly.name(), "true");
if (principal != null)
res.put(Context.SECURITY_PRINCIPAL, principal);
if (credentials != null)
res.put(Context.SECURITY_CREDENTIALS, credentials);
if (scheme != null) {// relative URIs are dealt with externally
- URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
- scheme.equals("file") ? u.getPath() : null, null, null);
- res.put(uri.name(), bareUri.toString());
+ if (SCHEME_OS.equals(scheme)) {
+ res.put(uri.name(), SCHEME_OS + ":///");
+ } else {
+ URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(),
+ scheme.equals(SCHEME_FILE) ? u.getPath() : null, null, null);
+ res.put(uri.name(), bareUri.toString());
+ }
}
return res;
} catch (Exception e) {
}
}
URI convertedUri = new URI(
- "ldap://" + ldapHostsStr + "/" + IpaUtils.domainToUserDirectoryConfigPath(kerberosRealm));
+ SCHEME_LDAP + "://" + ldapHostsStr + "/" + IpaUtils.domainToUserDirectoryConfigPath(kerberosRealm));
if (log.isDebugEnabled())
log.debug("Converted " + uri + " to " + convertedUri);
return convertedUri;
}
- // private static Map<String, List<String>> splitQuery(String query) throws
- // UnsupportedEncodingException {
- // final Map<String, List<String>> query_pairs = new LinkedHashMap<String,
- // List<String>>();
- // if (query == null)
- // return query_pairs;
- // final String[] pairs = query.split("&");
- // for (String pair : pairs) {
- // final int idx = pair.indexOf("=");
- // final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx),
- // "UTF-8") : pair;
- // if (!query_pairs.containsKey(key)) {
- // query_pairs.put(key, new LinkedList<String>());
- // }
- // final String value = idx > 0 && pair.length() > idx + 1
- // ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null;
- // query_pairs.get(key).add(value);
- // }
- // return query_pairs;
- // }
-
- public static void main(String[] args) {
- Dictionary<String, ?> props = uriAsProperties("ldap://" + "uid=admin,ou=system:secret@localhost:10389"
- + "/dc=example,dc=com" + "?readOnly=false&userObjectClass=person");
- System.out.println(props);
- System.out.println(propertiesAsUri(props));
-
- System.out.println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif"));
-
- props = uriAsProperties(
- "/dc=example,dc=com.ldif?readOnly=true" + "&userBase=ou=CoWorkers,ou=People&groupBase=ou=Roles");
- System.out.println(props);
- System.out.println(propertiesAsUri(props));
+ private static String getBaseDnFromHostname() {
+ String hostname;
+ try {
+ hostname = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ log.warn("Using localhost as hostname", e);
+ hostname = "localhost.localdomain";
+ }
+ int dotIdx = hostname.indexOf('.');
+ if (dotIdx >= 0) {
+ String domain = hostname.substring(dotIdx + 1, hostname.length());
+ String bDn = ("." + domain).replaceAll("\\.", ",dc=");
+ bDn = bDn.substring(1, bDn.length());
+ return bDn;
+ } else {
+ return "dc=" + hostname;
+ }
}
}
--- /dev/null
+USER_NIX {
+ com.sun.security.auth.module.UnixLoginModule requisite;
+};
+
+USER_NT {
+ com.sun.security.auth.module.NTLoginModule requisite;
+};
+
@Override
public boolean equals(Object obj) {
- return this == obj;
+ return obj instanceof DataAdminPrincipal;
}
@Override
import org.argeo.node.NodeConstants;
public class NodeSecurityUtils {
- public final static LdapName ROLE_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME, ROLE_USER_ADMIN_NAME;
+ public final static LdapName ROLE_ADMIN_NAME, ROLE_DATA_ADMIN_NAME, ROLE_ANONYMOUS_NAME, ROLE_USER_NAME,
+ ROLE_USER_ADMIN_NAME;
public final static List<LdapName> RESERVED_ROLES;
static {
try {
ROLE_ADMIN_NAME = new LdapName(NodeConstants.ROLE_ADMIN);
+ ROLE_DATA_ADMIN_NAME = new LdapName(NodeConstants.ROLE_DATA_ADMIN);
ROLE_USER_NAME = new LdapName(NodeConstants.ROLE_USER);
ROLE_USER_ADMIN_NAME = new LdapName(NodeConstants.ROLE_USER_ADMIN);
ROLE_ANONYMOUS_NAME = new LdapName(NodeConstants.ROLE_ANONYMOUS);