diff options
author | Eike Stepper | 2021-02-06 16:22:57 +0000 |
---|---|---|
committer | Eike Stepper | 2021-02-06 16:22:57 +0000 |
commit | 9b95e35ecb3b96137e06f502ca2f1144d4d74c48 (patch) | |
tree | f303d5408888cc2bd6fe0ac397b842895196bffc | |
parent | 90b818a6b5dec111b873c552f592ee157ebf42bd (diff) | |
download | cdo-committers/estepper/multi-security.tar.gz cdo-committers/estepper/multi-security.tar.xz cdo-committers/estepper/multi-security.zip |
[Prototype] Multitenant SecurityManagercommitters/estepper/multi-security
13 files changed, 495 insertions, 295 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/model/CDOModelUtil.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/model/CDOModelUtil.java index 5d3a523ddf..a8e27a2aa7 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/model/CDOModelUtil.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/model/CDOModelUtil.java @@ -14,6 +14,7 @@ package org.eclipse.emf.cdo.common.model; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit.State; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.util.CDOException; import org.eclipse.emf.cdo.internal.common.bundle.OM; @@ -23,6 +24,7 @@ import org.eclipse.emf.cdo.internal.common.model.CDOPackageInfoImpl; import org.eclipse.emf.cdo.internal.common.model.CDOPackageRegistryImpl; import org.eclipse.emf.cdo.internal.common.model.CDOPackageUnitImpl; import org.eclipse.emf.cdo.internal.common.model.CDOTypeImpl; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.net4j.util.io.ExtendedDataInput; @@ -589,6 +591,34 @@ public final class CDOModelUtil implements CDOModelConstants } /** + * @since 4.13 + */ + public static CDOPackageUnit copyPackageUnit(CDOPackageUnit packageUnit) + { + InternalCDOPackageUnit newPackageUnit = (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); + newPackageUnit.setOriginalType(packageUnit.getOriginalType()); + newPackageUnit.setTimeStamp(packageUnit.getTimeStamp()); + newPackageUnit.setState(State.LOADED); + + InternalCDOPackageInfo[] packageInfos = (InternalCDOPackageInfo[])packageUnit.getPackageInfos(); + InternalCDOPackageInfo[] newPackageInfos = new InternalCDOPackageInfo[packageInfos.length]; + + for (int i = 0; i < packageInfos.length; i++) + { + InternalCDOPackageInfo packageInfo = packageInfos[i]; + + newPackageInfos[i] = (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); + newPackageInfos[i].setPackageUnit(newPackageUnit); + newPackageInfos[i].setEPackage(packageInfo.getEPackage()); + newPackageInfos[i].setPackageURI(packageInfo.getPackageURI()); + newPackageInfos[i].setParentURI(packageInfo.getParentURI()); + } + + newPackageUnit.setPackageInfos(newPackageInfos); + return newPackageUnit; + } + + /** * @since 2.0 */ public static CDOPackageUnit createPackageUnit() diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java index da71cc2c08..b3156c3abc 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/model/CDOPackageRegistryImpl.java @@ -261,6 +261,7 @@ public class CDOPackageRegistryImpl extends EPackageRegistryImpl implements Inte { LifecycleUtil.checkActive(this); packageUnit.setPackageRegistry(this); + for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos()) { EPackage ePackage = packageInfo.getEPackage(false); diff --git a/plugins/org.eclipse.emf.cdo.security/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.security/META-INF/MANIFEST.MF index c11406deed..271742656a 100644 --- a/plugins/org.eclipse.emf.cdo.security/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.security/META-INF/MANIFEST.MF @@ -2,22 +2,22 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.emf.cdo.security;singleton:=true -Bundle-Version: 4.4.1.qualifier +Bundle-Version: 4.4.2.qualifier Bundle-ClassPath: . Bundle-Vendor: %providerName Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Export-Package: org.eclipse.emf.cdo.internal.security;version="4.4.1"; +Export-Package: org.eclipse.emf.cdo.internal.security;version="4.4.2"; x-friends:="org.eclipse.emf.cdo.security.edit, org.eclipse.emf.cdo.security.editor, org.eclipse.emf.cdo.server.security, org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.tests.db, org.eclipse.emf.cdo.tests.mongodb", - org.eclipse.emf.cdo.internal.security.bundle;version="4.4.1";x-internal:=true, - org.eclipse.emf.cdo.security;version="4.4.1", - org.eclipse.emf.cdo.security.impl;version="4.4.1", - org.eclipse.emf.cdo.security.util;version="4.4.1" + org.eclipse.emf.cdo.internal.security.bundle;version="4.4.2";x-internal:=true, + org.eclipse.emf.cdo.security;version="4.4.2", + org.eclipse.emf.cdo.security.impl;version="4.4.2", + org.eclipse.emf.cdo.security.util;version="4.4.2" Require-Bundle: org.eclipse.emf.cdo;bundle-version="[4.1.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.expressions;bundle-version="[4.3.0,5.0.0)";visibility:=reexport Bundle-ActivationPolicy: lazy diff --git a/plugins/org.eclipse.emf.cdo.security/pom.xml b/plugins/org.eclipse.emf.cdo.security/pom.xml index 58f4a44e07..7f830c5f28 100644 --- a/plugins/org.eclipse.emf.cdo.security/pom.xml +++ b/plugins/org.eclipse.emf.cdo.security/pom.xml @@ -25,7 +25,7 @@ <groupId>org.eclipse.emf.cdo</groupId> <artifactId>org.eclipse.emf.cdo.security</artifactId> - <version>4.4.1-SNAPSHOT</version> + <version>4.4.2-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/internal/security/ViewCreator.java b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/internal/security/ViewCreator.java index d5bffab34c..304c7ac052 100644 --- a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/internal/security/ViewCreator.java +++ b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/internal/security/ViewCreator.java @@ -16,6 +16,7 @@ import org.eclipse.emf.cdo.view.CDOView; /** * @author Eike Stepper */ +@FunctionalInterface public interface ViewCreator { public CDOView createView(CDORevisionProvider revisionProvider); diff --git a/plugins/org.eclipse.emf.cdo.server.security/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.security/META-INF/MANIFEST.MF index 1a4bfdf412..8bc1d0c2bc 100644 --- a/plugins/org.eclipse.emf.cdo.server.security/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server.security/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.server.security;singleton:=true Bundle-Name: %pluginName -Bundle-Version: 4.5.0.qualifier +Bundle-Version: 4.6.0.qualifier Bundle-ClassPath: . Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -12,13 +12,13 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", org.eclipse.emf.cdo.security;bundle-version="[4.1.0,5.0.0)", org.eclipse.emf.cdo.net4j;bundle-version="[4.1.0,5.0.0)", org.eclipse.net4j.jvm;bundle-version="[4.1.0,5.0.0)" -Export-Package: org.eclipse.emf.cdo.server.internal.security;version="4.5.0"; +Export-Package: org.eclipse.emf.cdo.server.internal.security;version="4.6.0"; x-friends:="org.eclipse.emf.cdo.tests, org.eclipse.emf.cdo.tests.db, org.eclipse.emf.cdo.tests.mongodb", - org.eclipse.emf.cdo.server.internal.security.bundle;version="4.5.0";x-internal:=true, - org.eclipse.emf.cdo.server.security;version="4.5.0", - org.eclipse.emf.cdo.server.spi.security;version="4.5.0" + org.eclipse.emf.cdo.server.internal.security.bundle;version="4.6.0";x-internal:=true, + org.eclipse.emf.cdo.server.security;version="4.6.0", + org.eclipse.emf.cdo.server.spi.security;version="4.6.0" Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.emf.cdo.server.internal.security.bundle.OM$Activator Automatic-Module-Name: org.eclipse.emf.cdo.server.security diff --git a/plugins/org.eclipse.emf.cdo.server.security/pom.xml b/plugins/org.eclipse.emf.cdo.server.security/pom.xml index 5fd8edb971..1951fa1c16 100644 --- a/plugins/org.eclipse.emf.cdo.server.security/pom.xml +++ b/plugins/org.eclipse.emf.cdo.server.security/pom.xml @@ -25,7 +25,7 @@ <groupId>org.eclipse.emf.cdo</groupId> <artifactId>org.eclipse.emf.cdo.server.security</artifactId> - <version>4.5.0-SNAPSHOT</version> + <version>4.6.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java index ebffb83206..d071268bea 100644 --- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java +++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityManager.java @@ -17,6 +17,8 @@ package org.eclipse.emf.cdo.server.internal.security; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.protocol.CDOProtocol.CommitNotificationInfo; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionProvider; @@ -47,10 +49,14 @@ import org.eclipse.emf.cdo.server.CDOServerUtil; import org.eclipse.emf.cdo.server.IPermissionManager; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.ISession; +import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; import org.eclipse.emf.cdo.server.ITransaction; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.internal.security.bundle.OM; import org.eclipse.emf.cdo.server.spi.security.InternalSecurityManager; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; @@ -68,6 +74,7 @@ import org.eclipse.net4j.Net4jUtil; import org.eclipse.net4j.acceptor.IAcceptor; import org.eclipse.net4j.connector.IConnector; import org.eclipse.net4j.util.ArrayUtil; +import org.eclipse.net4j.util.RunnableWithException; import org.eclipse.net4j.util.WrappedException; import org.eclipse.net4j.util.collection.HashBag; import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException; @@ -80,6 +87,7 @@ import org.eclipse.net4j.util.lifecycle.ILifecycle; import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.om.monitor.Monitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.security.IAuthenticator; import org.eclipse.net4j.util.security.IAuthenticator2; @@ -93,18 +101,24 @@ import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EValidator; import org.eclipse.emf.spi.cdo.InternalCDOSessionInvalidationEvent; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; /** * @author Eike Stepper */ public class SecurityManager extends Lifecycle implements InternalSecurityManager { - private static final Map<IRepository, InternalSecurityManager> SECURITY_MANAGERS = new HashMap<>(); + private static final Map<IRepository, InternalSecurityManager> SECURITY_MANAGERS = Collections.synchronizedMap(new HashMap<>()); private static final SecurityFactory SF = SecurityFactory.eINSTANCE; @@ -127,13 +141,19 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage private final IListener sessionManagerListener = new ContainerEventAdapter<ISession>() { @Override + protected void onAdded(IContainer<ISession> container, ISession session) + { + sessionAdded(session); + } + + @Override protected void onRemoved(IContainer<ISession> container, ISession session) { - removeUserInfo(session); + sessionRemoved(session); } }; - private final IListener systemListener = new IListener() + private final IListener realmInvalidationListener = new IListener() { private boolean clearUserInfos; @@ -152,7 +172,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage { if (clearUserInfos) { - clearUserInfos(); + clearUserInfos(true); clearUserInfos = false; } } @@ -169,7 +189,9 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage private final IManagedContainer container; - private final Map<ISession, UserInfo> userInfos = new HashMap<>(); + private final ConcurrentMap<InternalRepository, SecondaryRepository> secondaryRepositories = new ConcurrentHashMap<>(); + + private final ConcurrentMap<String, UserInfo> userInfos = new ConcurrentHashMap<>(); private final HashBag<PermissionImpl> permissionBag = new HashBag<>(); @@ -187,9 +209,9 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage private IConnector connector; - private CDONet4jSession systemSession; + private CDONet4jSession realmSession; - private CDOView systemView; + private CDOView realmView; private Realm realm; @@ -216,7 +238,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } @Override - public final IRepository getRepository() + public final InternalRepository getRepository() { return repository; } @@ -232,6 +254,30 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } @Override + public InternalRepository[] getSecondaryRepositories() + { + return secondaryRepositories.keySet().toArray(new InternalRepository[0]); + } + + @Override + public void addSecondaryRepository(InternalRepository repository) + { + secondaryRepositories.computeIfAbsent(repository, k -> { + return new SecondaryRepository(k); + }); + } + + @Override + public void removeSecondaryRepository(InternalRepository repository) + { + SecondaryRepository secondaryRepository = secondaryRepositories.remove(repository); + if (secondaryRepository != null) + { + secondaryRepository.dispose(); + } + } + + @Override public Realm getRealm() { return realm; @@ -274,68 +320,39 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } @Override - public Role addRole(final String id) + public Role addRole(String id) { - final Role[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.addRole(id); - } - }); - + Role[] result = { null }; + modify(realm -> result[0] = realm.addRole(id)); return result[0]; } @Override - public Group addGroup(final String id) + public Group addGroup(String id) { - final Group[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.addGroup(id); - } - }); - + Group[] result = { null }; + modify(realm -> result[0] = realm.addGroup(id)); return result[0]; } @Override - public User addUser(final String id) + public User addUser(String id) { - final User[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.addUser(id); - } - }); - + User[] result = { null }; + modify(realm -> result[0] = realm.addUser(id)); return result[0]; } @Override - public User addUser(final String id, final String password) + public User addUser(String id, String password) { - final User[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - UserPassword userPassword = SF.createUserPassword(); - userPassword.setEncrypted(new String(password)); + User[] result = { null }; + modify(realm -> { + UserPassword userPassword = SF.createUserPassword(); + userPassword.setEncrypted(new String(password)); - result[0] = realm.addUser(id); - result[0].setPassword(userPassword); - } + result[0] = realm.addUser(id); + result[0].setPassword(userPassword); }); return result[0]; @@ -348,66 +365,34 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } @Override - public User setPassword(final String id, final String password) + public User setPassword(String id, String password) { - final User[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.setPassword(id, password); - } - }); - + User[] result = { null }; + modify(realm -> result[0] = realm.setPassword(id, password)); return result[0]; } @Override - public Role removeRole(final String id) + public Role removeRole(String id) { - final Role[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.removeRole(id); - } - }); - + Role[] result = { null }; + modify(realm -> result[0] = realm.removeRole(id)); return result[0]; } @Override - public Group removeGroup(final String id) + public Group removeGroup(String id) { - final Group[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.removeGroup(id); - } - }); - + Group[] result = { null }; + modify(realm -> result[0] = realm.removeGroup(id)); return result[0]; } @Override - public User removeUser(final String id) + public User removeUser(String id) { - final User[] result = { null }; - modify(new RealmOperation() - { - @Override - public void execute(Realm realm) - { - result[0] = realm.removeUser(id); - } - }); - + User[] result = { null }; + modify(realm -> result[0] = realm.removeUser(id)); return result[0]; } @@ -434,7 +419,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage public CDOCommitInfo modifyWithInfo(RealmOperation operation, boolean waitUntilReadable) { checkReady(); - CDOTransaction transaction = systemSession.openTransaction(); + CDOTransaction transaction = realmSession.openTransaction(); try { @@ -444,7 +429,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage if (waitUntilReadable) { - if (!systemView.waitForUpdate(info.getTimeStamp(), 10000)) + if (!realmView.waitForUpdate(info.getTimeStamp(), 10000)) { throw new TimeoutRuntimeException(); } @@ -566,7 +551,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage */ protected void checkReady() { - if (realm == null || systemSession == null) + if (realm == null || realmSession == null) { // If I have no realm or session, I am probably inactive, so this will throw checkActive(); @@ -605,11 +590,11 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage config.setRepositoryName(repositoryName); config.setUserID(SYSTEM_USER_ID); - systemSession = config.openNet4jSession(); - systemSession.options().setGeneratedPackageEmulationEnabled(true); - systemSession.addListener(systemListener); + realmSession = config.openNet4jSession(); + realmSession.options().setGeneratedPackageEmulationEnabled(true); + realmSession.addListener(realmInvalidationListener); - CDOTransaction initialTransaction = systemSession.openTransaction(); + CDOTransaction initialTransaction = realmSession.openTransaction(); boolean firstTime = !initialTransaction.hasResource(realmPath); if (firstTime) @@ -641,10 +626,10 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage initialTransaction.close(); } - systemView = systemSession.openView(); - systemView.addListener(systemListener); + realmView = realmSession.openView(); + realmView.addListener(realmInvalidationListener); - realm = systemView.getObject(realm); + realm = realmView.getObject(realm); realmID = realm.cdoID(); InternalSessionManager sessionManager = repository.getSessionManager(); @@ -704,11 +689,11 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage return directory; } - protected CDOPermission convertPermission(Access permission) + protected CDOPermission convertPermission(Access access) { - if (permission != null) + if (access != null) { - switch (permission) + switch (access) { case READ: return CDOPermission.READ; @@ -726,7 +711,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage { if (lastRealmModification != CDOBranchPoint.UNSPECIFIED_DATE) { - if (!systemView.waitForUpdate(lastRealmModification, 10000L)) + if (!realmView.waitForUpdate(lastRealmModification, 10000L)) { throw new TimeoutRuntimeException(); } @@ -786,79 +771,195 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } } - protected UserInfo getUserInfo(ISession session) + protected void authorizeCommit(CommitContext commitContext, UserInfo userInfo) { - UserInfo userInfo; - synchronized (userInfos) + PermissionUtil.setUser(userInfo.getUserId()); + PermissionUtil.initViewCreation(xxx -> CDOServerUtil.openView(commitContext)); + + try { - userInfo = userInfos.get(session); - } + CDOBranchPoint securityContext = commitContext.getBranchPoint(); - if (userInfo == null) + ITransaction transaction = commitContext.getTransaction(); + ISession session = transaction.getSession(); + + Access userDefaultAccess = userInfo.getDefaultAccess(); + Permission[] userPermissions = userInfo.getPermissions(); + + InternalCDORevision[] revisions = commitContext.getDirtyObjects(); + InternalCDORevisionDelta[] revisionDeltas = commitContext.getDirtyObjectDeltas(); + + // Check permissions on the commit changes and detect realm modifications + byte securityImpact = CommitNotificationInfo.IMPACT_NONE; + for (int i = 0; i < revisions.length; i++) + { + InternalCDORevision revision = revisions[i]; + CDOPermission permission = authorize(revision, commitContext, securityContext, session, userDefaultAccess, userPermissions); + + if (permission != CDOPermission.WRITE) + { + throw new SecurityException("User " + commitContext.getUserID() + " is not allowed to write to " + revision); + } + + if (securityImpact != CommitNotificationInfo.IMPACT_REALM) + { + InternalCDORevisionDelta revisionDelta = revisionDeltas[i]; + if (CDORevisionUtil.isContained(revisionDelta.getID(), realmID, transaction)) // Use "before commit" state + { + securityImpact = CommitNotificationInfo.IMPACT_REALM; + } + } + } + + // Determine permissions that are impacted by the commit changes + Set<Permission> impactedRules = null; + if (securityImpact != CommitNotificationInfo.IMPACT_REALM) + { + PermissionImpl[] assignedPermissions = permissionArray; // Thread-safe + if (assignedPermissions.length != 0) + { + CommitImpactContext commitImpactContext = new PermissionImpl.CommitImpactContext() + { + @Override + public CDORevision[] getNewObjects() + { + return commitContext.getNewObjects(); + } + + @Override + public CDORevision[] getDirtyObjects() + { + return revisions; + } + + @Override + public CDORevisionDelta[] getDirtyObjectDeltas() + { + return revisionDeltas; + } + + @Override + public CDOID[] getDetachedObjects() + { + return commitContext.getDetachedObjects(); + } + }; + + for (int i = 0; i < assignedPermissions.length; i++) + { + PermissionImpl permission = assignedPermissions[i]; + if (permission.isImpacted(commitImpactContext)) + { + if (impactedRules == null) + { + impactedRules = new HashSet<>(); + } + + impactedRules.add(permission); + } + } + + if (impactedRules != null) + { + securityImpact = CommitNotificationInfo.IMPACT_PERMISSIONS; + } + } + } + + ((InternalCommitContext)commitContext).setSecurityImpact(securityImpact, impactedRules); + } + finally { - userInfo = addUserInfo(session); + PermissionUtil.setUser(null); + PermissionUtil.doneViewCreation(); } - - return userInfo; } - protected UserInfo addUserInfo(ISession session) + protected void sessionAdded(ISession session) { String userID = session.getUserID(); - User user = getUser(userID); - UserInfo userInfo = new UserInfo(user); - synchronized (userInfos) - { - userInfos.put(session, userInfo); + UserInfo result = userInfos.computeIfAbsent(userID, k -> { + User user = getUser(k); + UserInfo userInfo = new UserInfo(user); + updatePermissions(userInfo, true); + return userInfo; + }); - Permission[] permissions = userInfo.getPermissions(); - for (int i = 0; i < permissions.length; i++) + result.addSessionRef(); + } + + protected void sessionRemoved(ISession session) + { + String userID = session.getUserID(); + + userInfos.computeIfPresent(userID, (k, v) -> { + if (v.removeSessionRef()) { - Permission permission = permissions[i]; - permissionBag.add((PermissionImpl)permission); + return null; } - // Atomic update - permissionArray = permissionBag.toArray(new PermissionImpl[permissionBag.size()]); + return v; + }); + } + + protected UserInfo getUserInfo(ISession session) + { + String userID = session.getUserID(); + + UserInfo userInfo = userInfos.get(userID); + if (userInfo == null) + { + throw new IllegalStateException("No user info for " + userID); } return userInfo; } - protected UserInfo removeUserInfo(ISession session) + protected void clearUserInfos(boolean rebuild) { - UserInfo userInfo; - synchronized (userInfos) + synchronized (permissionBag) { - userInfo = userInfos.remove(session); + permissionBag.clear(); + permissionArray = null; - if (userInfo != null) + if (rebuild) { - Permission[] permissions = userInfo.getPermissions(); - for (int i = 0; i < permissions.length; i++) + for (UserInfo userInfo : userInfos.values()) { - Permission permission = permissions[i]; - permissionBag.remove(permission); + userInfo.rebuildPermissions(); + updatePermissions(userInfo, false); } - // Atomic update - permissionArray = permissionBag.toArray(new PermissionImpl[permissionBag.size()]); + updatePermissions(null, true); + } + else + { + userInfos.clear(); } } - - return userInfo; } - protected void clearUserInfos() + protected void updatePermissions(UserInfo userInfo, boolean updateArray) { - synchronized (userInfos) + Permission[] permissions = userInfo == null ? null : userInfo.getPermissions(); + + synchronized (permissionBag) { - // System.out.println("clearUserInfos()"); + if (permissions != null) + { + for (int i = 0; i < permissions.length; i++) + { + Permission permission = permissions[i]; + permissionBag.add((PermissionImpl)permission); + } + } - userInfos.clear(); - permissionBag.clear(); - permissionArray = null; + if (updateArray) + { + // Atomic update + permissionArray = permissionBag.toArray(new PermissionImpl[permissionBag.size()]); + } } } @@ -895,14 +996,14 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage @Override protected void doDeactivate() throws Exception { - clearUserInfos(); + clearUserInfos(false); realm = null; realmID = null; - systemSession.close(); - systemSession = null; - systemView = null; + realmSession.close(); + realmSession = null; + realmView = null; connector.close(); connector = null; @@ -921,17 +1022,18 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage /** * @author Eike Stepper */ - private static final class UserInfo + private static final class UserInfo extends AtomicInteger { + private static final long serialVersionUID = 1L; + private final User user; - private final Permission[] permissions; + private Permission[] permissions; public UserInfo(User user) { this.user = user; - EList<Permission> allPermissions = user.getAllPermissions(); - permissions = allPermissions.toArray(new Permission[allPermissions.size()]); + rebuildPermissions(); } public User getUser() @@ -939,10 +1041,42 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage return user; } + public String getUserId() + { + return user.getId(); + } + + public Access getDefaultAccess() + { + return user.getDefaultAccess(); + } + public Permission[] getPermissions() { return permissions; } + + public void rebuildPermissions() + { + EList<Permission> allPermissions = user.getAllPermissions(); + permissions = allPermissions.toArray(new Permission[allPermissions.size()]); + } + + public synchronized void addSessionRef() + { + incrementAndGet(); + } + + public synchronized boolean removeSessionRef() + { + return decrementAndGet() == 0; + } + + @Override + public String toString() + { + return "UserInfo[user=" + getUserId() + ", refs=" + super.toString() + "]"; + } } /** @@ -950,6 +1084,10 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage */ private final class Authenticator implements IAuthenticator2 { + public Authenticator() + { + } + @Override public void authenticate(String userID, char[] password) throws SecurityException { @@ -1008,6 +1146,10 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage */ private final class PermissionManager implements IPermissionManager { + public PermissionManager() + { + } + @Override @Deprecated public CDOPermission getPermission(CDORevision revision, CDOBranchPoint securityContext, String userID) @@ -1016,7 +1158,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } @Override - public CDOPermission getPermission(CDORevision revision, final CDOBranchPoint securityContext, final ISession session) + public CDOPermission getPermission(CDORevision revision, CDOBranchPoint securityContext, ISession session) { String userID = session.getUserID(); if (SYSTEM_USER_ID.equals(userID)) @@ -1086,21 +1228,14 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage { private final IRepository.WriteAccessHandler realmValidationHandler = new RealmValidationHandler(); - @Override - public void handleTransactionBeforeCommitting(ITransaction transaction, final CommitContext commitContext, OMMonitor monitor) throws RuntimeException + public WriteAccessHandler() { - doHandleTransactionBeforeCommitting(transaction, commitContext, monitor); - - if (commitContext.getSecurityImpact() == CommitNotificationInfo.IMPACT_REALM) - { - // Validate changes to the realm - realmValidationHandler.handleTransactionBeforeCommitting(transaction, commitContext, monitor); - } } - protected void doHandleTransactionBeforeCommitting(ITransaction transaction, final CommitContext commitContext, OMMonitor monitor) throws RuntimeException + @Override + public void handleTransactionBeforeCommitting(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) throws RuntimeException { - if (transaction.getSessionID() == systemSession.getSessionID()) + if (transaction.getSessionID() == realmSession.getSessionID()) { // Access through ISecurityManager.modify(RealmOperation) handleCommit(commitContext, null); @@ -1109,119 +1244,19 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage } UserInfo userInfo = getUserInfo(transaction.getSession()); - User user = userInfo.getUser(); - - handleCommit(commitContext, user); - - PermissionUtil.setUser(user.getId()); - PermissionUtil.initViewCreation(new ViewCreator() - { - @Override - public CDOView createView(CDORevisionProvider revisionProvider) - { - return CDOServerUtil.openView(commitContext); - } - }); - - try - { - CDOBranchPoint securityContext = commitContext.getBranchPoint(); - ISession session = transaction.getSession(); - Access userDefaultAccess = user.getDefaultAccess(); - Permission[] userPermissions = userInfo.getPermissions(); + handleCommit(commitContext, userInfo.getUser()); + authorizeCommit(commitContext, userInfo); - final InternalCDORevision[] revisions = commitContext.getDirtyObjects(); - final InternalCDORevisionDelta[] revisionDeltas = commitContext.getDirtyObjectDeltas(); - - // Check permissions on the commit changes and detect realm modifications - byte securityImpact = CommitNotificationInfo.IMPACT_NONE; - for (int i = 0; i < revisions.length; i++) - { - InternalCDORevision revision = revisions[i]; - CDOPermission permission = authorize(revision, commitContext, securityContext, session, userDefaultAccess, userPermissions); - - if (permission != CDOPermission.WRITE) - { - throw new SecurityException("User " + commitContext.getUserID() + " is not allowed to write to " + revision); - } - - if (securityImpact != CommitNotificationInfo.IMPACT_REALM) - { - InternalCDORevisionDelta revisionDelta = revisionDeltas[i]; - if (CDORevisionUtil.isContained(revisionDelta.getID(), realmID, transaction)) // Use "before commit" state - { - securityImpact = CommitNotificationInfo.IMPACT_REALM; - } - } - } - - // Determine permissions that are impacted by the commit changes - Set<Permission> impactedRules = null; - if (securityImpact != CommitNotificationInfo.IMPACT_REALM) - { - PermissionImpl[] assignedPermissions = permissionArray; // Thread-safe - if (assignedPermissions.length != 0) - { - CommitImpactContext commitImpactContext = new PermissionImpl.CommitImpactContext() - { - @Override - public CDORevision[] getNewObjects() - { - return commitContext.getNewObjects(); - } - - @Override - public CDORevision[] getDirtyObjects() - { - return revisions; - } - - @Override - public CDORevisionDelta[] getDirtyObjectDeltas() - { - return revisionDeltas; - } - - @Override - public CDOID[] getDetachedObjects() - { - return commitContext.getDetachedObjects(); - } - }; - - for (int i = 0; i < assignedPermissions.length; i++) - { - PermissionImpl permission = assignedPermissions[i]; - if (permission.isImpacted(commitImpactContext)) - { - if (impactedRules == null) - { - impactedRules = new HashSet<>(); - } - - impactedRules.add(permission); - } - } - - if (impactedRules != null) - { - securityImpact = CommitNotificationInfo.IMPACT_PERMISSIONS; - } - } - } - - ((InternalCommitContext)commitContext).setSecurityImpact(securityImpact, impactedRules); - } - finally + if (commitContext.getSecurityImpact() == CommitNotificationInfo.IMPACT_REALM) { - PermissionUtil.setUser(null); - PermissionUtil.doneViewCreation(); + // Validate changes to the realm + realmValidationHandler.handleTransactionBeforeCommitting(transaction, commitContext, monitor); } } @Override - public void handleTransactionAfterCommitted(ITransaction transaction, final CommitContext commitContext, OMMonitor monitor) + public void handleTransactionAfterCommitted(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) { if (commitContext.getSecurityImpact() == CommitNotificationInfo.IMPACT_REALM) { @@ -1243,11 +1278,15 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage { private final EValidator realmValidator = EValidator.Registry.INSTANCE.getEValidator(SecurityPackage.eINSTANCE); + public RealmValidationHandler() + { + } + @Override protected void handleTransactionBeforeCommitting(OMMonitor monitor) throws RuntimeException { - final BasicDiagnostic diagnostic = new BasicDiagnostic(); - final Map<Object, Object> context = createValidationContext(); + BasicDiagnostic diagnostic = new BasicDiagnostic(); + Map<Object, Object> context = createValidationContext(); boolean realmChecked = false; for (EObject object : getDirtyObjects()) @@ -1278,7 +1317,7 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage protected Map<Object, Object> createValidationContext() { Map<Object, Object> result = new java.util.HashMap<>(); - final CommitContext commitContext = getCommitContext(); + CommitContext commitContext = getCommitContext(); // Supply the revision-provider and branch point required by realm validation result.put(CDORevisionProvider.class, commitContext); @@ -1315,4 +1354,109 @@ public class SecurityManager extends Lifecycle implements InternalSecurityManage return null; } } + + /** + * @author Eike Stepper + */ + private final class SecondaryRepository extends LifecycleEventAdapter implements IRepository.WriteAccessHandler + { + private final InternalRepository delegate; + + public SecondaryRepository(InternalRepository delegate) + { + this.delegate = delegate; + + InternalSessionManager sessionManager = delegate.getSessionManager(); + sessionManager.setAuthenticator(authenticator); + sessionManager.setPermissionManager(permissionManager); + sessionManager.addListener(sessionManagerListener); + + delegate.addListener(this); + delegate.addHandler(this); + + SECURITY_MANAGERS.put(delegate, SecurityManager.this); + } + + @Override + public void handleTransactionBeforeCommitting(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) throws RuntimeException + { + handleNewPackageUnits(commitContext); + + UserInfo userInfo = getUserInfo(transaction.getSession()); + authorizeCommit(commitContext, userInfo); + } + + @Override + public void handleTransactionAfterCommitted(ITransaction transaction, CommitContext commitContext, OMMonitor monitor) + { + // Do nothing. + } + + public void dispose() + { + SECURITY_MANAGERS.remove(delegate); + } + + @Override + protected void onDeactivated(ILifecycle lifecycle) + { + removeSecondaryRepository(delegate); + } + + private void handleNewPackageUnits(CommitContext commitContext) + { + InternalCDOPackageUnit[] newPackageUnits = commitContext.getNewPackageUnits(); + if (newPackageUnits != null && newPackageUnits.length != 0) + { + InternalCDOPackageRegistry realmPackageRegistry = getRepository().getPackageRegistry(); + List<InternalCDOPackageUnit> unknownPackageUnits = new ArrayList<>(); + + for (InternalCDOPackageUnit packageUnit : newPackageUnits) + { + String nsURI = packageUnit.getID(); + if (!realmPackageRegistry.containsKey(nsURI)) + { + unknownPackageUnits.add((InternalCDOPackageUnit)CDOModelUtil.copyPackageUnit(packageUnit)); + } + } + + if (!unknownPackageUnits.isEmpty()) + { + InternalCDOPackageUnit[] unitArray = unknownPackageUnits.toArray(new InternalCDOPackageUnit[unknownPackageUnits.size()]); + + try + { + RunnableWithException.forkAndWait(() -> { + synchronized (realmPackageRegistry) + { + realmPackageRegistry.putPackageUnits(unitArray, CDOPackageUnit.State.LOADED); + } + + commitRealmPackageUnits(unitArray); + }); + } + catch (Exception ex) + { + throw WrappedException.wrap(ex); + } + } + } + } + + private void commitRealmPackageUnits(InternalCDOPackageUnit[] packageUnits) + { + IStoreAccessor writer = getRepository().getStore().getWriter(null); + StoreThreadLocal.setAccessor(writer); + + try + { + writer.writePackageUnits(packageUnits, new Monitor()); + writer.commit(new Monitor()); + } + finally + { + StoreThreadLocal.release(); + } + } + } } diff --git a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/security/ISecurityManager.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/security/ISecurityManager.java index 0534955714..9214661152 100644 --- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/security/ISecurityManager.java +++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/security/ISecurityManager.java @@ -32,6 +32,11 @@ public interface ISecurityManager extends SecurityItemContainer public IRepository getRepository(); + /** + * @since 4.6 + */ + public IRepository[] getSecondaryRepositories(); + public Realm getRealm(); /** @@ -56,6 +61,7 @@ public interface ISecurityManager extends SecurityItemContainer * * @author Eike Stepper */ + @FunctionalInterface public interface RealmOperation { public void execute(Realm realm); diff --git a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/spi/security/InternalSecurityManager.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/spi/security/InternalSecurityManager.java index 50836180bf..4bee9af22a 100644 --- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/spi/security/InternalSecurityManager.java +++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/spi/security/InternalSecurityManager.java @@ -31,6 +31,22 @@ public interface InternalSecurityManager extends ISecurityManager public void setRepository(InternalRepository repository); + /** + * @since 4.6 + */ + @Override + public InternalRepository[] getSecondaryRepositories(); + + /** + * @since 4.6 + */ + public void addSecondaryRepository(InternalRepository repository); + + /** + * @since 4.6 + */ + public void removeSecondaryRepository(InternalRepository repository); + public String getRealmPath(); public CommitHandler[] getCommitHandlers(); diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java index 9098dd3dd0..319fe9d3ba 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java @@ -1807,7 +1807,7 @@ public class TransactionCommitContext implements InternalCommitContext { InternalCDOPackageUnit packageUnit = newPackageUnits[i]; packageUnit.setState(CDOPackageUnit.State.LOADED); - packageUnit.setPackageRegistry(repositoryPackageRegistry); + repositoryPackageRegistry.putPackageUnit(packageUnit); monitor.worked(); } @@ -1921,6 +1921,7 @@ public class TransactionCommitContext implements InternalCommitContext { LifecycleUtil.checkActive(this); packageUnit.setPackageRegistry(this); + for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos()) { EPackage ePackage = packageInfo.getEPackage(); diff --git a/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch b/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch index ef1747089a..eacf45733d 100644 --- a/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch +++ b/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch @@ -2,7 +2,7 @@ <launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench"> <setAttribute key="additional_plugins"> <setEntry value="javax.servlet:3.1.0.v201410161800:default:false:default:default"/> - <setEntry value="org.eclipse.emf.cdo.edit:4.5.3.qualifier:default:true:default:default"/> + <setEntry value="org.eclipse.emf.cdo.edit:4.5.4.qualifier:default:true:default:default"/> <setEntry value="org.eclipse.emf.cdo.examples.company.edit:4.1.0.qualifier:default:true:default:default"/> <setEntry value="org.eclipse.emf.cdo.expressions.edit:4.4.0.qualifier:default:true:default:default"/> <setEntry value="org.eclipse.emf.cdo.security.edit:4.5.0.qualifier:default:true:default:default"/> diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/event/IListener.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/event/IListener.java index 451c6a17c7..473e25de83 100644 --- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/event/IListener.java +++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/event/IListener.java @@ -17,6 +17,7 @@ import java.util.EventListener; * * @author Eike Stepper */ +@FunctionalInterface public interface IListener extends EventListener { public void notifyEvent(IEvent event); |