package org.argeo.cms.internal.runtime;
import java.io.IOException;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Iterator;
+import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
-import org.apache.commons.httpclient.auth.AuthPolicy;
-import org.apache.commons.httpclient.auth.CredentialsProvider;
-import org.apache.commons.httpclient.params.DefaultHttpParams;
-import org.apache.commons.httpclient.params.HttpMethodParams;
-import org.apache.commons.httpclient.params.HttpParams;
import org.argeo.api.cms.CmsAuth;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.internal.http.client.HttpCredentialProvider;
-import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
+import org.argeo.api.cms.CmsState;
+import org.argeo.cms.CmsDeployProperty;
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.DirectoryUserAdmin;
import org.argeo.osgi.useradmin.UserDirectory;
import org.argeo.util.directory.DirectoryConf;
import org.argeo.util.naming.dns.DnsBrowser;
private WorkControl transactionManager;
private WorkTransaction userTransaction;
+ private CmsState cmsState;
+
public CmsUserAdmin() {
- super(CmsConstants.ROLES_BASEDN, CmsConstants.TOKENS_BASEDN);
+ super(CmsConstants.SYSTEM_ROLES_BASEDN, CmsConstants.TOKENS_BASEDN);
}
public void start() {
+ super.start();
+ List<Dictionary<String, Object>> configs = getUserDirectoryConfigs();
+ for (Dictionary<String, Object> config : configs) {
+ enableUserDirectory(config);
+// if (userDirectory.getRealm().isPresent())
+// loadIpaJaasConfiguration();
+ }
+ log.debug(() -> "CMS user admin available");
}
public void stop() {
+// for (UserDirectory userDirectory : getUserDirectories()) {
+// removeUserDirectory(userDirectory);
+// }
+ super.stop();
+ }
+
+ protected List<Dictionary<String, Object>> getUserDirectoryConfigs() {
+ List<Dictionary<String, Object>> res = new ArrayList<>();
+ Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_PRIVATE);
+ List<String> uris = new ArrayList<>();
+
+ // node roles
+ String nodeRolesUri = null;// getFrameworkProp(CmsConstants.ROLES_URI);
+ String baseNodeRoleDn = CmsConstants.SYSTEM_ROLES_BASEDN;
+ if (nodeRolesUri == null && nodeBase != null) {
+ nodeRolesUri = baseNodeRoleDn + ".ldif";
+ Path nodeRolesFile = nodeBase.resolve(nodeRolesUri);
+ if (!Files.exists(nodeRolesFile))
+ try {
+ Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeRoleDn + ".ldif"), nodeRolesFile);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy demo resource", e);
+ }
+ // nodeRolesUri = nodeRolesFile.toURI().toString();
+ }
+ if (nodeRolesUri != null)
+ uris.add(nodeRolesUri);
+
+ // node tokens
+ String nodeTokensUri = null;// getFrameworkProp(CmsConstants.TOKENS_URI);
+ String baseNodeTokensDn = CmsConstants.TOKENS_BASEDN;
+ if (nodeTokensUri == null && nodeBase != null) {
+ nodeTokensUri = baseNodeTokensDn + ".ldif";
+ Path nodeTokensFile = nodeBase.resolve(nodeTokensUri);
+ if (!Files.exists(nodeTokensFile))
+ try {
+ Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeTokensDn + ".ldif"), nodeTokensFile);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy demo resource", e);
+ }
+ // nodeRolesUri = nodeRolesFile.toURI().toString();
+ }
+ if (nodeTokensUri != null)
+ uris.add(nodeTokensUri);
+
+ // Business roles
+// String userAdminUris = getFrameworkProp(CmsConstants.USERADMIN_URIS);
+ List<String> userAdminUris = CmsStateImpl.getDeployProperties(cmsState, CmsDeployProperty.DIRECTORY);// getFrameworkProp(CmsConstants.USERADMIN_URIS);
+ for (String userAdminUri : userAdminUris) {
+ if (userAdminUri == null)
+ continue;
+// if (!userAdminUri.trim().equals(""))
+ uris.add(userAdminUri);
+ }
+
+ if (uris.size() == 0 && nodeBase != null) {
+ // TODO put this somewhere else
+ String demoBaseDn = "dc=example,dc=com";
+ String userAdminUri = demoBaseDn + ".ldif";
+ Path businessRolesFile = nodeBase.resolve(userAdminUri);
+ Path systemRolesFile = nodeBase.resolve("ou=roles,ou=node.ldif");
+ if (!Files.exists(businessRolesFile))
+ try {
+ Files.copy(CmsUserAdmin.class.getResourceAsStream(demoBaseDn + ".ldif"), businessRolesFile);
+ if (!Files.exists(systemRolesFile))
+ Files.copy(CmsUserAdmin.class.getResourceAsStream("example-ou=roles,ou=node.ldif"),
+ systemRolesFile);
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot copy demo resources", e);
+ }
+ // userAdminUris = businessRolesFile.toURI().toString();
+ log.warn("## DEV Using dummy base DN " + demoBaseDn);
+ // TODO downgrade security level
+ }
+
+ // Interprets URIs
+ for (String uri : uris) {
+ URI u;
+ try {
+ u = new URI(uri);
+ if (u.getPath() == null)
+ throw new IllegalArgumentException(
+ "URI " + uri + " must have a path in order to determine base DN");
+ if (u.getScheme() == null) {
+ if (uri.startsWith("/") || uri.startsWith("./") || uri.startsWith("../"))
+ u = Paths.get(uri).toRealPath().toUri();
+ else if (!uri.contains("/")) {
+ // u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + uri);
+ u = new URI(uri);
+ } else
+ throw new IllegalArgumentException("Cannot interpret " + uri + " as an uri");
+ } else if (u.getScheme().equals(DirectoryConf.SCHEME_FILE)) {
+ u = Paths.get(u).toRealPath().toUri();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot interpret " + uri + " as an uri", e);
+ }
+
+ try {
+ Dictionary<String, Object> properties = DirectoryConf.uriAsProperties(u.toString());
+ res.add(properties);
+ } catch (Exception e) {
+ log.error("Cannot load user directory " + u, e);
+ }
+ }
+
+ return res;
}
public UserDirectory enableUserDirectory(Dictionary<String, ?> properties) {
try {
if (uri == null) {
String baseDn = (String) properties.get(DirectoryConf.baseDn.name());
- u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + baseDn + ".ldif");
+ u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_PRIVATE + '/' + baseDn + ".ldif");
} else if (realm != null) {
u = null;
} else {
}
// Create
- UserDirectory userDirectory;
- if (realm != null || DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
- || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
- userDirectory = new LdapUserAdmin(properties);
- } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
- userDirectory = new LdifUserAdmin(u, properties);
- } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
- userDirectory = new OsUserDirectory(u, properties);
- singleUser = true;
- } else {
- throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
- }
- String basePath = userDirectory.getContext();
+ UserDirectory userDirectory = new DirectoryUserAdmin(u, properties);
+// if (realm != null || DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
+// || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
+// userDirectory = new LdapUserAdmin(properties);
+// } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
+// userDirectory = new LdifUserAdmin(u, properties);
+// } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
+// userDirectory = new OsUserDirectory(u, properties);
+// singleUser = true;
+// } else {
+// throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+// }
+ String basePath = userDirectory.getBase();
addUserDirectory(userDirectory);
if (isSystemRolesBaseDn(basePath)) {
addStandardSystemRoles();
}
if (log.isDebugEnabled()) {
- log.debug("User directory " + userDirectory.getContext() + (u != null ? " [" + u.getScheme() + "]" : "")
+ log.debug("User directory " + userDirectory.getBase() + (u != null ? " [" + u.getScheme() + "]" : "")
+ " enabled." + (realm != null ? " " + realm + " realm." : ""));
}
return userDirectory;
Optional<String> realm = userDirectory.getRealm();
if (realm.isPresent()) {
+ loadIpaJaasConfiguration();
if (Files.exists(nodeKeyTab)) {
String servicePrincipal = getKerberosServicePrincipal(realm.get());
if (servicePrincipal != null) {
}
};
try {
- LoginContext nodeLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_NODE, callbackHandler);
+ LoginContext nodeLc = CmsAuth.NODE.newLoginContext(callbackHandler);
nodeLc.login();
acceptorCredentials = logInAsAcceptor(nodeLc.getSubject(), servicePrincipal);
} catch (LoginException e) {
}
}
- // Register client-side SPNEGO auth scheme
- AuthPolicy.registerAuthScheme(SpnegoAuthScheme.NAME, SpnegoAuthScheme.class);
- HttpParams params = DefaultHttpParams.getDefaultParams();
- ArrayList<String> schemes = new ArrayList<>();
- schemes.add(SpnegoAuthScheme.NAME);// SPNEGO preferred
- // schemes.add(AuthPolicy.BASIC);// incompatible with Basic
- params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes);
- params.setParameter(CredentialsProvider.PROVIDER, new HttpCredentialProvider());
- params.setParameter(HttpMethodParams.COOKIE_POLICY, KernelConstants.COOKIE_POLICY_BROWSER_COMPATIBILITY);
- // params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
}
}
}
}
- private String getKerberosServicePrincipal(String realm) {
- String hostname;
- try (DnsBrowser dnsBrowser = new DnsBrowser()) {
- InetAddress localhost = InetAddress.getLocalHost();
- hostname = localhost.getHostName();
+ private void loadIpaJaasConfiguration() {
+ if (CmsStateImpl.getDeployProperty(cmsState, CmsDeployProperty.JAVA_LOGIN_CONFIG) == null) {
+ String jaasConfig = KernelConstants.JAAS_CONFIG_IPA;
+ URL url = getClass().getClassLoader().getResource(jaasConfig);
+ KernelUtils.setJaasConfiguration(url);
+ log.debug("Set IPA JAAS configuration.");
+ }
+ }
+
+ protected String getKerberosServicePrincipal(String realm) {
+ if (!Files.exists(nodeKeyTab))
+ return null;
+ List<String> dns = CmsStateImpl.getDeployProperties(cmsState, CmsDeployProperty.DNS);
+ String hostname = CmsStateImpl.getDeployProperty(cmsState, CmsDeployProperty.HOST);
+ try (DnsBrowser dnsBrowser = new DnsBrowser(dns)) {
+ hostname = hostname != null ? hostname : InetAddress.getLocalHost().getHostName();
String dnsZone = hostname.substring(hostname.indexOf('.') + 1);
- String ipfromDns = dnsBrowser.getRecord(hostname, localhost instanceof Inet6Address ? "AAAA" : "A");
- boolean consistentIp = localhost.getHostAddress().equals(ipfromDns);
+ String ipv4fromDns = dnsBrowser.getRecord(hostname, "A");
+ String ipv6fromDns = dnsBrowser.getRecord(hostname, "AAAA");
+ if (ipv4fromDns == null && ipv6fromDns == null)
+ throw new IllegalStateException("hostname " + hostname + " is not registered in DNS");
+ // boolean consistentIp = localhost.getHostAddress().equals(ipfromDns);
String kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT");
- if (consistentIp && kerberosDomain != null && kerberosDomain.equals(realm) && Files.exists(nodeKeyTab)) {
+ if (kerberosDomain != null && kerberosDomain.equals(realm)) {
return KernelConstants.DEFAULT_KERBEROS_SERVICE + "/" + hostname + "@" + kerberosDomain;
} else
return null;
this.userTransaction = userTransaction;
}
- /*
- * STATIC
- */
+ public void setCmsState(CmsState cmsState) {
+ this.cmsState = cmsState;
+ }
}