Massive package refactoring
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / runtime / CmsUserAdmin.java
index 9ebc429178ce0276f7a83ae37eba2ebb083c96cf..6aa490a69ae144f9ec697a0e6c2f39b0ce482762 100644 (file)
@@ -1,14 +1,13 @@
 package org.argeo.cms.internal.runtime;
 
-import java.io.File;
 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;
@@ -26,26 +25,18 @@ import javax.security.auth.kerberos.KerberosPrincipal;
 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.apache.commons.io.FileUtils;
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
+import org.argeo.api.cms.transaction.WorkControl;
+import org.argeo.api.cms.transaction.WorkTransaction;
 import org.argeo.cms.CmsDeployProperty;
-import org.argeo.cms.internal.http.client.HttpCredentialProvider;
-import org.argeo.cms.internal.http.client.SpnegoAuthScheme;
-import org.argeo.osgi.useradmin.AggregatingUserAdmin;
-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;
-import org.argeo.util.transaction.WorkControl;
-import org.argeo.util.transaction.WorkTransaction;
+import org.argeo.cms.dns.DnsBrowser;
+import org.argeo.cms.osgi.useradmin.AggregatingUserAdmin;
+import org.argeo.cms.osgi.useradmin.DirectoryUserAdmin;
+import org.argeo.cms.osgi.useradmin.UserDirectory;
+import org.argeo.cms.runtime.DirectoryConf;
 import org.ietf.jgss.GSSCredential;
 import org.ietf.jgss.GSSException;
 import org.ietf.jgss.GSSManager;
@@ -74,16 +65,16 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
        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) {
-                       UserDirectory userDirectory = enableUserDirectory(config);
-                       if (userDirectory.getRealm().isPresent())
-                               loadIpaJaasConfiguration();
+                       enableUserDirectory(config);
+//                     if (userDirectory.getRealm().isPresent())
+//                             loadIpaJaasConfiguration();
                }
                log.debug(() -> "CMS user admin available");
        }
@@ -97,42 +88,42 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
 
        protected List<Dictionary<String, Object>> getUserDirectoryConfigs() {
                List<Dictionary<String, Object>> res = new ArrayList<>();
-               File nodeBaseDir = cmsState.getDataPath(KernelConstants.DIR_NODE).toFile();
+               Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_PRIVATE);
                List<String> uris = new ArrayList<>();
 
                // node roles
                String nodeRolesUri = null;// getFrameworkProp(CmsConstants.ROLES_URI);
-               String baseNodeRoleDn = CmsConstants.ROLES_BASEDN;
-               if (nodeRolesUri == null) {
+               String baseNodeRoleDn = CmsConstants.SYSTEM_ROLES_BASEDN;
+               if (nodeRolesUri == null && nodeBase != null) {
                        nodeRolesUri = baseNodeRoleDn + ".ldif";
-                       File nodeRolesFile = new File(nodeBaseDir, nodeRolesUri);
-                       if (!nodeRolesFile.exists())
+                       Path nodeRolesFile = nodeBase.resolve(nodeRolesUri);
+                       if (!Files.exists(nodeRolesFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(baseNodeRoleDn + ".ldif"),
-                                                       nodeRolesFile);
+                                       Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeRoleDn + ".ldif"), nodeRolesFile);
                                } catch (IOException e) {
                                        throw new RuntimeException("Cannot copy demo resource", e);
                                }
                        // nodeRolesUri = nodeRolesFile.toURI().toString();
                }
-               uris.add(nodeRolesUri);
+               if (nodeRolesUri != null)
+                       uris.add(nodeRolesUri);
 
                // node tokens
                String nodeTokensUri = null;// getFrameworkProp(CmsConstants.TOKENS_URI);
                String baseNodeTokensDn = CmsConstants.TOKENS_BASEDN;
-               if (nodeTokensUri == null) {
+               if (nodeTokensUri == null && nodeBase != null) {
                        nodeTokensUri = baseNodeTokensDn + ".ldif";
-                       File nodeTokensFile = new File(nodeBaseDir, nodeTokensUri);
-                       if (!nodeTokensFile.exists())
+                       Path nodeTokensFile = nodeBase.resolve(nodeTokensUri);
+                       if (!Files.exists(nodeTokensFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(baseNodeTokensDn + ".ldif"),
-                                                       nodeTokensFile);
+                                       Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeTokensDn + ".ldif"), nodeTokensFile);
                                } catch (IOException e) {
                                        throw new RuntimeException("Cannot copy demo resource", e);
                                }
                        // nodeRolesUri = nodeRolesFile.toURI().toString();
                }
-               uris.add(nodeTokensUri);
+               if (nodeTokensUri != null)
+                       uris.add(nodeTokensUri);
 
                // Business roles
 //             String userAdminUris = getFrameworkProp(CmsConstants.USERADMIN_URIS);
@@ -144,19 +135,17 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                        uris.add(userAdminUri);
                }
 
-               if (uris.size() == 0) {
+               if (uris.size() == 0 && nodeBase != null) {
                        // TODO put this somewhere else
                        String demoBaseDn = "dc=example,dc=com";
                        String userAdminUri = demoBaseDn + ".ldif";
-                       File businessRolesFile = new File(nodeBaseDir, userAdminUri);
-                       File systemRolesFile = new File(nodeBaseDir, "ou=roles,ou=node.ldif");
-                       if (!businessRolesFile.exists())
+                       Path businessRolesFile = nodeBase.resolve(userAdminUri);
+                       Path systemRolesFile = nodeBase.resolve("ou=roles,ou=node.ldif");
+                       if (!Files.exists(businessRolesFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(demoBaseDn + ".ldif"),
-                                                       businessRolesFile);
-                                       if (!systemRolesFile.exists())
-                                               FileUtils.copyInputStreamToFile(
-                                                               CmsUserAdmin.class.getResourceAsStream("example-ou=roles,ou=node.ldif"),
+                                       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);
@@ -176,20 +165,25 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                                                        "URI " + uri + " must have a path in order to determine base DN");
                                if (u.getScheme() == null) {
                                        if (uri.startsWith("/") || uri.startsWith("./") || uri.startsWith("../"))
-                                               u = new File(uri).getCanonicalFile().toURI();
+                                               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 = new File(u).getCanonicalFile().toURI();
+                                       u = Paths.get(u).toRealPath().toUri();
                                }
                        } catch (Exception e) {
                                throw new RuntimeException("Cannot interpret " + uri + " as an uri", e);
                        }
-                       Dictionary<String, Object> properties = DirectoryConf.uriAsProperties(u.toString());
-                       res.add(properties);
+
+                       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;
@@ -202,7 +196,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                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 {
@@ -225,14 +219,14 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
 //             } else {
 //                     throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
 //             }
-               String basePath = userDirectory.getContext();
+               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;
@@ -276,6 +270,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
 
                Optional<String> realm = userDirectory.getRealm();
                if (realm.isPresent()) {
+                       loadIpaJaasConfiguration();
                        if (Files.exists(nodeKeyTab)) {
                                String servicePrincipal = getKerberosServicePrincipal(realm.get());
                                if (servicePrincipal != null) {
@@ -289,7 +284,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                                                }
                                        };
                                        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) {
@@ -298,16 +293,6 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                                }
                        }
 
-                       // 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);
                }
        }
 
@@ -335,16 +320,21 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                }
        }
 
-       private String getKerberosServicePrincipal(String realm) {
-               String hostname;
-               try (DnsBrowser dnsBrowser = new DnsBrowser()) {
-                       InetAddress localhost = InetAddress.getLocalHost();
-                       hostname = localhost.getHostName();
+       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;