X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fruntime%2FCmsUserAdmin.java;h=6aa490a69ae144f9ec697a0e6c2f39b0ce482762;hb=54df376a9c2dd458a82eaa09bfbb718fe699dd0d;hp=890e283914d9d2027c5e4964a07239c101b46ff9;hpb=eb4324be6ac9cdff15828a21ee7d3f6ca2f19fb9;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java index 890e28391..6aa490a69 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java @@ -1,16 +1,18 @@ 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; @@ -23,25 +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.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.osgi.transaction.WorkControl; -import org.argeo.osgi.transaction.WorkTransaction; -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.argeo.util.naming.DnsBrowser; +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.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; @@ -67,24 +62,141 @@ public class CmsUserAdmin extends AggregatingUserAdmin { 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> configs = getUserDirectoryConfigs(); + for (Dictionary 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> getUserDirectoryConfigs() { + List> res = new ArrayList<>(); + Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_PRIVATE); + List 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 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 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 properties) { - String uri = (String) properties.get(UserAdminConf.uri.name()); - Object realm = properties.get(UserAdminConf.realm.name()); + String uri = (String) properties.get(DirectoryConf.uri.name()); + Object realm = properties.get(DirectoryConf.realm.name()); URI u; try { if (uri == null) { - String baseDn = (String) properties.get(UserAdminConf.baseDn.name()); - u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + baseDn + ".ldif"); + String baseDn = (String) properties.get(DirectoryConf.baseDn.name()); + u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_PRIVATE + '/' + baseDn + ".ldif"); } else if (realm != null) { u = null; } else { @@ -95,26 +207,26 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } // Create - UserDirectory userDirectory; - if (realm != null || UserAdminConf.SCHEME_LDAP.equals(u.getScheme()) - || UserAdminConf.SCHEME_LDAPS.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 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; @@ -158,6 +270,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin { Optional realm = userDirectory.getRealm(); if (realm.isPresent()) { + loadIpaJaasConfiguration(); if (Files.exists(nodeKeyTab)) { String servicePrincipal = getKerberosServicePrincipal(realm.get()); if (servicePrincipal != null) { @@ -171,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) { @@ -180,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 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); } } @@ -208,16 +311,30 @@ public class CmsUserAdmin extends AggregatingUserAdmin { } } - 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 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; @@ -290,8 +407,8 @@ public class CmsUserAdmin extends AggregatingUserAdmin { this.userTransaction = userTransaction; } - /* - * STATIC - */ + public void setCmsState(CmsState cmsState) { + this.cmsState = cmsState; + } }