From: Mathieu Baudier Date: Tue, 15 Sep 2015 14:52:42 +0000 (+0000) Subject: Improve user admin configuration X-Git-Tag: argeo-commons-2.1.30~152 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=e91af5c65a42b3ff98400caa552965cdb3f730e6;p=lgpl%2Fargeo-commons.git Improve user admin configuration git-svn-id: https://svn.argeo.org/commons/trunk@8400 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/demo/argeo_node_rap.properties b/demo/argeo_node_rap.properties index 5ea261764..2c9d5d842 100644 --- a/demo/argeo_node_rap.properties +++ b/demo/argeo_node_rap.properties @@ -12,7 +12,13 @@ org.eclipse.gemini.blueprint.extender argeo.osgi.start.4.workbench=\ org.eclipse.equinox.http.registry,\ -#argeo.node.useradmin.uri=ldap://localhost:10389/ +#argeo.node.useradmin.uri="\ +#ldap://uid=admin,ou=system:secret\ +#@localhost:10389\ +#/dc=example,dc=com\ +#?readOnly=false\ +#&userObjectClass=inetOrgPerson \ +#dc=example,dc=org.ldif" org.osgi.framework.security=osgi java.security.policy=file:../../all.policy diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index 6246a1b1b..189dd08d7 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -100,8 +100,6 @@ final class Kernel implements ServiceListener { repositoryFactory = new OsgiJackrabbitRepositoryFactory(); // Authentication - nodeSecurity.getUserAdmin().setSyncRegistry( - transactionManager.getTransactionSynchronizationRegistry()); nodeSecurity.getUserAdmin().setTransactionManager( transactionManager); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java index 63fe750be..e0d237da1 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelConstants.java @@ -17,7 +17,8 @@ public interface KernelConstants { final static String REPO_MAX_VOLATILE_INDEX_SIZE = "argeo.node.repo.maxVolatileIndexSize"; // Node Security - /** URI to an LDIF file used as initialization or backend */ + final static String ROLES_URI = "argeo.node.roles.uri"; + /** URI to an LDIF file or LDAP server used as initialization or backend */ final static String USERADMIN_URI = "argeo.node.useradmin.uri"; final static String[] DEFAULT_CNDS = { "/org/argeo/jcr/argeo.cnd", "/org/argeo/cms/cms.cnd" }; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java index 912d9fa99..579138c0f 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/KernelUtils.java @@ -76,6 +76,7 @@ class KernelUtils implements KernelConstants { } // Security + @Deprecated static void anonymousLogin(AuthenticationManager authenticationManager) { try { List anonAuthorities = Collections diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index f2cffb3ad..aed824fbd 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -8,6 +8,7 @@ import java.security.KeyStore; import java.security.Provider; import java.security.Security; import java.util.Arrays; +import java.util.Hashtable; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; @@ -19,14 +20,10 @@ import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.security.auth.x500.X500Principal; -import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.cms.CmsException; import org.argeo.cms.KernelHeader; -import org.argeo.osgi.useradmin.AbstractUserDirectory; -import org.argeo.osgi.useradmin.LdapUserAdmin; -import org.argeo.osgi.useradmin.LdifUserAdmin; import org.argeo.security.crypto.PkiUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.osgi.framework.BundleContext; @@ -57,14 +54,7 @@ class NodeSecurity implements AuthenticationManager { private final NodeUserAdmin userAdmin; private final Subject kernelSubject; - // private final OsAuthenticationProvider osAuth; - // private final InternalAuthenticationProvider internalAuth; - // private final AnonymousAuthenticationProvider anonymousAuth; - // private final JackrabbitUserAdminService userAdminService; - private ServiceRegistration authenticationManagerReg; - // private ServiceRegistration userAdminServiceReg; - // private ServiceRegistration userDetailsManagerReg; private ServiceRegistration userAdminReg; @@ -77,69 +67,7 @@ class NodeSecurity implements AuthenticationManager { this.bundleContext = bundleContext; this.kernelSubject = logKernel(); - - // osAuth = new OsAuthenticationProvider(); - // internalAuth = new InternalAuthenticationProvider( - // Activator.getSystemKey()); - // anonymousAuth = new AnonymousAuthenticationProvider( - // Activator.getSystemKey()); - - // user admin - // userAdminService = new JackrabbitUserAdminService(); - // userAdminService.setRepository(node); - // userAdminService.setSecurityModel(new SimpleJcrSecurityModel()); - // userAdminService.init(); - userAdmin = new NodeUserAdmin(); - - File osgiInstanceDir = KernelUtils.getOsgiInstanceDir(); - File homeDir = new File(osgiInstanceDir, "node"); - homeDir.mkdirs(); - - String userAdminUri = KernelUtils - .getFrameworkProp(KernelConstants.USERADMIN_URI); - String baseDn = "dc=example,dc=com"; - if (userAdminUri == null) { - File businessRolesFile = new File(homeDir, baseDn + ".ldif"); - // userAdminUri = getClass().getResource(baseDn + - // ".ldif").toString(); - if (!businessRolesFile.exists()) - try { - FileUtils.copyInputStreamToFile(getClass() - .getResourceAsStream(baseDn + ".ldif"), - businessRolesFile); - } catch (IOException e) { - throw new CmsException("Cannot copy demo resource", e); - } - userAdminUri = businessRolesFile.toURI().toString(); - } - - AbstractUserDirectory businessRoles; - if (userAdminUri.startsWith("ldap")) - businessRoles = new LdapUserAdmin(userAdminUri); - else { - businessRoles = new LdifUserAdmin(userAdminUri); - } - businessRoles.init(); - userAdmin.addUserAdmin(baseDn, businessRoles); - - String baseNodeRoleDn = KernelHeader.ROLES_BASEDN; - File nodeRolesFile = new File(homeDir, baseNodeRoleDn + ".ldif"); - if (!nodeRolesFile.exists()) - try { - FileUtils.copyInputStreamToFile( - getClass().getResourceAsStream("demo.ldif"), - nodeRolesFile); - } catch (IOException e) { - throw new CmsException("Cannot copy demo resource", e); - } - LdifUserAdmin nodeRoles = new LdifUserAdmin(nodeRolesFile.toURI() - .toString(), false); - nodeRoles.setExternalRoles(userAdmin); - nodeRoles.init(); - // nodeRoles.createRole(KernelHeader.ROLE_ADMIN, Role.GROUP); - userAdmin.addUserAdmin(baseNodeRoleDn, nodeRoles); - } private Subject logKernel() { @@ -175,25 +103,17 @@ class NodeSecurity implements AuthenticationManager { public void publish() { authenticationManagerReg = bundleContext.registerService( AuthenticationManager.class, this, null); - // userAdminServiceReg = bundleContext.registerService( - // UserAdminService.class, userAdminService, null); - // userDetailsManagerReg = bundleContext.registerService( - // UserDetailsManager.class, userAdminService, null); + Hashtable properties = new Hashtable(); + // properties.put(KernelConstants.USERADMIN_URI, + // userAdmin.asConfigUris()); userAdminReg = bundleContext.registerService(UserAdmin.class, - userAdmin, null); + userAdmin, properties); } void destroy() { - // try { - // userAdminService.destroy(); - // } catch (RepositoryException e) { - // log.error("Error while destroying Jackrabbit useradmin"); - // } - // userDetailsManagerReg.unregister(); - // userAdminServiceReg.unregister(); authenticationManagerReg.unregister(); - // userAdmin.destroy(); + userAdmin.destroy(); userAdminReg.unregister(); // Logout kernel @@ -219,21 +139,9 @@ class NodeSecurity implements AuthenticationManager { @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - log.error("Authentication manager is deprectaed and should not be used."); - // Authentication auth = null; - // if (authentication instanceof InternalAuthentication) - // auth = internalAuth.authenticate(authentication); - // else if (authentication instanceof AnonymousAuthenticationToken) - // auth = anonymousAuth.authenticate(authentication); - // else if (authentication instanceof - // UsernamePasswordAuthenticationToken) - // auth = userAdminService.authenticate(authentication); - // else if (authentication instanceof OsAuthenticationToken) - // auth = osAuth.authenticate(authentication); - // if (auth == null) - // throw new CmsException("Could not authenticate " + authentication); + log.error("Authentication manager is deprecated and should not be used."); throw new ProviderNotFoundException( - "Authentication manager is deprectaed and should not be used."); + "Authentication manager is deprecated and should not be used."); } private void createKeyStoreIfNeeded() { @@ -248,12 +156,10 @@ class NodeSecurity implements AuthenticationManager { PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal(KernelHeader.ROLE_KERNEL), keyPwd); PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore); - } catch (Exception e) { throw new CmsException("Cannot create key store " + keyStoreFile, e); } } } - } 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 9dd516137..e396ca09e 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 @@ -1,7 +1,12 @@ package org.argeo.cms.internal.kernel; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -10,12 +15,17 @@ import java.util.Set; import javax.naming.InvalidNameException; import javax.naming.ldap.LdapName; -import javax.transaction.Transaction; import javax.transaction.TransactionManager; -import javax.transaction.TransactionSynchronizationRegistry; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.cms.CmsException; import org.argeo.cms.KernelHeader; import org.argeo.osgi.useradmin.AbstractUserDirectory; +import org.argeo.osgi.useradmin.LdapProperties; +import org.argeo.osgi.useradmin.LdapUserAdmin; +import org.argeo.osgi.useradmin.LdifUserAdmin; import org.argeo.osgi.useradmin.UserAdminAggregator; import org.argeo.osgi.useradmin.UserDirectoryException; import org.osgi.framework.InvalidSyntaxException; @@ -25,6 +35,7 @@ import org.osgi.service.useradmin.User; import org.osgi.service.useradmin.UserAdmin; public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { + private final static Log log = LogFactory.getLog(NodeUserAdmin.class); final static LdapName ROLES_BASE; static { try { @@ -38,9 +49,125 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { private UserAdmin nodeRoles = null; private Map userAdmins = new HashMap(); - private TransactionSynchronizationRegistry syncRegistry; private TransactionManager transactionManager; + public NodeUserAdmin() { + File osgiInstanceDir = KernelUtils.getOsgiInstanceDir(); + File nodeBaseDir = new File(osgiInstanceDir, "node"); + nodeBaseDir.mkdirs(); + + String userAdminUri = KernelUtils + .getFrameworkProp(KernelConstants.USERADMIN_URI); + if (userAdminUri == null) { + String demoBaseDn = "dc=example,dc=com"; + File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif"); + if (!businessRolesFile.exists()) + try { + FileUtils.copyInputStreamToFile(getClass() + .getResourceAsStream(demoBaseDn + ".ldif"), + businessRolesFile); + } catch (IOException e) { + throw new CmsException("Cannot copy demo resource", e); + } + userAdminUri = businessRolesFile.toURI().toString(); + } + + String[] uris = userAdminUri.split(" "); + for (String uri : uris) { + URI u; + try { + u = new URI(uri); + if (u.getScheme() == null) { + if (uri.startsWith("/")) + u = new File(uri).getAbsoluteFile().toURI(); + else if (!uri.contains("/")) + u = new File(nodeBaseDir, uri).getAbsoluteFile() + .toURI(); + else + throw new CmsException("Cannot interpret " + uri + + " as an uri"); + } + } catch (URISyntaxException e) { + throw new CmsException( + "Cannot interpret " + uri + " as an uri", e); + } + Dictionary properties = LdapProperties.uriAsProperties(u + .toString()); + AbstractUserDirectory businessRoles; + if (u.getScheme().startsWith("ldap")) { + businessRoles = new LdapUserAdmin(properties); + } else { + businessRoles = new LdifUserAdmin(properties); + } + businessRoles.init(); + addUserAdmin(businessRoles.getBaseDn(), businessRoles); + if (log.isDebugEnabled()) + log.debug("User directory " + businessRoles.getBaseDn() + " [" + + u.getScheme() + "] enabled."); + } + + // NOde roles + String nodeRolesUri = KernelUtils + .getFrameworkProp(KernelConstants.ROLES_URI); + String baseNodeRoleDn = KernelHeader.ROLES_BASEDN; + if (nodeRolesUri == null) { + File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif"); + if (!nodeRolesFile.exists()) + try { + FileUtils.copyInputStreamToFile(getClass() + .getResourceAsStream("demo.ldif"), nodeRolesFile); + } catch (IOException e) { + throw new CmsException("Cannot copy demo resource", e); + } + nodeRolesUri = nodeRolesFile.toURI().toString(); + } + + Dictionary nodeRolesProperties = LdapProperties + .uriAsProperties(nodeRolesUri); + if (!nodeRolesProperties.get(LdapProperties.baseDn.getFullName()) + .equals(baseNodeRoleDn)) { + throw new CmsException("Invalid base dn for node roles"); + // TODO deal with "mounted" roles with a different baseDN + } + AbstractUserDirectory nodeRoles; + if (nodeRolesUri.startsWith("ldap")) { + nodeRoles = new LdapUserAdmin(nodeRolesProperties); + } else { + nodeRoles = new LdifUserAdmin(nodeRolesProperties); + } + nodeRoles.setExternalRoles(this); + nodeRoles.init(); + addUserAdmin(baseNodeRoleDn, nodeRoles); + if (log.isTraceEnabled()) + log.trace("Node roles enabled."); + } + + String asConfigUris() { + StringBuilder buf = new StringBuilder(); + for (LdapName name : userAdmins.keySet()) { + buf.append('/').append(name.toString()); + if (userAdmins.get(name) instanceof AbstractUserDirectory) { + AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins + .get(name); + if (userDirectory.isReadOnly()) + buf.append('?').append(LdapProperties.readOnly.name()) + .append("=true"); + } + buf.append(' '); + } + return buf.toString(); + } + + public void destroy() { + for (LdapName name : userAdmins.keySet()) { + if (userAdmins.get(name) instanceof AbstractUserDirectory) { + AbstractUserDirectory userDirectory = (AbstractUserDirectory) userAdmins + .get(name); + userDirectory.destroy(); + } + } + } + @Override public Role createRole(String name, int type) { return findUserAdmin(name).createRole(name, type); @@ -99,9 +226,6 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { // @Override public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) { - if (userAdmin instanceof AbstractUserDirectory) - ((AbstractUserDirectory) userAdmin).setSyncRegistry(syncRegistry); - if (baseDn.equals(KernelHeader.ROLES_BASEDN)) { nodeRoles = userAdmin; return; @@ -132,9 +256,7 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { if (!userAdmins.containsKey(base)) throw new UserDirectoryException("There is no user admin for " + base); - UserAdmin userAdmin = userAdmins.remove(base); - if (userAdmin instanceof AbstractUserDirectory) - ((AbstractUserDirectory) userAdmin).setSyncRegistry(null); + userAdmins.remove(base); } private UserAdmin findUserAdmin(String name) { @@ -173,16 +295,4 @@ public class NodeUserAdmin implements UserAdmin, UserAdminAggregator { .setTransactionManager(transactionManager); } } - - public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) { - this.syncRegistry = syncRegistry; - if (nodeRoles instanceof AbstractUserDirectory) - ((AbstractUserDirectory) nodeRoles).setSyncRegistry(syncRegistry); - for (UserAdmin userAdmin : userAdmins.values()) { - if (userAdmin instanceof AbstractUserDirectory) - ((AbstractUserDirectory) userAdmin) - .setSyncRegistry(syncRegistry); - } - } - } diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java index d034e2233..c7448b574 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/AbstractUserDirectory.java @@ -1,8 +1,17 @@ package org.argeo.osgi.useradmin; +import static org.argeo.osgi.useradmin.LdifName.inetOrgPerson; +import static org.argeo.osgi.useradmin.LdifName.objectClass; +import static org.argeo.osgi.useradmin.LdifName.organizationalPerson; +import static org.argeo.osgi.useradmin.LdifName.person; +import static org.argeo.osgi.useradmin.LdifName.top; + +import java.io.File; import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Dictionary; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -36,6 +45,12 @@ import org.osgi.service.useradmin.UserAdmin; public abstract class AbstractUserDirectory implements UserAdmin { private final static Log log = LogFactory .getLog(AbstractUserDirectory.class); + + private Dictionary properties; + private String baseDn = "dc=example,dc=com"; + private String userObjectClass; + private String groupObjectClass; + private boolean isReadOnly; private URI uri; @@ -54,14 +69,38 @@ public abstract class AbstractUserDirectory implements UserAdmin { private ThreadLocal workingCopy = new ThreadLocal(); private Xid editingTransactionXid = null; - public AbstractUserDirectory() { - } + public AbstractUserDirectory(Dictionary properties) { + // TODO make a copy? + this.properties = properties; - public AbstractUserDirectory(URI uri, boolean isReadOnly) { - this.uri = uri; - this.isReadOnly = isReadOnly; + String uriStr = LdapProperties.uri.getValue(properties); + if (uriStr == null) + uri = null; + else + try { + uri = new URI(uriStr); + } catch (URISyntaxException e) { + throw new UserDirectoryException("Badly formatted URI", e); + } + + baseDn = LdapProperties.baseDn.getValue(properties).toString(); + String isReadOnly = LdapProperties.readOnly.getValue(properties); + if (isReadOnly == null) + this.isReadOnly = readOnlyDefault(uri); + else + this.isReadOnly = new Boolean(isReadOnly); + + this.userObjectClass = LdapProperties.userObjectClass + .getValue(properties); + this.groupObjectClass = LdapProperties.groupObjectClass + .getValue(properties); } + // public AbstractUserDirectory(URI uri, boolean isReadOnly) { + // this.uri = uri; + // this.isReadOnly = isReadOnly; + // } + /** Returns the {@link Group}s this user is a direct member of. */ protected abstract List getDirectGroups(User user); @@ -250,18 +289,23 @@ public abstract class AbstractUserDirectory implements UserAdmin { protected DirectoryUser newRole(LdapName dn, int type, Attributes attrs) { LdifUser newRole; - BasicAttribute objectClass = new BasicAttribute("objectClass"); + BasicAttribute objClass = new BasicAttribute(objectClass.name()); if (type == Role.USER) { - objectClass.add("inetOrgPerson"); - objectClass.add("organizationalPerson"); - objectClass.add("person"); - objectClass.add("top"); - attrs.put(objectClass); + String userObjClass = getUserObjectClass(); + objClass.add(userObjClass); + if (inetOrgPerson.name().equals(userObjClass)) { + objClass.add(organizationalPerson.name()); + objClass.add(person.name()); + } else if (organizationalPerson.name().equals(userObjClass)) { + objClass.add(person.name()); + } + objClass.add(top); + attrs.put(objClass); newRole = new LdifUser(this, dn, attrs); } else if (type == Role.GROUP) { - objectClass.add("groupOfNames"); - objectClass.add("top"); - attrs.put(objectClass); + objClass.add(getGroupObjectClass()); + objClass.add(top); + attrs.put(objClass); newRole = new LdifGroup(this, dn, attrs); } else throw new UserDirectoryException("Unsupported type " + type); @@ -337,6 +381,16 @@ public abstract class AbstractUserDirectory implements UserAdmin { this.isReadOnly = isReadOnly; } + private static boolean readOnlyDefault(URI uri) { + if (uri == null) + return true; + if (uri.getScheme().equals("file")) { + File file = new File(uri); + return !file.canWrite(); + } + return true; + } + public boolean isReadOnly() { return isReadOnly; } @@ -345,12 +399,20 @@ public abstract class AbstractUserDirectory implements UserAdmin { return externalRoles; } - public void setExternalRoles(UserAdmin externalRoles) { - this.externalRoles = externalRoles; + public String getBaseDn() { + return baseDn; } - public void setSyncRegistry(TransactionSynchronizationRegistry syncRegistry) { - // this.syncRegistry = syncRegistry; + protected String getUserObjectClass() { + return userObjectClass; + } + + protected String getGroupObjectClass() { + return groupObjectClass; + } + + public void setExternalRoles(UserAdmin externalRoles) { + this.externalRoles = externalRoles; } public void setTransactionManager(TransactionManager transactionManager) { diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java deleted file mode 100644 index 62f4b2b37..000000000 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapNames.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.argeo.osgi.useradmin; - -/** - * Standard LDAP attributes and object classes leverages in ths implementation - * of user admin. - */ -public interface LdapNames { - public final static String LDAP_PREFIX = "ldap:"; - - // Attributes - public final static String LDAP_CN = LDAP_PREFIX + "cn"; - public final static String LDAP_SN = LDAP_PREFIX + "sn"; - public final static String LDAP_UID = LDAP_PREFIX + "uid"; - public final static String LDAP_DISPLAY_NAME = LDAP_PREFIX + "displayName"; - -} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java new file mode 100644 index 000000000..749c8fe84 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapProperties.java @@ -0,0 +1,148 @@ +package org.argeo.osgi.useradmin; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.naming.Context; + +public enum LdapProperties { + /** Base DN */ + baseDn("dc=example,dc=com"), + + /** URI of the underlying resource */ + uri("ldap://localhost:10389"), + + /** User objectClass */ + userObjectClass("inetOrgPerson"), + + /** Groups objectClass */ + groupObjectClass("groupOfNames"), + + /** Read-only source */ + readOnly(null); + + private static String PREFIX = "argeo.ldap."; + + /** The default value. */ + private Object def; + + LdapProperties(Object def) { + this.def = def; + } + + public Object getDefault() { + return def; + } + + public String getFullName() { + return getPrefix() + name(); + } + + public String getPrefix() { + return PREFIX; + } + + public String getValue(Dictionary properties) { + Object res = getRawValue(properties); + if (res == null) + return null; + return res.toString(); + } + + @SuppressWarnings("unchecked") + public T getRawValue(Dictionary properties) { + Object res = properties.get(getFullName()); + if (res == null) + res = getDefault(); + return (T) res; + } + + public static Dictionary uriAsProperties(String uriStr) { + try { + Hashtable res = new Hashtable(); + URI u = new URI(uriStr); + String scheme = u.getScheme(); + String path = u.getPath(); + String bDn = path.substring(path.lastIndexOf('/') + 1, + path.length()); + String principal = null; + String credentials = null; + if (scheme != null) + if (scheme.equals("ldap") || scheme.equals("ldaps")) { + // TODO additional checks + String[] userInfo = u.getUserInfo().split(":"); + principal = userInfo.length > 0 ? userInfo[0] : null; + credentials = userInfo.length > 1 ? userInfo[1] : null; + } else if (scheme.equals("file")) { + if (bDn.endsWith(".ldif")) { + bDn = bDn.substring(0, bDn.length() - ".ldif".length()); + } + } else + throw new UserDirectoryException("Unsupported scheme " + + scheme); + Map> query = splitQuery(u.getQuery()); + for (String key : query.keySet()) { + LdapProperties ldapProp = LdapProperties.valueOf(key); + List values = query.get(key); + if (values.size() == 1) { + res.put(ldapProp.getFullName(), values.get(0)); + } else { + throw new UserDirectoryException( + "Only single values are supported"); + } + } + res.put(baseDn.getFullName(), bDn); + if (principal != null) + res.put(Context.SECURITY_PRINCIPAL, principal); + if (credentials != null) + res.put(Context.SECURITY_CREDENTIALS, credentials); + if (scheme != null) { + URI bareUri = new URI(scheme, null, u.getHost(), u.getPort(), + scheme.equals("file") ? u.getPath() : null, null, null); + res.put(uri.getFullName(), bareUri.toString()); + } + return res; + } catch (Exception e) { + throw new UserDirectoryException("Cannot convert " + uri + + " to properties", e); + } + } + + public static Map> splitQuery(String query) + throws UnsupportedEncodingException { + final Map> query_pairs = new LinkedHashMap>(); + 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()); + } + 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) { + System.out.println(uriAsProperties("ldap://" + + "uid=admin,ou=system:secret@localhost:10389" + + "/dc=example,dc=com" + + "?readOnly=false&userObjectClass=person")); + System.out + .println(uriAsProperties("file://some/dir/dc=example,dc=com.ldif")); + System.out + .println(uriAsProperties("/dc=example,dc=com.ldif?readOnly=true")); + } +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java index 0cb435f07..7129cfb56 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdapUserAdmin.java @@ -1,7 +1,9 @@ package org.argeo.osgi.useradmin; -import java.net.URI; +import static org.argeo.osgi.useradmin.LdifName.objectClass; + import java.util.ArrayList; +import java.util.Dictionary; import java.util.Hashtable; import java.util.List; @@ -12,42 +14,31 @@ import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; import javax.naming.ldap.InitialLdapContext; -import javax.naming.ldap.LdapContext; import javax.naming.ldap.LdapName; -import javax.transaction.xa.XAException; -import javax.transaction.xa.Xid; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; import org.osgi.framework.Filter; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.service.useradmin.Authorization; -import org.osgi.service.useradmin.Group; -import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; public class LdapUserAdmin extends AbstractUserDirectory { private final static Log log = LogFactory.getLog(LdapUserAdmin.class); - private String baseDn = "dc=example,dc=com"; private InitialLdapContext initialLdapContext = null; - public LdapUserAdmin(String uri) { + public LdapUserAdmin(Dictionary properties) { + super(properties); try { - setUri(new URI(uri)); Hashtable connEnv = new Hashtable(); connEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); connEnv.put(Context.PROVIDER_URL, getUri().toString()); - connEnv.put("java.naming.ldap.attributes.binary", "userPassword"); - // connEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); - // connEnv.put(Context.SECURITY_PRINCIPAL, "uid=admin,ou=system"); - // connEnv.put(Context.SECURITY_CREDENTIALS, "secret"); + connEnv.put("java.naming.ldap.attributes.binary", + LdifName.userPassword.name()); initialLdapContext = new InitialLdapContext(connEnv, null); // StartTlsResponse tls = (StartTlsResponse) ctx @@ -55,14 +46,21 @@ public class LdapUserAdmin extends AbstractUserDirectory { // tls.negotiate(); initialLdapContext.addToEnvironment( Context.SECURITY_AUTHENTICATION, "simple"); - initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, - "uid=admin,ou=system"); - initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, - "secret"); - LdapContext ldapContext = (LdapContext) initialLdapContext - .lookup("uid=root,ou=users,dc=example,dc=com"); - log.debug(initialLdapContext.getAttributes( - "uid=root,ou=users,dc=example,dc=com").get("cn")); + Object principal = properties.get(Context.SECURITY_PRINCIPAL); + if (principal != null) { + initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, + principal.toString()); + Object creds = properties.get(Context.SECURITY_CREDENTIALS); + if (creds != null) { + initialLdapContext.addToEnvironment( + Context.SECURITY_CREDENTIALS, creds.toString()); + + } + } + // initialLdapContext.addToEnvironment(Context.SECURITY_PRINCIPAL, + // "uid=admin,ou=system"); + // initialLdapContext.addToEnvironment(Context.SECURITY_CREDENTIALS, + // "secret"); } catch (Exception e) { throw new UserDirectoryException("Cannot connect to LDAP", e); } @@ -77,6 +75,10 @@ public class LdapUserAdmin extends AbstractUserDirectory { } } + protected InitialLdapContext getLdapContext() { + return initialLdapContext; + } + @Override protected Boolean daoHasRole(LdapName dn) { return daoGetRole(dn) != null; @@ -85,13 +87,14 @@ public class LdapUserAdmin extends AbstractUserDirectory { @Override protected DirectoryUser daoGetRole(LdapName name) { try { - Attributes attrs = initialLdapContext.getAttributes(name); + Attributes attrs = getLdapContext().getAttributes(name); if (attrs.size() == 0) return null; LdifUser res; - if (attrs.get("objectClass").contains("groupOfNames")) + if (attrs.get(objectClass.name()).contains(getGroupObjectClass())) res = new LdifGroup(this, name, attrs); - else if (attrs.get("objectClass").contains("inetOrgPerson")) + else if (attrs.get(objectClass.name()).contains( + getUserObjectClass())) res = new LdifUser(this, name, attrs); else throw new UserDirectoryException("Unsupported LDAP type for " @@ -106,24 +109,27 @@ public class LdapUserAdmin extends AbstractUserDirectory { protected List doGetRoles(Filter f) { // TODO Auto-generated method stub try { - String searchFilter = f != null ? f.toString() - : "(|(objectClass=inetOrgPerson)(objectClass=groupOfNames))"; + String searchFilter = f != null ? f.toString() : "(|(" + + objectClass + "=" + getUserObjectClass() + ")(" + + objectClass + "=" + getGroupObjectClass() + "))"; SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - String searchBase = baseDn; - NamingEnumeration results = initialLdapContext - .search(searchBase, searchFilter, searchControls); + String searchBase = getBaseDn(); + NamingEnumeration results = getLdapContext().search( + searchBase, searchFilter, searchControls); ArrayList res = new ArrayList(); while (results.hasMoreElements()) { SearchResult searchResult = results.next(); Attributes attrs = searchResult.getAttributes(); LdifUser role; - if (attrs.get("objectClass").contains("groupOfNames")) + if (attrs.get(objectClass.name()).contains( + getGroupObjectClass())) role = new LdifGroup(this, toDn(searchBase, searchResult), attrs); - else if (attrs.get("objectClass").contains("inetOrgPerson")) + else if (attrs.get(objectClass.name()).contains( + getUserObjectClass())) role = new LdifUser(this, toDn(searchBase, searchResult), attrs); else @@ -143,15 +149,15 @@ public class LdapUserAdmin extends AbstractUserDirectory { protected void doGetUser(String key, String value, List collectedUsers) { try { - String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "=" - + value + "))"; + String searchFilter = "(&(" + objectClass + "=" + + getUserObjectClass() + ")(" + key + "=" + value + "))"; SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - String searchBase = baseDn; - NamingEnumeration results = initialLdapContext - .search(searchBase, searchFilter, searchControls); + String searchBase = getBaseDn(); + NamingEnumeration results = getLdapContext().search( + searchBase, searchFilter, searchControls); SearchResult searchResult = null; if (results.hasMoreElements()) { @@ -169,96 +175,26 @@ public class LdapUserAdmin extends AbstractUserDirectory { } - @Override - public User getUser(String key, String value) { - if (key == null) { - List users = new ArrayList(); - for (String prop : getIndexedUserProperties()) { - User user = getUser(prop, value); - if (user != null) - users.add(user); - } - if (users.size() == 1) - return users.get(0); - else - return null; - } - - try { - String searchFilter = "(&(objectClass=inetOrgPerson)(" + key + "=" - + value + "))"; - - SearchControls searchControls = new SearchControls(); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - - String searchBase = baseDn; - NamingEnumeration results = initialLdapContext - .search(searchBase, searchFilter, searchControls); - - SearchResult searchResult = null; - if (results.hasMoreElements()) { - searchResult = (SearchResult) results.nextElement(); - if (results.hasMoreElements()) - searchResult = null; - } - if (searchResult == null) - return null; - return new LdifUser(this, toDn(searchBase, searchResult), - searchResult.getAttributes()); - } catch (Exception e) { - throw new UserDirectoryException("Cannot get user with " + key - + "=" + value, e); - } - } - private LdapName toDn(String baseDn, Binding binding) throws InvalidNameException { return new LdapName(binding.isRelative() ? binding.getName() + "," + baseDn : binding.getName()); } - // void populateDirectMemberOf(LdifUser user) { - // - // try { - // String searchFilter = "(&(objectClass=groupOfNames)(member=" - // + user.getName() + "))"; - // - // SearchControls searchControls = new SearchControls(); - // searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - // - // String searchBase = "ou=node"; - // NamingEnumeration results = initialLdapContext - // .search(searchBase, searchFilter, searchControls); - // - // // TODO synchro - // //user.directMemberOf.clear(); - // while (results.hasMoreElements()) { - // SearchResult searchResult = (SearchResult) results - // .nextElement(); - // LdifGroup group = new LdifGroup(toDn(searchBase, searchResult), - // searchResult.getAttributes()); - // populateDirectMemberOf(group); - // //user.directMemberOf.add(group); - // } - // } catch (Exception e) { - // throw new ArgeoException("Cannot populate direct members of " - // + user, e); - // } - // } - @Override protected List getDirectGroups(User user) { List directGroups = new ArrayList(); try { - String searchFilter = "(&(objectClass=groupOfNames)(member=" - + user.getName() + "))"; + String searchFilter = "(&(" + objectClass + "=" + + getGroupObjectClass() + ")(" + getMemberAttributeId() + + "=" + user.getName() + "))"; SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - String searchBase = getGroupsSearchBase(); - NamingEnumeration results = initialLdapContext - .search(searchBase, searchFilter, searchControls); + String searchBase = getBaseDn(); + NamingEnumeration results = getLdapContext().search( + searchBase, searchFilter, searchControls); while (results.hasMoreElements()) { SearchResult searchResult = (SearchResult) results @@ -274,16 +210,10 @@ public class LdapUserAdmin extends AbstractUserDirectory { } } - protected String getGroupsSearchBase() { - // TODO configure group search base - return baseDn; - } - @Override protected void prepare(WorkingCopy wc) { try { - initialLdapContext.reconnect(initialLdapContext - .getConnectControls()); + getLdapContext().reconnect(getLdapContext().getConnectControls()); // delete for (LdapName dn : wc.getDeletedUsers().keySet()) { if (!entryExists(dn)) @@ -308,7 +238,7 @@ public class LdapUserAdmin extends AbstractUserDirectory { } private boolean entryExists(LdapName dn) throws NamingException { - return initialLdapContext.getAttributes(dn).size() != 0; + return getLdapContext().getAttributes(dn).size() != 0; } @Override @@ -316,17 +246,17 @@ public class LdapUserAdmin extends AbstractUserDirectory { try { // delete for (LdapName dn : wc.getDeletedUsers().keySet()) { - initialLdapContext.destroySubcontext(dn); + getLdapContext().destroySubcontext(dn); } // add for (LdapName dn : wc.getNewUsers().keySet()) { DirectoryUser user = wc.getNewUsers().get(dn); - initialLdapContext.createSubcontext(dn, user.getAttributes()); + getLdapContext().createSubcontext(dn, user.getAttributes()); } // modify for (LdapName dn : wc.getModifiedUsers().keySet()) { Attributes modifiedAttrs = wc.getModifiedUsers().get(dn); - initialLdapContext.modifyAttributes(dn, + getLdapContext().modifyAttributes(dn, DirContext.REPLACE_ATTRIBUTE, modifiedAttrs); } } catch (NamingException e) { @@ -336,8 +266,7 @@ public class LdapUserAdmin extends AbstractUserDirectory { @Override protected void rollback(WorkingCopy wc) { - // TODO Auto-generated method stub - super.rollback(wc); + // prepare not impacting } } diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifAuthorization.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifAuthorization.java index 845fefd13..3a2aeca2e 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifAuthorization.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifAuthorization.java @@ -9,7 +9,7 @@ import org.osgi.service.useradmin.Authorization; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; -public class LdifAuthorization implements Authorization, LdapNames { +public class LdifAuthorization implements Authorization { private final String name; private final String displayName; private final List allRoles; @@ -21,16 +21,16 @@ public class LdifAuthorization implements Authorization, LdapNames { } else { this.name = user.getName(); Dictionary props = user.getProperties(); - Object displayName = props.get(LDAP_DISPLAY_NAME); + Object displayName = props.get(LdifName.displayName); if (displayName == null) - displayName = props.get(LDAP_CN); + displayName = props.get(LdifName.cn); if (displayName == null) - displayName = props.get(LDAP_UID); + displayName = props.get(LdifName.uid); if (displayName == null) displayName = user.getName(); if (displayName == null) - throw new UserDirectoryException( - "Cannot set display name for " + user); + throw new UserDirectoryException("Cannot set display name for " + + user); this.displayName = displayName.toString(); } // roles diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java new file mode 100644 index 000000000..2614b6fa5 --- /dev/null +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifName.java @@ -0,0 +1,26 @@ +package org.argeo.osgi.useradmin; + +import javax.naming.ldap.LdapName; + +/** + * Standard LDAP attributes and object classes leveraged in this implementation + * of user admin. Named {@link LdifName} in order not to collide with + * {@link LdapName}. + */ +public enum LdifName { + // Attributes + cn, sn, uid, displayName, objectClass,userPassword, + // Object classes + inetOrgPerson, organizationalPerson, person, groupOfNames, top; + + public final static String LDAP_PREFIX = "ldap:"; + + public String property() { + return LDAP_PREFIX + name(); + } + + public static LdifName local(String property) { + String local = property.substring(LDAP_PREFIX.length()); + return LdifName.valueOf(local); + } +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java index 608a1f751..9bf558b31 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/LdifUserAdmin.java @@ -5,10 +5,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Dictionary; +import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -32,58 +31,35 @@ public class LdifUserAdmin extends AbstractUserDirectory { private Map> userIndexes = new LinkedHashMap>(); - // private Map> directMemberOf = new - // TreeMap>(); - - public LdifUserAdmin(String uri) { - this(uri, readOnlyDefault(uri)); - } - - public LdifUserAdmin(String uri, boolean isReadOnly) { - setReadOnly(isReadOnly); - try { - setUri(new URI(uri)); - } catch (URISyntaxException e) { - throw new UserDirectoryException("Invalid URI " + uri, e); - } - - if (!isReadOnly && !getUri().getScheme().equals("file")) - throw new UnsupportedOperationException(getUri().getScheme() - + " not supported read-write."); - + public LdifUserAdmin(String uri, String baseDn) { + this(fromUri(uri, baseDn)); } - public LdifUserAdmin(URI uri, boolean isReadOnly) { - setReadOnly(isReadOnly); - setUri(uri); - if (!isReadOnly && !getUri().getScheme().equals("file")) - throw new UnsupportedOperationException(getUri().getScheme() - + " not supported read-write."); - + public LdifUserAdmin(Dictionary properties) { + super(properties); } public LdifUserAdmin(InputStream in) { + super(new Hashtable()); load(in); setReadOnly(true); setUri(null); } - private static boolean readOnlyDefault(String uriStr) { - URI uri; - try { - uri = new URI(uriStr); - } catch (Exception e) { - throw new UserDirectoryException("Invalid URI " + uriStr, e); - } - if (uri.getScheme().equals("file")) { - File file = new File(uri); - return !file.canWrite(); - } - return true; + private static Dictionary fromUri(String uri, String baseDn) { + Hashtable res = new Hashtable(); + res.put(LdapProperties.uri.getFullName(), uri); + res.put(LdapProperties.baseDn.getFullName(), baseDn); + return res; } public void init() { try { + if (getUri().getScheme().equals("file")) { + File file = new File(getUri()); + if (!file.exists()) + return; + } load(getUri().toURL().openStream()); } catch (Exception e) { throw new UserDirectoryException("Cannot open URL " + getUri(), e); diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java deleted file mode 100644 index 42338b2af..000000000 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/cm/LdapUserAdminFactory.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.argeo.osgi.useradmin.cm; - -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Map; - -import org.argeo.osgi.useradmin.AbstractUserDirectory; -import org.argeo.osgi.useradmin.UserDirectoryException; -import org.argeo.osgi.useradmin.LdapUserAdmin; -import org.argeo.osgi.useradmin.LdifUserAdmin; -import org.argeo.osgi.useradmin.UserAdminAggregator; -import org.osgi.service.cm.ConfigurationException; -import org.osgi.service.cm.ManagedServiceFactory; - -public class LdapUserAdminFactory implements ManagedServiceFactory { - private final UserAdminAggregator userAdminAggregator; - - private Map index = new HashMap(); - - public LdapUserAdminFactory(UserAdminAggregator userAdminAggregator) { - this.userAdminAggregator = userAdminAggregator; - } - - @Override - public String getName() { - return "LDAP/LDIF User Source"; - } - - @Override - public synchronized void updated(String pid, - Dictionary properties) throws ConfigurationException { - String baseDn = properties.get("baseDn").toString(); - String userAdminUri = properties.get("uri").toString(); - AbstractUserDirectory userAdmin; - if (userAdminUri.startsWith("ldap")) - userAdmin = new LdapUserAdmin(userAdminUri); - else - userAdmin = new LdifUserAdmin(userAdminUri); - userAdminAggregator.addUserAdmin(baseDn, userAdmin); - index.put(pid, baseDn); - } - - @Override - public synchronized void deleted(String pid) { - if (index.containsKey(pid)) - userAdminAggregator.removeUserAdmin(index.get(pid)); - else - throw new UserDirectoryException("No user admin registered for " - + pid); - index.remove(pid); - } - -} diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java index 06e9bd5b9..f9c0ad9af 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/SecurityAdminPlugin.java @@ -22,6 +22,7 @@ import org.osgi.framework.BundleContext; public class SecurityAdminPlugin extends AbstractUIPlugin { public static final String PLUGIN_ID = "org.argeo.security.ui.admin"; //$NON-NLS-1$ private static SecurityAdminPlugin plugin; + private static BundleContext bundleContext; public SecurityAdminPlugin() { } @@ -29,10 +30,12 @@ public class SecurityAdminPlugin extends AbstractUIPlugin { public void start(BundleContext context) throws Exception { super.start(context); plugin = this; + bundleContext = context; } public void stop(BundleContext context) throws Exception { plugin = null; + bundleContext = null; super.stop(context); } @@ -40,6 +43,10 @@ public class SecurityAdminPlugin extends AbstractUIPlugin { return plugin; } + public static BundleContext getBundleContext() { + return bundleContext; + } + public static ImageDescriptor getImageDescriptor(String path) { return imageDescriptorFromPlugin(PLUGIN_ID, path); }