X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FNodeUserAdmin.java;h=17daa3e14ae15b33f8af32f1dfe6560a9c6c04cb;hb=b71546ddc74d6ca49d252806aafd491c75dfe1fb;hp=8410b3958aef378d49a34dbd260b43f83696a128;hpb=6338d85d3f970dd0eb8845693ddad90a93b99d03;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java index 8410b3958..17daa3e14 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java @@ -14,6 +14,7 @@ import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; +import java.util.Set; import javax.naming.ldap.LdapName; import javax.security.auth.Subject; @@ -24,28 +25,29 @@ import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.auth.kerberos.KerberosPrincipal; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; -import javax.transaction.TransactionManager; import org.apache.commons.httpclient.auth.AuthPolicy; import org.apache.commons.httpclient.auth.CredentialsProvider; -import org.apache.commons.httpclient.cookie.CookiePolicy; 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.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.cms.CmsException; -import org.argeo.cms.internal.http.NodeHttp; +import org.argeo.api.cms.CmsAuth; +import org.argeo.api.cms.CmsConstants; +import org.argeo.api.cms.CmsLog; +import org.argeo.cms.CmsUserManager; +import org.argeo.cms.internal.auth.CmsUserManagerImpl; import org.argeo.cms.internal.http.client.HttpCredentialProvider; import org.argeo.cms.internal.http.client.SpnegoAuthScheme; -import org.argeo.naming.DnsBrowser; -import org.argeo.node.NodeConstants; +import org.argeo.osgi.transaction.WorkControl; +import org.argeo.osgi.transaction.WorkTransaction; import org.argeo.osgi.useradmin.AbstractUserDirectory; 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.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; @@ -53,94 +55,144 @@ import org.ietf.jgss.GSSName; import org.ietf.jgss.Oid; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; -import org.osgi.framework.FrameworkUtil; -import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedServiceFactory; +import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.UserAdmin; import org.osgi.util.tracker.ServiceTracker; -import bitronix.tm.BitronixTransactionManager; -import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer; - /** * Aggregates multiple {@link UserDirectory} and integrates them with system * roles. */ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactory, KernelConstants { - private final static Log log = LogFactory.getLog(NodeUserAdmin.class); - private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); + private final static CmsLog log = CmsLog.getLog(NodeUserAdmin.class); +// private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext(); // OSGi private Map pidToBaseDn = new HashMap<>(); - private Map> pidToServiceRegs = new HashMap<>(); - private ServiceRegistration userAdminReg; +// private Map> pidToServiceRegs = new HashMap<>(); +// private ServiceRegistration userAdminReg; // JTA - private final ServiceTracker tmTracker; - private final String cacheName = UserDirectory.class.getName(); + private final ServiceTracker tmTracker; + // private final String cacheName = UserDirectory.class.getName(); // GSS API private Path nodeKeyTab = KernelUtils.getOsgiInstancePath(KernelConstants.NODE_KEY_TAB_PATH); private GSSCredential acceptorCredentials; - public NodeUserAdmin(String systemRolesBaseDn) { - super(systemRolesBaseDn); - tmTracker = new ServiceTracker<>(bc, TransactionManager.class, null); - tmTracker.open(); + private boolean singleUser = false; +// private boolean systemRolesAvailable = false; + + CmsUserManagerImpl userManager; + + public NodeUserAdmin(String systemRolesBaseDn, String tokensBaseDn) { + super(systemRolesBaseDn, tokensBaseDn); + BundleContext bc = Activator.getBundleContext(); + if (bc != null) { + tmTracker = new ServiceTracker<>(bc, WorkControl.class, null) { + + @Override + public WorkControl addingService(ServiceReference reference) { + WorkControl workControl = super.addingService(reference); + userManager = new CmsUserManagerImpl(); + userManager.setUserAdmin(NodeUserAdmin.this); + // FIXME make it more robust + userManager.setUserTransaction((WorkTransaction) workControl); + bc.registerService(CmsUserManager.class, userManager, null); + return workControl; + } + }; + tmTracker.open(); + } else { + tmTracker = null; + } } @Override public void updated(String pid, Dictionary properties) throws ConfigurationException { String uri = (String) properties.get(UserAdminConf.uri.name()); + Object realm = properties.get(UserAdminConf.realm.name()); URI u; try { if (uri == null) { String baseDn = (String) properties.get(UserAdminConf.baseDn.name()); u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + baseDn + ".ldif"); - } else + } else if (realm != null) { + u = null; + } else { u = new URI(uri); + } } catch (URISyntaxException e) { - throw new CmsException("Badly formatted URI " + uri, e); + throw new IllegalArgumentException("Badly formatted URI " + uri, e); } // Create - AbstractUserDirectory userDirectory = u.getScheme().equals("ldap") ? new LdapUserAdmin(properties) - : new LdifUserAdmin(u, properties); - Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name()); + AbstractUserDirectory 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()); + } addUserDirectory(userDirectory); // OSGi LdapName baseDn = userDirectory.getBaseDn(); - Dictionary regProps = new Hashtable<>(); + Hashtable regProps = new Hashtable<>(); regProps.put(Constants.SERVICE_PID, pid); if (isSystemRolesBaseDn(baseDn)) regProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); regProps.put(UserAdminConf.baseDn.name(), baseDn); - ServiceRegistration reg = bc.registerService(UserDirectory.class, userDirectory, regProps); + // ServiceRegistration reg = + // bc.registerService(UserDirectory.class, userDirectory, regProps); + Activator.registerService(UserDirectory.class, userDirectory, regProps); + userManager.addUserDirectory(userDirectory, regProps); pidToBaseDn.put(pid, baseDn); - pidToServiceRegs.put(pid, reg); - - if (log.isDebugEnabled()) - log.debug("User directory " + userDirectory.getBaseDn() + " [" + u.getScheme() + "] enabled." - + (realm != null ? " " + realm + " realm." : "")); - - if (!isSystemRolesBaseDn(baseDn)) { - if (userAdminReg != null) - userAdminReg.unregister(); - // register self as main user admin - Dictionary userAdminregProps = currentState(); - userAdminregProps.put(NodeConstants.CN, NodeConstants.DEFAULT); + // pidToServiceRegs.put(pid, reg); + + if (log.isDebugEnabled()) { + log.debug("User directory " + userDirectory.getBaseDn() + (u != null ? " [" + u.getScheme() + "]" : "") + + " enabled." + (realm != null ? " " + realm + " realm." : "")); + } + + if (isSystemRolesBaseDn(baseDn)) { + // publishes only when system roles are available + Dictionary userAdminregProps = new Hashtable<>(); + userAdminregProps.put(CmsConstants.CN, CmsConstants.DEFAULT); userAdminregProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); - userAdminReg = bc.registerService(UserAdmin.class, this, userAdminregProps); + Activator.registerService(UserAdmin.class, this, userAdminregProps); } + +// if (isSystemRolesBaseDn(baseDn)) +// systemRolesAvailable = true; +// +// // start publishing only when system roles are available +// if (systemRolesAvailable) { +// // The list of baseDns is published as properties +// // TODO clients should rather reference USerDirectory services +// if (userAdminReg != null) +// userAdminReg.unregister(); +// // register self as main user admin +// Dictionary userAdminregProps = currentState(); +// userAdminregProps.put(NodeConstants.CN, NodeConstants.DEFAULT); +// userAdminregProps.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE); +// userAdminReg = bc.registerService(UserAdmin.class, this, userAdminregProps); +// } } @Override public void deleted(String pid) { - assert pidToServiceRegs.get(pid) != null; + // assert pidToServiceRegs.get(pid) != null; assert pidToBaseDn.get(pid) != null; - pidToServiceRegs.remove(pid).unregister(); + // pidToServiceRegs.remove(pid).unregister(); LdapName baseDn = pidToBaseDn.remove(pid); removeUserDirectory(baseDn); } @@ -150,14 +202,23 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor return "Node User Admin"; } + @Override + protected void addAbstractSystemRoles(Authorization rawAuthorization, Set sysRoles) { + if (rawAuthorization.getName() == null) { + sysRoles.add(CmsConstants.ROLE_ANONYMOUS); + } else { + sysRoles.add(CmsConstants.ROLE_USER); + } + } + protected void postAdd(AbstractUserDirectory userDirectory) { // JTA - TransactionManager tm = tmTracker.getService(); + WorkControl tm = tmTracker != null ? tmTracker.getService() : null; if (tm == null) - throw new CmsException("A JTA transaction manager must be available."); - userDirectory.setTransactionManager(tm); - if (tmTracker.getService() instanceof BitronixTransactionManager) - EhCacheXAResourceProducer.registerXAResource(cacheName, userDirectory.getXaResource()); + throw new IllegalStateException("A JTA transaction manager must be available."); + userDirectory.setTransactionControl(tm); +// if (tmTracker.getService() instanceof BitronixTransactionManager) +// EhCacheXAResourceProducer.registerXAResource(cacheName, userDirectory.getXaResource()); Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name()); if (realm != null) { @@ -174,11 +235,11 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor } }; try { - LoginContext nodeLc = new LoginContext(NodeConstants.LOGIN_CONTEXT_NODE, callbackHandler); + LoginContext nodeLc = new LoginContext(CmsAuth.LOGIN_CONTEXT_NODE, callbackHandler); nodeLc.login(); acceptorCredentials = logInAsAcceptor(nodeLc.getSubject(), servicePrincipal); } catch (LoginException e) { - throw new CmsException("Cannot log in kernel", e); + throw new IllegalStateException("Cannot log in kernel", e); } } } @@ -191,14 +252,14 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor // 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, CookiePolicy.BROWSER_COMPATIBILITY); + params.setParameter(HttpMethodParams.COOKIE_POLICY, KernelConstants.COOKIE_POLICY_BROWSER_COMPATIBILITY); // params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); } } protected void preDestroy(AbstractUserDirectory userDirectory) { - if (tmTracker.getService() instanceof BitronixTransactionManager) - EhCacheXAResourceProducer.unregisterXAResource(cacheName, userDirectory.getXaResource()); +// if (tmTracker.getService() instanceof BitronixTransactionManager) +// EhCacheXAResourceProducer.unregisterXAResource(cacheName, userDirectory.getXaResource()); Object realm = userDirectory.getProperties().get(UserAdminConf.realm.name()); if (realm != null) { @@ -223,7 +284,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor boolean consistentIp = localhost.getHostAddress().equals(ipfromDns); String kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT"); if (consistentIp && kerberosDomain != null && kerberosDomain.equals(realm) && Files.exists(nodeKeyTab)) { - return NodeHttp.DEFAULT_SERVICE + "/" + hostname + "@" + kerberosDomain; + return KernelConstants.DEFAULT_KERBEROS_SERVICE + "/" + hostname + "@" + kerberosDomain; } else return null; } catch (Exception e) { @@ -264,7 +325,7 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor log.debug("GSS acceptor configured for " + krb5Principal); return serverCredentials; } catch (Exception gsse) { - throw new CmsException("Cannot create acceptor credentials for " + krb5Principal, gsse); + throw new IllegalStateException("Cannot create acceptor credentials for " + krb5Principal, gsse); } } @@ -272,6 +333,10 @@ class NodeUserAdmin extends AggregatingUserAdmin implements ManagedServiceFactor return acceptorCredentials; } + public boolean isSingleUser() { + return singleUser; + } + public final static Oid KERBEROS_OID; static { try {