[571768] Make SecurityManager multitenant
https://bugs.eclipse.org/bugs/show_bug.cgi?id=571768
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java
index 14405a1..2681b72 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/CDOCommonSession.java
@@ -31,6 +31,11 @@
{
public int getSessionID();
+ /**
+ * @since 4.13
+ */
+ public long getOpeningTime();
+
public CDOCommonView[] getViews();
public CDOCommonView getView(int viewID);
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 5d3a523..a8e27a2 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.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 @@
}
/**
+ * @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/commit/CDOCommitInfoImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/commit/CDOCommitInfoImpl.java
index ae07d13..05233b3 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/commit/CDOCommitInfoImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/commit/CDOCommitInfoImpl.java
@@ -145,6 +145,7 @@
@Override
public boolean isInitialCommit()
{
+ int xxx;
return CDOCommonUtil.SYSTEM_USER_ID.equals(userID);
}
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 da71cc2..b3156c3 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 @@
{
LifecycleUtil.checkActive(this);
packageUnit.setPackageRegistry(this);
+
for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos())
{
EPackage ePackage = packageInfo.getEPackage(false);
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml b/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
index c51de2b..da788cf 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/plugin.xml
@@ -715,10 +715,24 @@
</with>
</visibleWhen>
</command>
+ <command
+ commandId="org.eclipse.emf.cdo.explorer.ui.CheckoutDuplicate"
+ icon="icons/duplicate.gif"
+ label="Duplicate Checkout"
+ style="push"
+ tooltip="Duplicate the checkout">
+ <visibleWhen checkEnabled="false">
+ <with variable="activeMenuSelection">
+ <iterate ifEmpty="false">
+ <instanceof value="org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout"/>
+ </iterate>
+ </with>
+ </visibleWhen>
+ </command>
</menuContribution>
<menuContribution
allPopups="false"
- locationURI="popup:org.eclipse.ui.popup.any?after=group.build">
+ locationURI="popup:org.eclipse.ui.popup.any?after=group.close">
<command
commandId="org.eclipse.emf.cdo.explorer.ui.RepositoryDisconnect"
icon="icons/disconnect.gif"
@@ -736,6 +750,10 @@
</with>
</visibleWhen>
</command>
+ </menuContribution>
+ <menuContribution
+ allPopups="false"
+ locationURI="popup:org.eclipse.ui.popup.any?after=group.build">
<command
commandId="org.eclipse.emf.cdo.explorer.ui.CheckoutClose"
icon="icons/checkout_closed.gif"
@@ -753,20 +771,6 @@
</with>
</visibleWhen>
</command>
- <command
- commandId="org.eclipse.emf.cdo.explorer.ui.CheckoutDuplicate"
- icon="icons/duplicate.gif"
- label="Duplicate Checkout"
- style="push"
- tooltip="Duplicate the checkout">
- <visibleWhen checkEnabled="false">
- <with variable="activeMenuSelection">
- <iterate ifEmpty="false">
- <instanceof value="org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout"/>
- </iterate>
- </with>
- </visibleWhen>
- </command>
</menuContribution>
<menuContribution
allPopups="false"
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java
index 3dc2643..bfeaa37 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutLabelProvider.java
@@ -229,6 +229,11 @@
return ContainerItemProvider.PENDING_IMAGE;
}
+ if (object instanceof ViewerUtil.Error)
+ {
+ return ContainerItemProvider.ERROR_IMAGE;
+ }
+
try
{
ILabelProvider provider = getStateManager().getLabelProvider(object);
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java
index 6758572..09d884b 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/CDOCheckoutState.java
@@ -11,6 +11,7 @@
package org.eclipse.emf.cdo.explorer.ui.checkouts;
import org.eclipse.emf.cdo.CDOElement;
+import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.eresource.CDOResourceLeaf;
import org.eclipse.emf.cdo.eresource.CDOResourceNode;
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
@@ -21,6 +22,7 @@
import org.eclipse.emf.cdo.internal.ui.editor.CDOEditor;
import org.eclipse.emf.cdo.ui.CDOEditorUtil;
import org.eclipse.emf.cdo.ui.CDOLabelDecorator;
+import org.eclipse.emf.cdo.ui.CDOLabelProvider;
import org.eclipse.emf.cdo.ui.CDOTreeExpansionAgent;
import org.eclipse.emf.cdo.view.CDOView;
@@ -362,6 +364,15 @@
return ContainerItemProvider.PENDING_COLOR;
}
+ if (object instanceof CDOObject)
+ {
+ Color color = CDOLabelProvider.getColor((CDOObject)object);
+ if (color != null)
+ {
+ return color;
+ }
+ }
+
return super.getForeground(object);
}
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/ShowInActionProvider.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/ShowInActionProvider.java
index 747102c..af00979 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/ShowInActionProvider.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/checkouts/actions/ShowInActionProvider.java
@@ -17,10 +17,12 @@
import org.eclipse.emf.cdo.explorer.CDOExplorerUtil;
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.explorer.repositories.CDORepository;
+import org.eclipse.emf.cdo.explorer.repositories.CDORepositoryManager.RepositoryConnectionEvent;
import org.eclipse.emf.cdo.explorer.ui.bundle.OM;
import org.eclipse.emf.cdo.explorer.ui.checkouts.CDOCheckoutContentProvider;
import org.eclipse.emf.cdo.internal.explorer.AbstractElement;
import org.eclipse.emf.cdo.internal.explorer.checkouts.OfflineCDOCheckout;
+import org.eclipse.emf.cdo.internal.explorer.repositories.CDORepositoryImpl;
import org.eclipse.emf.cdo.internal.explorer.repositories.LocalCDORepository;
import org.eclipse.emf.cdo.internal.ui.views.CDOSessionsView;
import org.eclipse.emf.cdo.internal.ui.views.CDOTimeMachineView;
@@ -38,9 +40,17 @@
import org.eclipse.emf.internal.cdo.session.CDOSessionFactory;
+import org.eclipse.net4j.util.container.ContainerEventAdapter;
+import org.eclipse.net4j.util.container.FactoryNotFoundException;
+import org.eclipse.net4j.util.container.IContainer;
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.container.IPluginContainer;
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.IListener;
+import org.eclipse.net4j.util.factory.ProductCreationException;
import org.eclipse.net4j.util.io.IOUtil;
+import org.eclipse.net4j.util.lifecycle.LifecycleEvent;
+import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.ui.MenuFiller;
import org.eclipse.emf.ecore.EObject;
@@ -259,18 +269,18 @@
return false;
}
- public static void showDashboard(final StructuredViewer viewer, ISelectionService selectionService)
+ public static void showDashboard(StructuredViewer viewer, ISelectionService selectionService)
{
- final CDOCheckoutDashboard[] dashboard = { (CDOCheckoutDashboard)viewer.getData(DASHBOARD_KEY) };
+ CDOCheckoutDashboard[] dashboard = { (CDOCheckoutDashboard)viewer.getData(DASHBOARD_KEY) };
if (dashboard[0] == null)
{
- final Control control = viewer.getControl();
- final Object controlLayoutData = control.getLayoutData();
+ Control control = viewer.getControl();
+ Object controlLayoutData = control.getLayoutData();
- final Composite parent = control.getParent();
- final Layout parentLayout = parent.getLayout();
+ Composite parent = control.getParent();
+ Layout parentLayout = parent.getLayout();
- final int[] minimumHeight = { 0 };
+ int[] minimumHeight = { 0 };
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 0;
@@ -280,7 +290,7 @@
parent.setLayout(layout);
control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
- final Sash sash = new Sash(parent, SWT.HORIZONTAL | SWT.SMOOTH);
+ Sash sash = new Sash(parent, SWT.HORIZONTAL | SWT.SMOOTH);
sash.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
sash.addListener(SWT.Selection, new Listener()
{
@@ -547,10 +557,10 @@
@Override
protected void run(IViewPart viewPart) throws Exception
{
- final Object select = show();
+ Object select = show();
if (select != null)
{
- final TreeViewer viewer = ((CDOSessionsView)viewPart).getViewer();
+ TreeViewer viewer = ((CDOSessionsView)viewPart).getViewer();
viewer.getControl().getDisplay().asyncExec(new Runnable()
{
@Override
@@ -584,7 +594,7 @@
CDOBranch branch = checkoutView.getBranch();
for (CDOTransaction transaction : session.getTransactions())
{
- if (branch.equals(transaction.getBranch()))
+ if (branch.getID() == transaction.getBranch().getID())
{
return transaction;
}
@@ -617,13 +627,64 @@
{
repository.connect();
- String description = repository.getURI();
- int lastSlash = description.lastIndexOf('/');
- description = description.substring(0, lastSlash) + "?repositoryName=" + repository.getName() + "&automaticPackageRegistry=true&repositoryID="
- + repository.getID();
+ String factoryType = "cdo-explorer";
+ String description = repository.getID();
- return (CDOSession)IPluginContainer.INSTANCE.getElement(CDOSessionFactory.PRODUCT_GROUP, "cdo", repository.getConnectorType() + "://"
- + repository.getConnectorDescription() + "?repositoryName=" + repository.getName() + "&repositoryID=" + repository.getID());
+ try
+ {
+ return (CDOSession)IPluginContainer.INSTANCE.getElement(CDOSessionFactory.PRODUCT_GROUP, factoryType, description);
+ }
+ catch (FactoryNotFoundException | ProductCreationException ex)
+ {
+ CDOSession session = ((CDORepositoryImpl)repository).openSession();
+
+ IListener listener = new ContainerEventAdapter<Object>()
+ {
+ @Override
+ protected void onRemoved(IContainer<Object> container, Object element)
+ {
+ if (element == repository)
+ {
+ dispose(session);
+ }
+ }
+
+ @Override
+ protected void notifyOtherEvent(IEvent event)
+ {
+ if (event instanceof RepositoryConnectionEvent)
+ {
+ RepositoryConnectionEvent e = (RepositoryConnectionEvent)event;
+ if (e.getRepository() == repository)
+ {
+ dispose(session);
+ }
+ }
+ else if (event instanceof LifecycleEvent)
+ {
+ LifecycleEvent e = (LifecycleEvent)event;
+ if (e.getSource() == session && e.getKind() == LifecycleEvent.Kind.DEACTIVATED)
+ {
+ dispose(session);
+ }
+ }
+ }
+
+ private void dispose(CDOSession session)
+ {
+ session.removeListener(this);
+ CDOExplorerUtil.getRepositoryManager().removeListener(this);
+ LifecycleUtil.deactivate(session);
+ }
+ };
+
+ session.addListener(listener);
+ CDOExplorerUtil.getRepositoryManager().addListener(listener);
+
+ IPluginContainer.INSTANCE.putElement(CDOSessionFactory.PRODUCT_GROUP, factoryType, description, session);
+
+ return session;
+ }
}
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/AbstractPropertyPage.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/AbstractPropertyPage.java
index 2d00676..7344ebb 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/AbstractPropertyPage.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/AbstractPropertyPage.java
@@ -28,11 +28,11 @@
import org.eclipse.ui.dialogs.PropertyPage;
import java.io.File;
-import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.function.Consumer;
/**
* @author Eike Stepper
@@ -139,7 +139,7 @@
Label labelControl = new Label(parent, SWT.NONE);
labelControl.setText(label + ":");
- Control control = createControl(parent, name, label, description, value);
+ Control control = createControl(parent, name, description, value);
if (control == null)
{
control = new Label(parent, SWT.NONE);
@@ -147,14 +147,21 @@
if (!StringUtil.isEmpty(description))
{
- labelControl.setToolTipText(description);
- control.setToolTipText(description);
+ if (StringUtil.isEmpty(labelControl.getToolTipText()))
+ {
+ labelControl.setToolTipText(description);
+ }
+
+ if (StringUtil.isEmpty(control.getToolTipText()))
+ {
+ control.setToolTipText(description);
+ }
}
return control;
}
- protected Control createControl(Composite parent, String name, String label, String description, String value)
+ protected Control createControl(Composite parent, String name, String description, String value)
{
Label control = new Label(parent, SWT.NONE);
control.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
@@ -163,25 +170,34 @@
return control;
}
- protected Link createLink(Composite parent, String name, String label, String description, String value)
+ protected Link createFileLink(Composite parent, String name, String description, String value)
{
File file = new File(value);
- URI uri = file.toURI();
+ return createLink(parent, file.toString(), file.toURI().toString(), uri -> IOUtil.openSystemBrowser(uri));
+ }
+ protected Link createLink(Composite parent, String label, String uri, Consumer<String> consumer)
+ {
Link link = new Link(parent, SWT.NONE);
link.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
- link.setText("<a href=\"" + uri + "\">" + file + "</a>");
+ setLinkText(link, label, uri);
+
link.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
- IOUtil.openSystemBrowser(uri.toString());
+ consumer.accept(uri);
}
});
return link;
}
+ protected void setLinkText(Link link, String label, String uri)
+ {
+ link.setText("<a href=\"" + uri + "\">" + label + "</a>");
+ }
+
protected abstract T convertElement(IAdaptable element);
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/CheckoutPropertyPage.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/CheckoutPropertyPage.java
index 430307f..20a8dab 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/CheckoutPropertyPage.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/CheckoutPropertyPage.java
@@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
+ *
* Contributors:
* Eike Stepper - initial API and implementation
*/
@@ -36,13 +36,13 @@
}
@Override
- protected Control createControl(Composite parent, String name, String label, String description, String value)
+ protected Control createControl(Composite parent, String name, String description, String value)
{
if ("folder".equals(name))
{
- return createLink(parent, name, label, description, value);
+ return createFileLink(parent, name, description, value);
}
- return super.createControl(parent, name, label, description, value);
+ return super.createControl(parent, name, description, value);
}
-}
\ No newline at end of file
+}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/RepositoryPropertyPage.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/RepositoryPropertyPage.java
index d5b6781..c0ea1fa 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/RepositoryPropertyPage.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/properties/RepositoryPropertyPage.java
@@ -4,7 +4,7 @@
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
- *
+ *
* Contributors:
* Eike Stepper - initial API and implementation
*/
@@ -12,19 +12,35 @@
import org.eclipse.emf.cdo.explorer.checkouts.CDOCheckout;
import org.eclipse.emf.cdo.explorer.repositories.CDORepository;
+import org.eclipse.emf.cdo.explorer.ui.bundle.OM;
+import org.eclipse.emf.cdo.internal.explorer.repositories.CDORepositoryImpl;
import org.eclipse.emf.cdo.internal.explorer.repositories.CDORepositoryProperties;
import org.eclipse.net4j.util.AdapterUtil;
+import org.eclipse.net4j.util.StringUtil;
+import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.ui.security.CredentialsDialog;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Shell;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
/**
* @author Eike Stepper
*/
public final class RepositoryPropertyPage extends AbstractPropertyPage<CDORepository>
{
+ private static final String USER_ID_LINK_URI = "security:change_login_crendentials";
+
+ private Link userIDLink;
+
public RepositoryPropertyPage()
{
super(CDORepositoryProperties.INSTANCE, CDORepositoryProperties.CATEGORY_REPOSITORY, "id", "type", "label", "folder");
@@ -42,13 +58,120 @@
}
@Override
- protected Control createControl(Composite parent, String name, String label, String description, String value)
+ protected Control createControl(Composite parent, String name, String description, String value)
{
if ("folder".equals(name))
{
- return createLink(parent, name, label, description, value);
+ return createFileLink(parent, name, description, value);
}
- return super.createControl(parent, name, label, description, value);
+ if ("userID".equals(name))
+ {
+ userIDLink = createLink(parent, value, USER_ID_LINK_URI, uri -> changeLoginCrendentials());
+ userIDLink.setToolTipText("Change login credentials");
+ return userIDLink;
+ }
+
+ return super.createControl(parent, name, description, value);
}
-}
\ No newline at end of file
+
+ private void changeLoginCrendentials()
+ {
+ CDORepositoryImpl repository = (CDORepositoryImpl)getInput();
+ String realm = repository.getURI();
+ IPasswordCredentials credentials = repository.getCredentials();
+ String currentUserID = credentials == null ? null : credentials.getUserID();
+
+ ChangeCredentialsDialog dialog = new ChangeCredentialsDialog(getShell(), realm, currentUserID);
+ if (dialog.open() == ChangeCredentialsDialog.OK)
+ {
+ List<CDOCheckout> openCheckouts = null;
+ boolean connected = repository.isConnected();
+
+ if (connected)
+ {
+ try
+ {
+ openCheckouts = new ArrayList<>();
+ for (CDOCheckout checkout : repository.getCheckouts())
+ {
+ if (checkout.isOpen())
+ {
+ openCheckouts.add(checkout);
+ }
+ }
+
+ repository.disconnect(true);
+ }
+ catch (Exception ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+
+ IPasswordCredentials newCredentials = dialog.getCredentials();
+ setLinkText(userIDLink, newCredentials.getUserID(), USER_ID_LINK_URI);
+
+ repository.setCredentials(newCredentials);
+
+ if (connected)
+ {
+ try
+ {
+ repository.connect();
+
+ if (repository.isConnected() && openCheckouts != null)
+ {
+ for (CDOCheckout checkout : openCheckouts)
+ {
+ checkout.open();
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class ChangeCredentialsDialog extends CredentialsDialog
+ {
+ private final String currentUserID;
+
+ public ChangeCredentialsDialog(Shell shell, String realm, String currentUserID)
+ {
+ super(shell, realm, "Change Login Credentials", "Enter your user ID and password for the connection.");
+ this.currentUserID = currentUserID;
+ }
+
+ @Override
+ protected String getInitialUserID()
+ {
+ if (!StringUtil.isEmpty(currentUserID))
+ {
+ return currentUserID;
+ }
+
+ return super.getInitialUserID();
+ }
+
+ @Override
+ protected List<String> loadUsers()
+ {
+ Set<String> userIDs = new HashSet<>(super.loadUsers());
+ if (!StringUtil.isEmpty(currentUserID))
+ {
+ userIDs.add(currentUserID);
+ }
+
+ List<String> result = new ArrayList<>(userIDs);
+ result.sort(null);
+ return result;
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoriesView.java b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoriesView.java
index a2d3d13..40d41fe 100644
--- a/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoriesView.java
+++ b/plugins/org.eclipse.emf.cdo.explorer.ui/src/org/eclipse/emf/cdo/explorer/ui/repositories/CDORepositoriesView.java
@@ -31,7 +31,9 @@
import org.eclipse.emf.cdo.util.ConcurrentAccessException;
import org.eclipse.net4j.util.container.IContainer;
+import org.eclipse.net4j.util.security.PasswordCredentials;
import org.eclipse.net4j.util.ui.UIUtil;
+import org.eclipse.net4j.util.ui.actions.LongRunningAction;
import org.eclipse.net4j.util.ui.views.ContainerItemProvider;
import org.eclipse.net4j.util.ui.views.ContainerView;
@@ -41,12 +43,14 @@
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.GroupMarker;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.TreeExpansionEvent;
@@ -77,6 +81,8 @@
public static final String SHOW_IN_MENU_ID = ID + ".ShowInMenu";
+ private static final String GROUP_SECURITY = "group.security";
+
private final ActivityDetector activityDetector = new ActivityDetector();
private CDORepositoryItemProvider itemProvider;
@@ -233,6 +239,8 @@
manager.add(new Separator("group.port"));
manager.add(new Separator("group.build"));
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
+ manager.add(new Separator(GROUP_SECURITY));
+ manager.add(new Separator("group.close"));
manager.add(new Separator("group.properties"));
IWorkbenchPage page = getSite().getPage();
@@ -247,6 +255,16 @@
manager.appendToGroup(ICommonMenuConstants.GROUP_OPEN, showInMenu);
}
+ if (selectedElement instanceof CDORepository)
+ {
+ CDORepository repository = (CDORepository)selectedElement;
+ CDOSession session = repository.getSession();
+ if (session != null)
+ {
+ manager.appendToGroup(GROUP_SECURITY, new ChangeServerPasswordAction(page, repository));
+ }
+ }
+
if (propertiesAction.isApplicableForSelection())
{
manager.appendToGroup("group.properties", propertiesAction);
@@ -397,4 +415,39 @@
newRepository(shell);
}
}
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class ChangeServerPasswordAction extends LongRunningAction
+ {
+ private static final String TITLE = "Change Server Password";
+
+ private final CDORepository repository;
+
+ public ChangeServerPasswordAction(IWorkbenchPage page, CDORepository repository)
+ {
+ super(page, TITLE + INTERACTIVE);
+ this.repository = repository;
+ }
+
+ @Override
+ protected void doRun(IProgressMonitor progressMonitor) throws Exception
+ {
+ CDOSession session = repository.getSession();
+ if (session != null)
+ {
+ // Opens the org.eclipse.net4j.util.ui.security.CredentialsUpdateDialog.
+ char[] newPassword = session.changeServerPassword();
+
+ UIUtil.asyncExec(getDisplay(), () -> {
+ if (MessageDialog.openQuestion(getShell(), TITLE, "Adjust login credentials, accordingly?"))
+ {
+ String userID = repository.getCredentials().getUserID();
+ repository.setCredentials(new PasswordCredentials(userID, newPassword));
+ }
+ });
+ }
+ }
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/repositories/CDORepository.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/repositories/CDORepository.java
index 96005e9..9ba9e41 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/repositories/CDORepository.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/explorer/repositories/CDORepository.java
@@ -24,6 +24,7 @@
import org.eclipse.net4j.util.container.IManagedContainer;
import org.eclipse.net4j.util.security.IPasswordCredentials;
import org.eclipse.net4j.util.security.IPasswordCredentialsProvider2;
+import org.eclipse.net4j.util.security.IPasswordCredentialsUpdateProvider;
/**
* A CDO server independent representation of a repository.
@@ -33,8 +34,13 @@
* @noextend This interface is not intended to be extended by clients.
* @noimplement This interface is not intended to be implemented by clients.
*/
-public interface CDORepository
- extends CDOExplorerElement, IContainer<CDOBranch>, IPasswordCredentialsProvider2, CDOSessionProvider, CDOViewOpener, CDOTransactionOpener
+public interface CDORepository extends CDOExplorerElement, //
+ IContainer<CDOBranch>, //
+ IPasswordCredentialsProvider2, //
+ IPasswordCredentialsUpdateProvider, //
+ CDOSessionProvider, //
+ CDOViewOpener, //
+ CDOTransactionOpener
{
public static final String TYPE_REMOTE = "remote";
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryImpl.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryImpl.java
index 3f466aa..ffefa0c 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryImpl.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryImpl.java
@@ -38,6 +38,8 @@
import org.eclipse.net4j.Net4jUtil;
import org.eclipse.net4j.connector.IConnector;
+import org.eclipse.net4j.util.ConsumerWithException;
+import org.eclipse.net4j.util.ReflectUtil;
import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.UUIDGenerator;
import org.eclipse.net4j.util.container.ContainerEvent;
@@ -49,8 +51,14 @@
import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
import org.eclipse.net4j.util.om.OMPlatform;
+import org.eclipse.net4j.util.security.CredentialsProviderFactory;
+import org.eclipse.net4j.util.security.CredentialsUpdateOperation;
+import org.eclipse.net4j.util.security.ICredentialsProvider;
import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.security.IPasswordCredentialsUpdate;
+import org.eclipse.net4j.util.security.IPasswordCredentialsUpdateProvider;
import org.eclipse.net4j.util.security.PasswordCredentials;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
@@ -197,54 +205,80 @@
@Override
public IPasswordCredentials getCredentials(String realm)
{
- try
- {
- ISecurePreferences securePreferences = getSecurePreferences();
- if (securePreferences != null)
+ IPasswordCredentials[] result = { null };
+
+ withSecureNode(false, node -> {
+ String userID = node.get("username", null);
+ if (!StringUtil.isEmpty(userID))
{
- String path = getSecurePath(securePreferences);
- if (securePreferences.nodeExists(path))
- {
- ISecurePreferences node = securePreferences.node(path);
- String userID = node.get("username", null);
-
- if (!StringUtil.isEmpty(userID))
- {
- String password = node.get("password", null);
- return new PasswordCredentials(userID, password);
- }
- }
+ String password = node.get("password", null);
+ result[0] = new PasswordCredentials(userID, password);
}
- }
- catch (Exception ex)
- {
- OM.LOG.error(ex);
- }
+ });
- return null;
+ return result[0];
}
@Override
public void setCredentials(IPasswordCredentials credentials)
{
- try
+ if (credentials == null)
{
- ISecurePreferences securePreferences = getSecurePreferences();
- if (securePreferences != null)
- {
- String path = getSecurePath(securePreferences);
- ISecurePreferences node = securePreferences.node(path);
-
- node.put("uri", getURI(), false);
- node.put("username", credentials.getUserID(), false);
- node.put("password", new String(credentials.getPassword()), true);
+ // Delete node.
+ withSecureNode(false, node -> {
+ node.removeNode();
node.flush();
+ });
+
+ return;
+ }
+
+ String password = SecurityUtil.toString(credentials.getPassword());
+
+ withSecureNode(true, node -> {
+ node.put("uri", getURI(), false);
+ node.put("username", credentials.getUserID(), false);
+
+ if (password == null)
+ {
+ node.remove("password");
+ }
+ else
+ {
+ node.put("password", password, true);
+ }
+
+ node.flush();
+ });
+ }
+
+ @Override
+ public IPasswordCredentialsUpdate getCredentialsUpdate(String userID, CredentialsUpdateOperation operation)
+ {
+ return getCredentialsUpdate(null, userID, operation);
+ }
+
+ @Override
+ public IPasswordCredentialsUpdate getCredentialsUpdate(String realm, String userID, CredentialsUpdateOperation operation)
+ {
+ IManagedContainer container = getContainer();
+
+ ICredentialsProvider provider = container.getElementOrNull(CredentialsProviderFactory.PRODUCT_GROUP, "cdo-explorer", null);
+ if (provider == null)
+ {
+ provider = container.getElementOrNull(CredentialsProviderFactory.PRODUCT_GROUP, "interactive", null);
+ if (provider == null)
+ {
+ provider = container.getElementOrNull(CredentialsProviderFactory.PRODUCT_GROUP, "default", null);
}
}
- catch (Exception ex)
+
+ if (provider instanceof IPasswordCredentialsUpdateProvider)
{
- OM.LOG.error(ex);
+ return ((IPasswordCredentialsUpdateProvider)provider).getCredentialsUpdate(realm, userID, operation);
}
+
+ return null;
}
@Override
@@ -329,8 +363,13 @@
@Override
public final void disconnect()
{
+ disconnect(false);
+ }
+
+ public final void disconnect(boolean force)
+ {
explicitlyConnected = false;
- doDisconnect(false);
+ doDisconnect(force);
}
protected void doDisconnect(boolean force)
@@ -452,6 +491,9 @@
{
disconnect();
+ // Delete secure preference node.
+ setCredentials(null);
+
CDORepositoryManagerImpl manager = getManager();
if (manager != null)
{
@@ -739,7 +781,7 @@
return config;
}
- protected CDOSession openSession()
+ public CDOSession openSession()
{
CDOSessionConfiguration sessionConfiguration = createSessionConfiguration();
sessionConfiguration.setPassiveUpdateEnabled(true);
@@ -766,6 +808,27 @@
session.close();
}
+ private void withSecureNode(boolean createOnDemand, ConsumerWithException<ISecurePreferences, Exception> consumer)
+ {
+ try
+ {
+ ISecurePreferences securePreferences = getSecurePreferences();
+ if (securePreferences != null)
+ {
+ String path = getSecurePath(securePreferences);
+ if (createOnDemand || securePreferences.nodeExists(path))
+ {
+ ISecurePreferences node = securePreferences.node(path);
+ consumer.accept(node);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+
private String getSecurePath(ISecurePreferences securePreferences)
{
String stateLocation = OM.getStateLocation().replace('/', '\\');
@@ -779,6 +842,38 @@
Map<Object, Object> options = new HashMap<>();
options.put(IProviderHints.PROMPT_USER, Boolean.FALSE);
- return SecurePreferencesFactory.open(null, options);
+ ISecurePreferences result = SecurePreferencesFactory.open(null, options);
+ if (result != null)
+ {
+ // Try to refresh the entire secure storage, if needed.
+ try
+ {
+ // Fetch the root node.
+ Object root = ReflectUtil.getValue("node", result); //$NON-NLS-1$
+
+ // Just to be sure...
+ root = ReflectUtil.invokeMethod("getRoot", root); //$NON-NLS-1$
+
+ // Check if it has been modified, i.e., whether it is dirty from unsaved changes.
+ boolean modified = ReflectUtil.invokeMethod("isModified", root); //$NON-NLS-1$
+ if (!modified)
+ {
+ // If it's not dirty, check if the expected time stamp is different from the timestamp on disk.
+ long lastModified = ReflectUtil.invokeMethod("getLastModified", root); //$NON-NLS-1$
+ long timestamp = ReflectUtil.getValue("timestamp", root); //$NON-NLS-1$
+ if (lastModified != timestamp)
+ {
+ // If so, reload the secure storage from disk.
+ ReflectUtil.invokeMethod("load", root); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (Throwable ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+
+ return result;
}
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryManagerImpl.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryManagerImpl.java
index 2214167..2e97c13 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryManagerImpl.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CDORepositoryManagerImpl.java
@@ -79,7 +79,7 @@
public CDORepository addRepository(Properties properties, IPasswordCredentials credentials)
{
CDORepository repository = newElement(properties);
- if (repository != null && credentials != null)
+ if (repository != null)
{
repository.setCredentials(credentials);
}
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CloneCDORepository.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CloneCDORepository.java
index b63143a..111e826 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CloneCDORepository.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/CloneCDORepository.java
@@ -145,7 +145,7 @@
}
@Override
- protected CDOSession openSession()
+ public CDOSession openSession()
{
final String repositoryName = getName();
File folder = new File(getFolder(), "db");
diff --git a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/LocalCDORepository.java b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/LocalCDORepository.java
index bdb2631..8410d0c 100644
--- a/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/LocalCDORepository.java
+++ b/plugins/org.eclipse.emf.cdo.explorer/src/org/eclipse/emf/cdo/internal/explorer/repositories/LocalCDORepository.java
@@ -124,7 +124,7 @@
}
@Override
- protected CDOSession openSession()
+ public CDOSession openSession()
{
String repositoryName = getName();
File folder = new File(getFolder(), "db");
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
index 540eb7e..726ad33 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/CDONet4jSessionImpl.java
@@ -47,6 +47,8 @@
import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
import org.eclipse.emf.spi.cdo.CDOSessionProtocol.OpenSessionResult;
+import java.util.concurrent.atomic.AtomicReference;
+
/**
* @author Eike Stepper
*/
@@ -113,14 +115,28 @@
}
@Override
+ @Deprecated
public void changeCredentials()
{
+ changeServerPassword();
// Send a request to the server to initiate (from the server) the password change protocol
CDOSessionProtocol sessionProtocol = getSessionProtocol();
sessionProtocol.requestChangeCredentials();
}
@Override
+ public char[] changeServerPassword()
+ {
+ AtomicReference<char[]> result = new AtomicReference<>();
+
+ // Send a request to the server to initiate (from the server) the password change protocol
+ CDOSessionProtocol sessionProtocol = getSessionProtocol();
+ sessionProtocol.requestChangeServerPassword(result);
+
+ return result.getAndSet(null);
+ }
+
+ @Override
public void resetCredentials(String userID)
{
// Send a request to the server to initiate (from the server) the password reset protocol
@@ -170,6 +186,7 @@
setSessionID(result.getSessionID());
setUserID(result.getUserID());
setLastUpdateTime(result.getLastUpdateTime());
+ setOpeningTime(result.getOpeningTime());
setRepositoryInfo(new RepositoryInfo(this, result));
return result;
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
index 07ec238..3c7626a 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CDOClientProtocol.java
@@ -65,7 +65,6 @@
import org.eclipse.net4j.util.om.monitor.Monitor;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.trace.PerfTracer;
-import org.eclipse.net4j.util.security.CredentialsUpdateOperation;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
@@ -83,6 +82,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
@@ -605,15 +605,22 @@
}
@Override
+ @Deprecated
public void requestChangeCredentials()
{
- send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.CHANGE_PASSWORD, null), new Monitor());
+ requestChangeServerPassword(null);
+ }
+
+ @Override
+ public void requestChangeServerPassword(AtomicReference<char[]> receiver)
+ {
+ send(new ChangeCredentialsRequest(this, receiver), new Monitor());
}
@Override
public void requestResetCredentials(String userID)
{
- send(new ChangeCredentialsRequest(this, CredentialsUpdateOperation.RESET_PASSWORD, userID), new Monitor());
+ send(new ChangeCredentialsRequest(this, userID), new Monitor());
}
@Override
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/ChangeCredentialsRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/ChangeCredentialsRequest.java
index 2e7dd55..8efde92 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/ChangeCredentialsRequest.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/ChangeCredentialsRequest.java
@@ -14,12 +14,16 @@
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
+import org.eclipse.emf.cdo.session.CDOSession;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.net4j.util.security.CredentialsUpdateOperation;
import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Request from the client to the server to initiate (from the server) the change-credentials protocol.
@@ -28,23 +32,40 @@
*/
public class ChangeCredentialsRequest extends CDOClientRequestWithMonitoring<Boolean>
{
+ static final ConcurrentMap<CDOSession, AtomicReference<char[]>> NEW_PASSWORD_RECEIVERS = new ConcurrentHashMap<>();
+
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, ChangeCredentialsRequest.class);
private final CredentialsUpdateOperation operation;
+ private final AtomicReference<char[]> newPasswordReceiver;
+
private final String userID;
- public ChangeCredentialsRequest(CDOClientProtocol protocol, CredentialsUpdateOperation operation, String userID)
+ public ChangeCredentialsRequest(CDOClientProtocol protocol, AtomicReference<char[]> newPasswordReceiver)
{
super(protocol, CDOProtocolConstants.SIGNAL_CHANGE_CREDENTIALS);
+ operation = CredentialsUpdateOperation.CHANGE_PASSWORD;
+ this.newPasswordReceiver = newPasswordReceiver;
+ userID = null;
+ }
- this.operation = operation;
+ public ChangeCredentialsRequest(CDOClientProtocol protocol, String userID)
+ {
+ super(protocol, CDOProtocolConstants.SIGNAL_CHANGE_CREDENTIALS);
+ operation = CredentialsUpdateOperation.RESET_PASSWORD;
+ newPasswordReceiver = null;
this.userID = userID;
}
@Override
protected void requesting(CDODataOutput out, OMMonitor monitor) throws IOException
{
+ if (newPasswordReceiver != null)
+ {
+ NEW_PASSWORD_RECEIVERS.put(getSession(), newPasswordReceiver);
+ }
+
if (TRACER.isEnabled())
{
TRACER.format("Requesting %s of user credentials", operation); //$NON-NLS-1$
@@ -57,6 +78,13 @@
@Override
protected Boolean confirming(CDODataInput in, OMMonitor monitor) throws IOException
{
- return in.readBoolean();
+ try
+ {
+ return in.readBoolean();
+ }
+ finally
+ {
+ NEW_PASSWORD_RECEIVERS.remove(getSession());
+ }
}
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CredentialsChallengeIndication.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CredentialsChallengeIndication.java
index 527cffd..8526c84 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CredentialsChallengeIndication.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/CredentialsChallengeIndication.java
@@ -16,7 +16,6 @@
import org.eclipse.net4j.signal.IndicationWithMonitoring;
import org.eclipse.net4j.signal.SignalProtocol;
-import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.io.ExtendedDataInputStream;
import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
import org.eclipse.net4j.util.om.monitor.OMMonitor;
@@ -28,10 +27,12 @@
import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
import org.eclipse.net4j.util.security.IPasswordCredentialsUpdate;
import org.eclipse.net4j.util.security.IPasswordCredentialsUpdateProvider;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.emf.spi.cdo.InternalCDOSession;
import java.io.ByteArrayOutputStream;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Implementation of the CDO client handler for the server-initiated change-credentials protocol.
@@ -40,6 +41,8 @@
*/
public class CredentialsChallengeIndication extends IndicationWithMonitoring
{
+ private AtomicReference<char[]> newPasswordReceiver;
+
private Challenge challenge;
private CredentialsUpdateOperation operation;
@@ -49,6 +52,7 @@
public CredentialsChallengeIndication(SignalProtocol<?> protocol)
{
super(protocol, CDOProtocolConstants.SIGNAL_CREDENTIALS_CHALLENGE);
+ newPasswordReceiver = ChangeCredentialsRequest.NEW_PASSWORD_RECEIVERS.remove(getSession());
}
@Override
@@ -99,12 +103,8 @@
}
String authUserID = credentials.getUserID();
- String authPassword = new String(credentials.getPassword());
- String newPassword = new String(credentials.getNewPassword());
- if (StringUtil.isEmpty(newPassword))
- {
- throw new IllegalStateException("No new password provided"); //$NON-NLS-1$
- }
+ String authPassword = SecurityUtil.toString(credentials.getPassword());
+ String newPassword = SecurityUtil.toString(credentials.getNewPassword());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ExtendedDataOutputStream stream = new ExtendedDataOutputStream(baos);
@@ -115,7 +115,15 @@
stream.writeString(authUserID);
stream.writeString(authPassword);
stream.writeString(newPassword);
+
+ if (newPasswordReceiver != null)
+ {
+ newPasswordReceiver.set(credentials.getNewPassword());
+ newPasswordReceiver = null;
+ }
+
break;
+
case RESET_PASSWORD:
stream.writeString(authUserID);
stream.writeString(authPassword);
diff --git a/plugins/org.eclipse.emf.cdo.security.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.security.ui/META-INF/MANIFEST.MF
index 9fd34d5..44a264c 100644
--- a/plugins/org.eclipse.emf.cdo.security.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.security.ui/META-INF/MANIFEST.MF
@@ -1,19 +1,19 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.emf.cdo.security.ui;singleton:=true
-Bundle-Version: 4.5.0.qualifier
+Bundle-Version: 4.5.1.qualifier
Bundle-Localization: plugin
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-ClassPath: .
Bundle-RequiredExecutionEnvironment: JavaSE-11
-Export-Package: org.eclipse.emf.cdo.security.internal.ui.bundle;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.internal.ui.dialogs;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.internal.ui.editor;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.internal.ui.handlers;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.internal.ui.messages;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.internal.ui.util;version="4.5.0";x-internal:=true,
- org.eclipse.emf.cdo.security.ui;version="4.5.0"
+Export-Package: org.eclipse.emf.cdo.security.internal.ui.bundle;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.internal.ui.dialogs;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.internal.ui.editor;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.internal.ui.handlers;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.internal.ui.messages;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.internal.ui.util;version="4.5.1";x-internal:=true,
+ org.eclipse.emf.cdo.security.ui;version="4.5.1"
Require-Bundle: org.eclipse.emf.cdo.security;bundle-version="[4.3.0,5.0.0)",
org.eclipse.emf.cdo.security.edit;bundle-version="[4.1.0,5.0.0)",
org.eclipse.emf.cdo.ui;bundle-version="[4.3.0,5.0.0)",
diff --git a/plugins/org.eclipse.emf.cdo.security.ui/plugin.xml b/plugins/org.eclipse.emf.cdo.security.ui/plugin.xml
index aac0298..8a5a852 100644
--- a/plugins/org.eclipse.emf.cdo.security.ui/plugin.xml
+++ b/plugins/org.eclipse.emf.cdo.security.ui/plugin.xml
@@ -13,39 +13,60 @@
<plugin>
- <extension
- point="org.eclipse.ui.editors">
+ <extension point="org.eclipse.ui.editors">
<editor
class="org.eclipse.emf.cdo.security.internal.ui.editor.CDOSecurityFormEditor"
contributorClass="org.eclipse.emf.cdo.security.internal.ui.editor.CDOSecurityFormActionBarContributor"
default="false"
icon="icons/full/obj16/SecurityRealmResource.png"
id="org.eclipse.emf.cdo.security.ui.CDOSecurityFormEditor"
- name="%editor.name">
- </editor>
+ name="%editor.name"/>
</extension>
- <extension
- point="org.eclipse.ui.menus">
- <menuContribution
- locationURI="popup:org.eclipse.ui.popup.any?after=additions">
+ <extension point="org.eclipse.ui.commands">
+ <category
+ id="org.eclipse.emf.cdo.security.ui.management"
+ name="%category.name"/>
+ <command
+ id="org.eclipse.emf.cdo.security.ui.resetPassword"
+ categoryId="org.eclipse.emf.cdo.security.ui.management"
+ name="%command.name"
+ description="%command.description"
+ defaultHandler="org.eclipse.emf.cdo.security.internal.ui.handlers.ResetPasswordHandler"/>
+ <command
+ id="org.eclipse.emf.cdo.security.ui.openEditor"
+ name="%action.label.1"
+ categoryId="org.eclipse.emf.cdo.security.ui.management"
+ defaultHandler="org.eclipse.emf.cdo.security.internal.ui.handlers.ManageSecurityHandler"/>
+ </extension>
+
+ <extension point="org.eclipse.ui.handlers">
+ <handler
+ commandId="org.eclipse.emf.cdo.security.ui.openEditor"
+ class="org.eclipse.emf.cdo.security.internal.ui.handlers.ManageSecurityHandler$Sessionless">
+ <activeWhen>
+ <with variable="activeMenuSelection">
+ <iterate ifEmpty="false">
+ <adapt type="org.eclipse.emf.cdo.admin.CDOAdminClientRepository"/>
+ </iterate>
+ </with>
+ </activeWhen>
+ </handler>
+ </extension>
+
+ <extension point="org.eclipse.ui.menus">
+ <menuContribution locationURI="popup:org.eclipse.ui.popup.any?after=group.security">
<command
id="org.eclipse.emf.cdo.security.ui.ResetPasswordCommand"
commandId="org.eclipse.emf.cdo.security.ui.resetPassword"
label="%action.label"
tooltip="%action.tooltip"
style="push">
- <visibleWhen
- checkEnabled="false">
- <with
- variable="activeMenuSelection">
- <count
- value="1">
- </count>
- <iterate >
- <adapt
- type="org.eclipse.emf.cdo.security.User">
- </adapt>
+ <visibleWhen checkEnabled="false">
+ <with variable="activeMenuSelection">
+ <count value="1"/>
+ <iterate>
+ <adapt type="org.eclipse.emf.cdo.security.User"/>
</iterate>
</with>
</visibleWhen>
@@ -55,22 +76,15 @@
icon="$nl$/icons/full/ctool16/ManageSecurity.png"
label="%action.label.1"
style="push">
- <visibleWhen
- checkEnabled="false">
- <with
- variable="activeMenuSelection">
- <count
- value="1">
- </count>
- <iterate >
+ <visibleWhen checkEnabled="false">
+ <with variable="activeMenuSelection">
+ <count value="1"/>
+ <iterate>
<or>
- <adapt
- type="org.eclipse.emf.cdo.session.CDOSession">
- <test property="org.eclipse.emf.cdo.session.userAuthenticated" />
+ <adapt type="org.eclipse.emf.cdo.session.CDOSession">
+ <test property="org.eclipse.emf.cdo.session.userAuthenticated"/>
</adapt>
- <adapt
- type="org.eclipse.emf.cdo.admin.CDOAdminClientRepository">
- </adapt>
+ <adapt type="org.eclipse.emf.cdo.admin.CDOAdminClientRepository"/>
</or>
</iterate>
</with>
@@ -79,42 +93,4 @@
</menuContribution>
</extension>
- <extension
- point="org.eclipse.ui.commands">
- <category
- id="org.eclipse.emf.cdo.security.ui.management"
- name="%category.name">
- </category>
- <command
- id="org.eclipse.emf.cdo.security.ui.resetPassword"
- categoryId="org.eclipse.emf.cdo.security.ui.management"
- name="%command.name"
- description="%command.description"
- defaultHandler="org.eclipse.emf.cdo.security.internal.ui.handlers.ResetPasswordHandler">
- </command>
- <command
- id="org.eclipse.emf.cdo.security.ui.openEditor"
- name="%action.label.1"
- categoryId="org.eclipse.emf.cdo.security.ui.management"
- defaultHandler="org.eclipse.emf.cdo.security.internal.ui.handlers.ManageSecurityHandler">
- </command>
- </extension>
-
- <extension
- point="org.eclipse.ui.handlers">
- <handler
- commandId="org.eclipse.emf.cdo.security.ui.openEditor"
- class="org.eclipse.emf.cdo.security.internal.ui.handlers.ManageSecurityHandler$Sessionless">
- <activeWhen>
- <with
- variable="activeMenuSelection">
- <iterate ifEmpty="false">
- <adapt
- type="org.eclipse.emf.cdo.admin.CDOAdminClientRepository">
- </adapt>
- </iterate>
- </with>
- </activeWhen>
- </handler>
- </extension>
</plugin>
diff --git a/plugins/org.eclipse.emf.cdo.security.ui/pom.xml b/plugins/org.eclipse.emf.cdo.security.ui/pom.xml
index 5d9a79a..d8fabdf 100644
--- a/plugins/org.eclipse.emf.cdo.security.ui/pom.xml
+++ b/plugins/org.eclipse.emf.cdo.security.ui/pom.xml
@@ -25,7 +25,7 @@
<groupId>org.eclipse.emf.cdo</groupId>
<artifactId>org.eclipse.emf.cdo.security.ui</artifactId>
- <version>4.5.0-SNAPSHOT</version>
+ <version>4.5.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
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 c11406d..db90e7a 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 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.emf.cdo.security;singleton:=true
-Bundle-Version: 4.4.1.qualifier
+Bundle-Version: 4.5.0.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.5.0";
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.5.0";x-internal:=true,
+ org.eclipse.emf.cdo.security;version="4.5.0",
+ org.eclipse.emf.cdo.security.impl;version="4.5.0",
+ org.eclipse.emf.cdo.security.util;version="4.5.0"
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 58f4a44..5b53e49 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.5.0-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 d5bffab..304c7ac 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 @@
/**
* @author Eike Stepper
*/
+@FunctionalInterface
public interface ViewCreator
{
public CDOView createView(CDORevisionProvider revisionProvider);
diff --git a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/Role.java b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/Role.java
index e19f672..53ed395 100644
--- a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/Role.java
+++ b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/Role.java
@@ -37,11 +37,6 @@
/**
* @since 4.3
*/
- public static final String ADMINISTRATION = "Administration";
-
- /**
- * @since 4.3
- */
public static final String RESOURCE_TREE_WRITER = "Resource Tree Writer";
/**
@@ -60,6 +55,21 @@
public static final String ALL_OBJECTS_READER = "All Objects Reader";
/**
+ * @since 4.5
+ */
+ public static final String NORMAL_OBJECTS_WRITER = "Normal Objects Writer";
+
+ /**
+ * @since 4.5
+ */
+ public static final String NORMAL_OBJECTS_READER = "Normal Objects Reader";
+
+ /**
+ * @since 4.3
+ */
+ public static final String ADMINISTRATION = "Administration";
+
+ /**
* Returns the value of the '<em><b>Assignees</b></em>' reference list.
* The list contents are of type {@link org.eclipse.emf.cdo.security.Assignee}.
* It is bidirectional and its opposite is '{@link org.eclipse.emf.cdo.security.Assignee#getRoles <em>Roles</em>}'.
diff --git a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/DirectoryImpl.java b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/DirectoryImpl.java
index 22b7fa1..8f1e2b8 100644
--- a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/DirectoryImpl.java
+++ b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/DirectoryImpl.java
@@ -20,6 +20,7 @@
import org.eclipse.emf.cdo.security.User;
import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
@@ -172,7 +173,7 @@
@Override
public User addUser(IPasswordCredentials credentials)
{
- return addUser(credentials.getUserID(), new String(credentials.getPassword()));
+ return addUser(credentials.getUserID(), SecurityUtil.toString(credentials.getPassword()));
}
/**
diff --git a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/RealmImpl.java b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/RealmImpl.java
index cba059c..5f4f753 100644
--- a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/RealmImpl.java
+++ b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/RealmImpl.java
@@ -23,7 +23,9 @@
import org.eclipse.emf.cdo.security.User;
import org.eclipse.emf.cdo.security.UserPassword;
+import org.eclipse.net4j.util.StringUtil;
import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
@@ -441,7 +443,7 @@
@Override
public User addUser(IPasswordCredentials credentials)
{
- return addUser(credentials.getUserID(), new String(credentials.getPassword()));
+ return addUser(credentials.getUserID(), SecurityUtil.toString(credentials.getPassword()));
}
/**
@@ -461,7 +463,7 @@
public User setPassword(String id, String password)
{
UserPassword userPassword = null;
- if (password != null && password.length() != 0)
+ if (!StringUtil.isEmpty(password))
{
userPassword = SecurityFactory.eINSTANCE.createUserPassword();
userPassword.setEncrypted(password);
diff --git a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/ResourceFilterImpl.java b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/ResourceFilterImpl.java
index de10f9c..5ba7590 100644
--- a/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/ResourceFilterImpl.java
+++ b/plugins/org.eclipse.emf.cdo.security/src/org/eclipse/emf/cdo/security/impl/ResourceFilterImpl.java
@@ -14,6 +14,7 @@
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionData;
import org.eclipse.emf.cdo.common.revision.CDORevisionProvider;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
@@ -397,7 +398,9 @@
{
resourceNode = true;
- boolean rootResource = CDOIDUtil.isNull((CDOID)((InternalCDORevision)revision).getContainerID());
+ CDORevisionData revisionData = revision.data();
+ boolean rootResource = CDOIDUtil.isNull((CDOID)revisionData.getContainerID()) && CDOIDUtil.isNull(revisionData.getResourceID());
+
if (rootResource)
{
if (!isIncludeRoot())
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.net4j/META-INF/MANIFEST.MF
index 7fd682d..86b62a2 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/META-INF/MANIFEST.MF
@@ -1,7 +1,7 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.emf.cdo.server.net4j;singleton:=true
-Bundle-Version: 4.3.0.qualifier
+Bundle-Version: 4.3.1.qualifier
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
Bundle-Localization: plugin
@@ -12,7 +12,7 @@
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)";resolution:=optional,
org.eclipse.emf.cdo.server;bundle-version="[4.0.0,5.0.0)";visibility:=reexport,
org.eclipse.net4j;bundle-version="[4.0.0,5.0.0)";visibility:=reexport
-Export-Package: org.eclipse.emf.cdo.server.internal.net4j.bundle;version="4.3.0";x-internal:=true,
- org.eclipse.emf.cdo.server.internal.net4j.protocol;version="4.3.0";x-friends:="org.eclipse.emf.cdo.tests",
- org.eclipse.emf.cdo.server.net4j;version="4.3.0"
+Export-Package: org.eclipse.emf.cdo.server.internal.net4j.bundle;version="4.3.1";x-internal:=true,
+ org.eclipse.emf.cdo.server.internal.net4j.protocol;version="4.3.1";x-friends:="org.eclipse.emf.cdo.tests",
+ org.eclipse.emf.cdo.server.net4j;version="4.3.1"
Automatic-Module-Name: org.eclipse.emf.cdo.server.net4j
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/pom.xml b/plugins/org.eclipse.emf.cdo.server.net4j/pom.xml
index 7d63a70..f3c5b94 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/pom.xml
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/pom.xml
@@ -25,7 +25,7 @@
<groupId>org.eclipse.emf.cdo</groupId>
<artifactId>org.eclipse.emf.cdo.server.net4j</artifactId>
- <version>4.3.0-SNAPSHOT</version>
+ <version>4.3.1-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/bundle/Net4jAppExtension.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/bundle/Net4jAppExtension.java
index c368ba9..0744a35 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/bundle/Net4jAppExtension.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/bundle/Net4jAppExtension.java
@@ -10,7 +10,7 @@
*/
package org.eclipse.emf.cdo.server.internal.net4j.bundle;
-import org.eclipse.emf.cdo.spi.server.IAppExtension;
+import org.eclipse.emf.cdo.spi.server.IAppExtension4;
import org.eclipse.net4j.TransportConfigurator;
import org.eclipse.net4j.acceptor.IAcceptor;
@@ -22,7 +22,7 @@
/**
* @author Eike Stepper
*/
-public class Net4jAppExtension implements IAppExtension
+public class Net4jAppExtension implements IAppExtension4
{
private IAcceptor[] acceptors;
@@ -31,6 +31,12 @@
}
@Override
+ public int getPriority()
+ {
+ return PRIORITY_NETWORK;
+ }
+
+ @Override
public void start(File configFile) throws Exception
{
OM.LOG.info("Net4j extension starting"); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java
index cb1c877..52faaf9 100644
--- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java
+++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/OpenSessionIndication.java
@@ -201,6 +201,7 @@
out.writeXLong(repository.getCreationTime());
out.writeXLong(session.getFirstUpdateTime());
+ out.writeXLong(session.getOpeningTime());
out.writeXInt(repository.getBranchManager().getTagModCount());
out.writeCDOID(repository.getRootResourceID());
out.writeBoolean(repository.isAuthenticating());
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 1a4bfdf..89a7da1 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,23 +2,23 @@
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
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.emf.cdo.server;bundle-version="[4.1.0,5.0.0)",
- org.eclipse.emf.cdo.security;bundle-version="[4.1.0,5.0.0)",
+ org.eclipse.emf.cdo.server;bundle-version="[4.1.0,5.0.0)";visibility:=reexport,
+ org.eclipse.emf.cdo.security;bundle-version="[4.1.0,5.0.0)";visibility:=reexport,
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 5fd8edb..1951fa1 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/SecurityExtension.java b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
index 67c34fe..12eb0ed 100644
--- a/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
+++ b/plugins/org.eclipse.emf.cdo.server.security/src/org/eclipse/emf/cdo/server/internal/security/SecurityExtension.java
@@ -15,6 +15,7 @@
import org.eclipse.emf.cdo.server.internal.security.bundle.OM;
import org.eclipse.emf.cdo.server.spi.security.SecurityManagerFactory;
import org.eclipse.emf.cdo.spi.server.IAppExtension2;
+import org.eclipse.emf.cdo.spi.server.IAppExtension4;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.RepositoryFactory;
@@ -38,7 +39,7 @@
/**
* @author Eike Stepper
*/
-public class SecurityExtension implements IAppExtension2
+public class SecurityExtension implements IAppExtension2, IAppExtension4
{
public static final String DEFAULT_REALM_PATH = "security";
@@ -47,6 +48,12 @@
}
@Override
+ public int getPriority()
+ {
+ return PRIORITY_SECURITY;
+ }
+
+ @Override
public void start(File configFile) throws Exception
{
start(getDocument(configFile));
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 ebffb83..22e91db 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 @@
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.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,8 @@
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.StringUtil;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.HashBag;
import org.eclipse.net4j.util.concurrent.TimeoutRuntimeException;
@@ -80,10 +88,13 @@
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.OMPlatform;
+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;
import org.eclipse.net4j.util.security.IPasswordCredentials;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
@@ -93,18 +104,36 @@
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;
+import java.util.function.Consumer;
/**
* @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 boolean DISABLE_DETACH_CHECKS = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.server.security.DISABLE_DETACH_CHECKS");
+
+ private static final boolean ALLOW_EMPTY_PASSWORDS = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.server.security.ALLOW_EMPTY_PASSWORDS");
+
+ private static final Consumer<String> EMPTY_PASSWORD_PREVENTER = pw -> {
+ if (StringUtil.isEmpty(pw))
+ {
+ throw new SecurityException("Password is empty");
+ }
+ };
private static final SecurityFactory SF = SecurityFactory.eINSTANCE;
@@ -119,7 +148,7 @@
@Override
protected void onDeactivated(ILifecycle lifecycle)
{
- SECURITY_MANAGERS.remove(getRepository());
+ unregister(repository);
SecurityManager.this.deactivate();
}
};
@@ -127,13 +156,19 @@
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 +187,7 @@
{
if (clearUserInfos)
{
- clearUserInfos();
+ clearUserInfos(true);
clearUserInfos = false;
}
}
@@ -169,7 +204,9 @@
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<>();
@@ -181,21 +218,25 @@
private PermissionImpl[] permissionArray = {};
+ private Consumer<String> passwordValidator = ALLOW_EMPTY_PASSWORDS ? null : EMPTY_PASSWORD_PREVENTER;
+
private InternalRepository repository;
private IAcceptor acceptor;
private IConnector connector;
- private CDONet4jSession systemSession;
+ private CDONet4jSession realmSession;
- private CDOView systemView;
+ private CDOView realmView;
private Realm realm;
private CDOID realmID;
- private long lastRealmModification = CDOBranchPoint.UNSPECIFIED_DATE;
+ private volatile Long lastRealmModification;
+
+ private Object lastRealmModificationLock = new Object();
public SecurityManager(String realmPath, IManagedContainer container)
{
@@ -216,7 +257,7 @@
}
@Override
- public final IRepository getRepository()
+ public final InternalRepository getRepository()
{
return repository;
}
@@ -232,6 +273,41 @@
}
@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();
+ }
+ }
+
+ public Consumer<String> getPasswordValidator()
+ {
+ return passwordValidator;
+ }
+
+ public void setPasswordValidator(Consumer<String> passwordValidator)
+ {
+ checkInactive();
+ this.passwordValidator = passwordValidator;
+ }
+
+ @Override
public Realm getRealm()
{
return realm;
@@ -274,66 +350,40 @@
}
@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)
+ User[] result = { null };
+ modify(realm -> {
+ result[0] = realm.addUser(id);
+
+ if (!StringUtil.isEmpty(password))
{
UserPassword userPassword = SF.createUserPassword();
userPassword.setEncrypted(new String(password));
-
- result[0] = realm.addUser(id);
result[0].setPassword(userPassword);
}
});
@@ -344,70 +394,43 @@
@Override
public User addUser(IPasswordCredentials credentials)
{
- return addUser(credentials.getUserID(), new String(credentials.getPassword()));
+ return addUser(credentials.getUserID(), SecurityUtil.toString(credentials.getPassword()));
}
@Override
- public User setPassword(final String id, final String password)
+ public User setPassword(String id, String password)
{
- final User[] result = { null };
- modify(new RealmOperation()
+ if (passwordValidator != null)
{
- @Override
- public void execute(Realm realm)
- {
- result[0] = realm.setPassword(id, password);
- }
- });
+ passwordValidator.accept(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 +457,7 @@
public CDOCommitInfo modifyWithInfo(RealmOperation operation, boolean waitUntilReadable)
{
checkReady();
- CDOTransaction transaction = systemSession.openTransaction();
+ CDOTransaction transaction = realmSession.openTransaction();
try
{
@@ -444,7 +467,7 @@
if (waitUntilReadable)
{
- if (!systemView.waitForUpdate(info.getTimeStamp(), 10000))
+ if (!realmView.waitForUpdate(info.getTimeStamp(), 10000))
{
throw new TimeoutRuntimeException();
}
@@ -566,7 +589,7 @@
*/
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 +628,11 @@
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 +664,10 @@
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();
@@ -653,7 +676,7 @@
sessionManager.addListener(sessionManagerListener);
repository.addHandler(writeAccessHandler);
- SECURITY_MANAGERS.put(repository, this);
+ register(repository);
initCommitHandlers(firstTime);
}
@@ -672,6 +695,14 @@
Role allWriterRole = realm.addRole(Role.ALL_OBJECTS_WRITER);
allWriterRole.getPermissions().add(SF.createFilterPermission(Access.WRITE, SF.createResourceFilter(".*", PatternStyle.REGEX)));
+ Role normalReaderRole = realm.addRole(Role.NORMAL_OBJECTS_READER);
+ normalReaderRole.getPermissions()
+ .add(SF.createFilterPermission(Access.READ, SF.createNotFilter(SF.createResourceFilter(realmPath, PatternStyle.EXACT, false))));
+
+ Role normalWriterRole = realm.addRole(Role.NORMAL_OBJECTS_WRITER);
+ normalWriterRole.getPermissions()
+ .add(SF.createFilterPermission(Access.WRITE, SF.createNotFilter(SF.createResourceFilter(realmPath, PatternStyle.EXACT, false))));
+
Role treeReaderRole = realm.addRole(Role.RESOURCE_TREE_READER);
treeReaderRole.getPermissions().add(SF.createFilterPermission(Access.READ, SF.createPackageFilter(EresourcePackage.eINSTANCE)));
@@ -704,11 +735,11 @@
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;
@@ -724,15 +755,7 @@
protected CDOPermission authorize(CDORevision revision, CDORevisionProvider revisionProvider, CDOBranchPoint securityContext, ISession session,
Access defaultAccess, Permission[] permissions)
{
- if (lastRealmModification != CDOBranchPoint.UNSPECIFIED_DATE)
- {
- if (!systemView.waitForUpdate(lastRealmModification, 10000L))
- {
- throw new TimeoutRuntimeException();
- }
-
- lastRealmModification = CDOBranchPoint.UNSPECIFIED_DATE;
- }
+ waitForRealmUpdate(securityContext);
boolean setUser = defaultAccess == null;
if (setUser)
@@ -786,80 +809,219 @@
}
}
- 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)
- {
- userInfo = addUserInfo(session);
- }
+ ITransaction transaction = commitContext.getTransaction();
+ ISession session = transaction.getSession();
- return userInfo;
- }
+ Access userDefaultAccess = userInfo.getDefaultAccess();
+ Permission[] userPermissions = userInfo.getPermissions();
- protected UserInfo addUserInfo(ISession session)
- {
- String userID = session.getUserID();
- User user = getUser(userID);
- UserInfo userInfo = new UserInfo(user);
-
- synchronized (userInfos)
- {
- userInfos.put(session, userInfo);
-
- Permission[] permissions = userInfo.getPermissions();
- for (int i = 0; i < permissions.length; i++)
+ if (!DISABLE_DETACH_CHECKS)
{
- Permission permission = permissions[i];
- permissionBag.add((PermissionImpl)permission);
+ CDOID[] detachedObjects = commitContext.getDetachedObjects();
+ if (detachedObjects != null && detachedObjects.length != 0)
+ {
+ for (int i = 0; i < detachedObjects.length; i++)
+ {
+ CDOID id = detachedObjects[i];
+ CDORevision revision = transaction.getRevision(id);
+
+ CDOPermission permission = authorize(revision, transaction, securityContext, session, userDefaultAccess, userPermissions);
+ if (permission != CDOPermission.WRITE)
+ {
+ throw new SecurityException("User " + commitContext.getUserID() + " is not allowed to detach " + revision);
+ }
+ }
+ }
}
- // Atomic update
- permissionArray = permissionBag.toArray(new PermissionImpl[permissionBag.size()]);
+ 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
+ {
+ PermissionUtil.setUser(null);
+ PermissionUtil.doneViewCreation();
+ }
+ }
+
+ protected void sessionAdded(ISession session)
+ {
+ String userID = session.getUserID();
+ if (userID != null)
+ {
+ UserInfo result = userInfos.computeIfAbsent(userID, k -> {
+ User user = getUser(k);
+ UserInfo userInfo = new UserInfo(user);
+ updatePermissions(userInfo, true);
+ return userInfo;
+ });
+
+ result.addSessionRef();
+ }
+ }
+
+ protected void sessionRemoved(ISession session)
+ {
+ String userID = session.getUserID();
+ if (userID != null)
+ {
+ userInfos.computeIfPresent(userID, (k, v) -> {
+ if (v.removeSessionRef())
+ {
+ return null;
+ }
+
+ 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 (UserInfo userInfo : userInfos.values())
+ {
+ userInfo.rebuildPermissions();
+ updatePermissions(userInfo, false);
+ }
+
+ updatePermissions(null, true);
+ }
+ else
+ {
+ userInfos.clear();
+ }
+ }
+ }
+
+ protected void updatePermissions(UserInfo userInfo, boolean updateArray)
+ {
+ Permission[] permissions = userInfo == null ? null : userInfo.getPermissions();
+
+ synchronized (permissionBag)
+ {
+ if (permissions != null)
+ {
for (int i = 0; i < permissions.length; i++)
{
Permission permission = permissions[i];
- permissionBag.remove(permission);
+ permissionBag.add((PermissionImpl)permission);
}
+ }
+ if (updateArray)
+ {
// Atomic update
permissionArray = permissionBag.toArray(new PermissionImpl[permissionBag.size()]);
}
}
-
- return userInfo;
- }
-
- protected void clearUserInfos()
- {
- synchronized (userInfos)
- {
- // System.out.println("clearUserInfos()");
-
- userInfos.clear();
- permissionBag.clear();
- permissionArray = null;
- }
}
protected final boolean isAdministrator(User user)
@@ -895,14 +1057,14 @@
@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;
@@ -913,6 +1075,60 @@
super.doDeactivate();
}
+ private void rememberRealmCommit(CDOBranchPoint commitBranchPoint)
+ {
+ synchronized (lastRealmModificationLock)
+ {
+ lastRealmModification = commitBranchPoint.getTimeStamp();
+ }
+ }
+
+ private void waitForRealmUpdate(CDOBranchPoint securityContext)
+ {
+ if (lastRealmModification != null)
+ {
+ long updateTime;
+
+ synchronized (lastRealmModificationLock)
+ {
+ if (lastRealmModification != null)
+ {
+ updateTime = lastRealmModification;
+ lastRealmModification = null;
+ }
+ else
+ {
+ updateTime = CDOBranchPoint.UNSPECIFIED_DATE;
+ }
+ }
+
+ if (updateTime != CDOBranchPoint.UNSPECIFIED_DATE)
+ {
+ long contextTime = securityContext.getTimeStamp();
+ if (contextTime == CDOBranchPoint.UNSPECIFIED_DATE || contextTime < updateTime)
+ {
+ if (!realmView.waitForUpdate(updateTime, 10000L))
+ {
+ throw new TimeoutRuntimeException();
+ }
+ }
+ }
+ }
+ }
+
+ private void register(InternalRepository repository)
+ {
+ if (SECURITY_MANAGERS.putIfAbsent(repository, this) != null)
+ {
+ throw new IllegalStateException("A security manager is already associated with repository " + repository);
+ }
+ }
+
+ private void unregister(InternalRepository repository)
+ {
+ SECURITY_MANAGERS.remove(repository);
+ }
+
public static InternalSecurityManager get(IRepository repository)
{
return SECURITY_MANAGERS.get(repository);
@@ -921,17 +1137,18 @@
/**
* @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 +1156,42 @@
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,27 +1199,34 @@
*/
private final class Authenticator implements IAuthenticator2
{
+ public Authenticator()
+ {
+ }
+
@Override
public void authenticate(String userID, char[] password) throws SecurityException
{
User user = getUser(userID);
- UserPassword userPassword = user.getPassword();
-
- if (userPassword != null)
+ if (!user.isLocked())
{
- String encrypted = userPassword.getEncrypted();
- if (!Arrays.equals(password, encrypted == null ? null : encrypted.toCharArray()))
+ UserPassword userPassword = user.getPassword();
+
+ String encrypted = userPassword == null ? null : userPassword.getEncrypted();
+ if (Arrays.equals(password, SecurityUtil.toCharArray(encrypted)))
{
- throw new SecurityException("Access denied"); //$NON-NLS-1$
+ // Access granted.
+ return;
}
}
+
+ throw new SecurityException("Access denied"); //$NON-NLS-1$
}
@Override
public void updatePassword(String userID, char[] oldPassword, char[] newPassword)
{
authenticate(userID, oldPassword);
- setPassword(userID, new String(newPassword));
+ setPassword(userID, SecurityUtil.toString(newPassword));
}
@Override
@@ -984,7 +1240,7 @@
throw new SecurityException("Password reset requires administrator privilege"); //$NON-NLS-1$
}
- setPassword(userID, new String(newPassword));
+ setPassword(userID, SecurityUtil.toString(newPassword));
}
@Override
@@ -1008,6 +1264,10 @@
*/
private final class PermissionManager implements IPermissionManager
{
+ public PermissionManager()
+ {
+ }
+
@Override
@Deprecated
public CDOPermission getPermission(CDORevision revision, CDOBranchPoint securityContext, String userID)
@@ -1016,7 +1276,7 @@
}
@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 +1346,14 @@
{
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,123 +1362,25 @@
}
UserInfo userInfo = getUserInfo(transaction.getSession());
- User user = userInfo.getUser();
- handleCommit(commitContext, user);
+ handleCommit(commitContext, userInfo.getUser());
+ authorizeCommit(commitContext, userInfo);
- PermissionUtil.setUser(user.getId());
- PermissionUtil.initViewCreation(new ViewCreator()
+ if (commitContext.getSecurityImpact() == CommitNotificationInfo.IMPACT_REALM)
{
- @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();
-
- 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
- {
- 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)
{
- lastRealmModification = commitContext.getBranchPoint().getTimeStamp();
+ CDOBranchPoint commitBranchPoint = commitContext.getBranchPoint();
+
+ rememberRealmCommit(commitBranchPoint);
}
handleCommitted(commitContext);
@@ -1243,11 +1398,15 @@
{
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 +1437,7 @@
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 +1474,108 @@
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);
+ register(delegate);
+ }
+
+ @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()
+ {
+ unregister(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 0534955..9214661 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 IRepository getRepository();
+ /**
+ * @since 4.6
+ */
+ public IRepository[] getSecondaryRepositories();
+
public Realm getRealm();
/**
@@ -56,6 +61,7 @@
*
* @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 5083618..4bee9af 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 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/ServerCDOView.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
index dfcf42f..0da5976 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/ServerCDOView.java
@@ -615,16 +615,19 @@
}
};
+ private final InternalSession internalSession;
+
+ private final InternalRepository repository;
+
+ private final long openingTime;
+
private boolean generatedPackageEmulationEnabled;
- private InternalSession internalSession;
-
- private InternalRepository repository;
-
public ServerCDOSession(InternalSession internalSession)
{
this.internalSession = internalSession;
repository = internalSession.getManager().getRepository();
+ openingTime = repository.getTimeStamp();
}
@Override
@@ -726,16 +729,28 @@
* be done client-side by interaction with the user.
*
* @since 4.3
+ * @deprecated
*/
@Override
+ @Deprecated
public void changeCredentials()
{
throw new UnsupportedOperationException();
}
/**
+ * Server sessions may not be used to change the user's credentials: it must
+ * be done client-side by interaction with the user.
+ */
+ @Override
+ public char[] changeServerPassword()
+ {
+ return null;
+ }
+
+ /**
* Server sessions may not be used to reset a user's credentials: it must
- * be done client-side by interaction with an adminstrator.
+ * be done client-side by interaction with an administrator.
*
* @since 4.3
*/
@@ -1027,6 +1042,12 @@
}
@Override
+ public long getOpeningTime()
+ {
+ return openingTime;
+ }
+
+ @Override
public long getLastUpdateTime()
{
return getBranchPoint().getTimeStamp();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
index 3a56802..965e425 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
@@ -53,6 +53,7 @@
import org.eclipse.emf.cdo.spi.server.InternalView;
import org.eclipse.net4j.util.AdapterUtil;
+import org.eclipse.net4j.util.CheckUtil;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.collection.IndexedList;
import org.eclipse.net4j.util.container.Container;
@@ -98,6 +99,8 @@
private boolean openOnClientSide;
+ private long openingTime;
+
private long firstUpdateTime;
private long lastUpdateTime;
@@ -284,6 +287,19 @@
}
@Override
+ public long getOpeningTime()
+ {
+ return openingTime;
+ }
+
+ @Override
+ public void setOpeningTime(long openingTime)
+ {
+ CheckUtil.checkState(this.openingTime == 0, "Opening time is already set");
+ this.openingTime = openingTime;
+ }
+
+ @Override
@Deprecated
public long getLastUpdateTime()
{
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
index 8c47f1a..495638a 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java
@@ -26,6 +26,7 @@
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
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.session.remote.CDORemoteSessionMessage;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
@@ -50,10 +51,12 @@
import org.eclipse.net4j.util.security.IAuthenticator;
import org.eclipse.net4j.util.security.IAuthenticator2;
import org.eclipse.net4j.util.security.IUserManager;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.net4j.util.security.UserManagerAuthenticator;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -93,6 +96,8 @@
}
};
+ private InternalSession[] sessionsArray = {};
+
/**
* @since 2.0
*/
@@ -190,10 +195,33 @@
@Override
public InternalSession[] getSessions()
{
- synchronized (sessions)
- {
- return sessions.values().toArray(new InternalSession[sessions.size()]);
- }
+ return sessionsArray;
+ }
+
+ /**
+ * This method is (and must be) called while holding the "sessions" monitor lock.
+ */
+ private void buildSessionsArray()
+ {
+ sessionsArray = sessions.values().toArray(new InternalSession[sessions.size()]);
+
+ Arrays.sort(sessionsArray, (s1, s2) -> {
+ // Iterating system sessions first is very important for the SecurityManager.
+ // In particular realmView.waitForUpdate(lastRealmModification) may deadlock without this order.
+ int sys1 = IRepository.SYSTEM_USER_ID.equals(s1.getUserID()) ? 0 : 1;
+ int sys2 = IRepository.SYSTEM_USER_ID.equals(s2.getUserID()) ? 0 : 1;
+
+ int result = Integer.compare(sys1, sys2);
+ if (result == 0)
+ {
+ long t1 = s1.getOpeningTime();
+ long t2 = s2.getOpeningTime();
+
+ result = Long.compare(t1, t2);
+ }
+
+ return result;
+ });
}
/**
@@ -230,14 +258,14 @@
@Override
public InternalSession openSession(ISessionProtocol sessionProtocol)
{
- final int id = lastSessionID.incrementAndGet();
+ int id = lastSessionID.incrementAndGet();
if (TRACER.isEnabled())
{
TRACER.trace("Opening session " + id); //$NON-NLS-1$
}
String userID = authenticateUser(sessionProtocol);
- final InternalSession session = createSession(id, userID, sessionProtocol);
+ InternalSession session = createSession(id, userID, sessionProtocol);
LifecycleUtil.activate(session);
synchronized (sessions)
@@ -247,10 +275,14 @@
@Override
public void run()
{
+ long openingTime = repository.getTimeStamp();
+ session.setOpeningTime(openingTime);
+
long firstUpdateTime = repository.getLastCommitTimeStamp();
session.setFirstUpdateTime(firstUpdateTime);
sessions.put(id, session);
+ buildSessionsArray();
}
});
}
@@ -273,6 +305,7 @@
synchronized (sessions)
{
removeSession = sessions.remove(sessionID);
+ buildSessionsArray();
}
if (removeSession != null)
@@ -390,7 +423,9 @@
public void sendCommitNotification(CommitNotificationInfo info)
{
CDOCommonSession sender = info.getSender();
- for (InternalSession session : getSessions())
+ InternalSession[] sessions = getSessions();
+
+ for (InternalSession session : sessions)
{
if (session != sender || info.isModifiedByServer())
{
@@ -571,7 +606,7 @@
ExtendedDataInputStream stream = new ExtendedDataInputStream(bais);
String userID = stream.readString();
- char[] password = stream.readString().toCharArray();
+ char[] password = SecurityUtil.toCharArray(stream.readString());
authenticator.authenticate(userID, password);
return userID;
@@ -637,12 +672,13 @@
if (operation == CredentialsUpdateOperation.RESET_PASSWORD)
{
String adminID = stream.readString();
- char[] adminPassword = stream.readString().toCharArray();
+ char[] adminPassword = SecurityUtil.toCharArray(stream.readString());
if (!ObjectUtil.equals(userID, stream.readString()))
{
throw new SecurityException("Attempt to reset password of a different user than requested"); //$NON-NLS-1$
}
- char[] newPassword = stream.readString().toCharArray();
+
+ char[] newPassword = SecurityUtil.toCharArray(stream.readString());
// this will throw if the current credentials are not authenticated as an administrator
((IAuthenticator2)authenticator).resetPassword(adminID, adminPassword, userID, newPassword);
@@ -650,8 +686,8 @@
else
{
userID = stream.readString(); // user can change any password that she can authenticate on the old password
- char[] password = stream.readString().toCharArray();
- char[] newPassword = stream.readString().toCharArray();
+ char[] password = SecurityUtil.toCharArray(stream.readString());
+ char[] newPassword = SecurityUtil.toCharArray(stream.readString());
// this will throw if the "old password" provided by the user is not correct
((IAuthenticator2)authenticator).updatePassword(userID, password, newPassword);
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 9098dd3..319fe9d 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 @@
{
InternalCDOPackageUnit packageUnit = newPackageUnits[i];
packageUnit.setState(CDOPackageUnit.State.LOADED);
- packageUnit.setPackageRegistry(repositoryPackageRegistry);
+
repositoryPackageRegistry.putPackageUnit(packageUnit);
monitor.worked();
}
@@ -1921,6 +1921,7 @@
{
LifecycleUtil.checkActive(this);
packageUnit.setPackageRegistry(this);
+
for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos())
{
EPackage ePackage = packageInfo.getEPackage();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
index 30dc783..dd1d603 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/bundle/CDOServerApplication.java
@@ -14,6 +14,7 @@
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.spi.server.IAppExtension;
import org.eclipse.emf.cdo.spi.server.IAppExtension3;
+import org.eclipse.emf.cdo.spi.server.IAppExtension4;
import org.eclipse.emf.cdo.spi.server.RepositoryConfigurator;
import org.eclipse.net4j.util.container.IManagedContainer;
@@ -102,6 +103,9 @@
protected void doStop() throws Exception
{
OM.LOG.info(Messages.getString("CDOServerApplication.7")); //$NON-NLS-1$
+
+ extensions.sort(IAppExtension4.COMPARATOR.reversed());
+
for (IAppExtension extension : extensions)
{
try
@@ -141,24 +145,14 @@
{
IExtensionRegistry registry = Platform.getExtensionRegistry();
IConfigurationElement[] elements = registry.getConfigurationElementsFor(OM.BUNDLE_ID, IAppExtension.EXT_POINT);
- for (final IConfigurationElement element : elements)
+
+ for (IConfigurationElement element : elements)
{
if ("appExtension".equals(element.getName())) //$NON-NLS-1$
{
try
{
IAppExtension extension = (IAppExtension)element.createExecutableExtension("class"); //$NON-NLS-1$
-
- if (extension instanceof IAppExtension3)
- {
- IAppExtension3 extension3 = (IAppExtension3)extension;
- extension3.start(repositories, configFile);
- }
- else
- {
- extension.start(configFile);
- }
-
extensions.add(extension);
}
catch (Exception ex)
@@ -167,6 +161,28 @@
}
}
}
+
+ extensions.sort(IAppExtension4.COMPARATOR);
+
+ for (IAppExtension extension : extensions)
+ {
+ try
+ {
+ if (extension instanceof IAppExtension3)
+ {
+ IAppExtension3 extension3 = (IAppExtension3)extension;
+ extension3.start(repositories, configFile);
+ }
+ else
+ {
+ extension.start(configFile);
+ }
+ }
+ catch (Exception ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
}
public static IManagedContainer getContainer()
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/IAppExtension4.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/IAppExtension4.java
new file mode 100644
index 0000000..cac968a
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/IAppExtension4.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020 Eike Stepper (Loehne, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.spi.server;
+
+import java.util.Comparator;
+
+/**
+ * An optional extension of the {@link IAppExtension} interface for {@link #getPriority() prioritized} app extensions.
+ *
+ * @author Eike Stepper
+ * @since 4.12
+ */
+public interface IAppExtension4 extends IAppExtension
+{
+ public static final int PRIORITY_NETWORK = 10;
+
+ public static final int PRIORITY_SECURITY = 100;
+
+ public static final int PRIORITY_DEFAULT = 1000;
+
+ public static final Comparator<IAppExtension> COMPARATOR = (e1, e2) -> {
+ int p1 = getPriority(e1);
+ int p2 = getPriority(e2);
+ return Integer.compare(p1, p2);
+ };
+
+ public int getPriority();
+
+ public static int getPriority(IAppExtension appExtension)
+ {
+ if (appExtension instanceof IAppExtension4)
+ {
+ return ((IAppExtension4)appExtension).getPriority();
+ }
+
+ return PRIORITY_DEFAULT;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
index 9f7a3f8..fa73248 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java
@@ -52,6 +52,11 @@
public void setUserID(String userID);
/**
+ * @since 4.12
+ */
+ public void setOpeningTime(long openingTime);
+
+ /**
* @since 4.5
*/
public long getFirstUpdateTime();
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
index b09ad36..43a7017 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/SessionTest.java
@@ -67,7 +67,6 @@
{
super.setUp();
enableConsole();
-
}
public void testIsSupportingAudits() throws Exception
diff --git a/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch b/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch
index ef17470..eacf457 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.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java
index a774396..d8309f0 100644
--- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java
+++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/CDOContentProvider.java
@@ -16,6 +16,7 @@
import org.eclipse.emf.cdo.common.revision.CDOList;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionManager;
+import org.eclipse.emf.cdo.common.security.NoPermissionException;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.internal.ui.bundle.OM;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
@@ -220,7 +221,7 @@
return contentProvider.hasChildren(object);
}
}
- catch (LifecycleException ex)
+ catch (LifecycleException | NoPermissionException ex)
{
//$FALL-THROUGH$
}
@@ -366,17 +367,20 @@
}
catch (Exception ex)
{
- childrenCache.remove(originalObject);
+ childrenCache.put(originalObject, new Object[] { new ViewerUtil.Error(originalObject, ex.getMessage()) });
if (finalOpeningContext != null)
{
closeContext(finalOpeningContext);
}
- if (view == null)
+ if (view == null && finalObject instanceof EObject)
{
CDOObject cdoObject = getCDOObject((EObject)finalObject);
- view = cdoObject.cdoView();
+ if (cdoObject != null)
+ {
+ view = cdoObject.cdoView();
+ }
}
if (view == null || !view.isClosed())
@@ -471,7 +475,7 @@
return new Object[] { new ViewerUtil.Pending(originalObject, text) };
}
- catch (LifecycleException ex)
+ catch (LifecycleException | NoPermissionException ex)
{
//$FALL-THROUGH$
}
@@ -521,7 +525,7 @@
}
}
}
- catch (LifecycleException ex)
+ catch (LifecycleException | NoPermissionException ex)
{
//$FALL-THROUGH$
}
diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java
index cdc9956..816bbaa 100644
--- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java
+++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/ViewerUtil.java
@@ -202,4 +202,36 @@
return text;
}
}
+
+ /**
+ * @author Eike Stepper
+ */
+ public static final class Error
+ {
+ private final Object parent;
+
+ private final String text;
+
+ public Error(Object parent, String text)
+ {
+ this.parent = parent;
+ this.text = text;
+ }
+
+ public Object getParent()
+ {
+ return parent;
+ }
+
+ public String getText()
+ {
+ return text;
+ }
+
+ @Override
+ public String toString()
+ {
+ return text;
+ }
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/ChangePasswordAction.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/ChangePasswordAction.java
index 268376a..b5b6789 100644
--- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/ChangePasswordAction.java
+++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/ChangePasswordAction.java
@@ -35,6 +35,6 @@
@Override
protected void doRun(IProgressMonitor progressMonitor) throws Exception
{
- getSession().changeCredentials();
+ getSession().changeServerPassword();
}
}
diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java
index 33761fe..608b134 100644
--- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java
+++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java
@@ -3010,6 +3010,7 @@
return;
}
+ CDOView view = CDOEditor.this.view;
if (view != null)
{
setView(view);
diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelProvider.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelProvider.java
index 5b32cf1..0c0cf96 100644
--- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelProvider.java
+++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/ui/CDOLabelProvider.java
@@ -49,11 +49,11 @@
*/
public class CDOLabelProvider extends AdapterFactoryLabelProvider implements IColorProvider, IFontProvider
{
- private static final Color GRAY = UIUtil.getDisplay().getSystemColor(SWT.COLOR_GRAY);
+ private static final Color COLOR_PERMISSION_NONE = UIUtil.getDisplay().getSystemColor(SWT.COLOR_GRAY);
- private static final Color YELLOW = UIUtil.getDisplay().getSystemColor(SWT.COLOR_DARK_YELLOW);
+ private static final Color COLOR_PERMISSION_READ = UIUtil.getDisplay().getSystemColor(SWT.COLOR_DARK_CYAN);
- private static final Color RED = UIUtil.getDisplay().getSystemColor(SWT.COLOR_RED);
+ private static final Color COLOR_CONFLICT = UIUtil.getDisplay().getSystemColor(SWT.COLOR_RED);
private static final Image ERROR_IMAGE = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
@@ -217,17 +217,17 @@
{
if (object.cdoConflict())
{
- return RED;
+ return COLOR_CONFLICT;
}
CDOPermission permission = object.cdoPermission();
switch (permission)
{
case NONE:
- return GRAY;
+ return COLOR_PERMISSION_NONE;
case READ:
- return YELLOW;
+ return COLOR_PERMISSION_READ;
default:
//$FALL-THROUGH$
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSession.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSession.java
index 5b5c530..a388f64 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSession.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/session/CDOSession.java
@@ -190,11 +190,25 @@
* @throws UnsupportedOperationException if the session implementation does not permit changing credentials
*
* @since 4.3
+ * @deprecated As of 4.13 use {@link #changeServerPassword()}.
+ *
* @see #getCredentialsProvider()
*/
+ @Deprecated
public void changeCredentials();
/**
+ * Initiates (possibly interactive) changing of credentials for the user logged in in this session.
+ * This is an optional operation of the session.
+ *
+ * @throws UnsupportedOperationException if the session implementation does not permit changing credentials
+ *
+ * @since 4.13
+ * @see #getCredentialsProvider()
+ */
+ public char[] changeServerPassword();
+
+ /**
* @since 4.13
*/
public CDOClob newClob(Reader contents) throws IOException;
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/ObjectProperties.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/ObjectProperties.java
index a63efad..deebef1 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/ObjectProperties.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/ObjectProperties.java
@@ -19,6 +19,7 @@
import org.eclipse.emf.cdo.common.lock.CDOLockState;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.security.CDOPermission;
+import org.eclipse.emf.cdo.common.security.NoPermissionException;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
import org.eclipse.emf.cdo.transaction.CDOTransaction;
import org.eclipse.emf.cdo.util.CDOUtil;
@@ -285,7 +286,14 @@
@Override
protected Object eval(EObject object)
{
- return !object.eContents().isEmpty();
+ try
+ {
+ return !object.eContents().isEmpty();
+ }
+ catch (NoPermissionException ex)
+ {
+ return false;
+ }
}
});
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
index 0c7eae4..d4011ff 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/CDOSessionImpl.java
@@ -196,6 +196,8 @@
private String userID;
+ private long openingTime;
+
private long lastUpdateTime;
@ExcludeFromDump
@@ -861,6 +863,17 @@
}
@Override
+ public long getOpeningTime()
+ {
+ return openingTime;
+ }
+
+ public void setOpeningTime(long openingTime)
+ {
+ this.openingTime = openingTime;
+ }
+
+ @Override
public long getLastUpdateTime()
{
synchronized (lastUpdateTimeLock)
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
index 4bf5391..73747ae 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/session/DelegatingSessionProtocol.java
@@ -75,6 +75,7 @@
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
/**
@@ -1126,14 +1127,21 @@
}
@Override
+ @Deprecated
public void requestChangeCredentials()
{
+ requestChangeServerPassword(null);
+ }
+
+ @Override
+ public void requestChangeServerPassword(AtomicReference<char[]> receiver)
+ {
int attempt = 0;
for (;;)
{
try
{
- delegate.requestChangeCredentials();
+ delegate.requestChangeServerPassword(receiver);
return;
}
catch (Exception ex)
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
index 7c79346..2158912 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/spi/cdo/CDOSessionProtocol.java
@@ -76,6 +76,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
/**
* If the meaning of this type isn't clear, there really should be more of a description here...
@@ -330,13 +331,26 @@
* This is an optional session protocol operation.
*
* @since 4.3
+ * @deprecated As of 4.13 use {@link #requestChangeServerPassword(AtomicReference)}.
*
* @throws UnsupportedOperationException if the session protocol implementation does
* not support requesting change of credentials
*/
+ @Deprecated
public void requestChangeCredentials();
/**
+ * Requests that the server initiate the change-credentials protocol.
+ * This is an optional session protocol operation.
+ *
+ * @since 4.13
+ *
+ * @throws UnsupportedOperationException if the session protocol implementation does
+ * not support requesting change of credentials
+ */
+ public void requestChangeServerPassword(AtomicReference<char[]> receiver);
+
+ /**
* Requests that the server initiate the reset-credentials protocol.
* This is an optional session protocol operation.
*
@@ -383,6 +397,8 @@
private long lastUpdateTime;
+ private long openingTime;
+
private int tagModCount;
private RepositoryTimeResult repositoryTimeResult;
@@ -430,6 +446,7 @@
repositoryCreationTime = in.readXLong();
lastUpdateTime = in.readXLong();
+ openingTime = in.readXLong();
tagModCount = in.readXInt();
rootResourceID = in.readCDOID();
authenticating = in.readBoolean();
@@ -638,6 +655,14 @@
}
/**
+ * @since 4.13
+ */
+ public long getOpeningTime()
+ {
+ return openingTime;
+ }
+
+ /**
* @since 3.0
*/
public long getLastUpdateTime()
diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/internal/ui/messages/messages.properties b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/internal/ui/messages/messages.properties
index 2d0f663..d48eba1 100644
--- a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/internal/ui/messages/messages.properties
+++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/internal/ui/messages/messages.properties
@@ -25,7 +25,7 @@
CredentialsDialog_0=Login
CredentialsResetDialog_0=Reset Password
CredentialsResetDialog_1=Provide your administrator login to reset the password for user "{0}".
-CredentialsUpdateDialog_0=Change Password
+CredentialsUpdateDialog_0=Change Server Password
CredentialsUpdateDialog_1=Authenticate and enter your new password.
CredentialsUpdateDialog_2=New Password:
CredentialsUpdateDialog_3=Repeat Password:
diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsDialog.java b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsDialog.java
index 088b56d..f087a33 100644
--- a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsDialog.java
+++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsDialog.java
@@ -15,9 +15,11 @@
import org.eclipse.net4j.util.internal.ui.messages.Messages;
import org.eclipse.net4j.util.security.IPasswordCredentials;
import org.eclipse.net4j.util.security.PasswordCredentials;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.net4j.util.ui.UIUtil;
import org.eclipse.net4j.util.ui.widgets.BaseDialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
@@ -50,7 +52,7 @@
private final String realm;
- private final List<String> users;
+ private List<String> users;
private Control userIDControl;
@@ -79,7 +81,6 @@
super(shell, DEFAULT_SHELL_STYLE | SWT.APPLICATION_MODAL, title, message, OM.Activator.INSTANCE.getDialogSettings(),
OM.getImageDescriptor("icons/credentials_wiz.gif")); //$NON-NLS-1$
this.realm = realm;
- users = loadUsers();
}
/**
@@ -124,8 +125,17 @@
}
@Override
+ protected Control createButtonBar(Composite parent)
+ {
+ Control buttonBar = super.createButtonBar(parent);
+ updateOkButton();
+ return buttonBar;
+ }
+
+ @Override
protected void createUI(Composite parent)
{
+ users = loadUsers();
createCredentialsArea(parent);
}
@@ -161,12 +171,16 @@
{
if (users.isEmpty())
{
- return new Text(composite, SWT.BORDER);
+ Text text = new Text(composite, SWT.BORDER);
+ text.addModifyListener(e -> updateOkButton());
+
+ return text;
}
Combo combo = new Combo(composite, SWT.BORDER);
combo.setItems(users.toArray(new String[users.size()]));
- combo.setText(users.get(0));
+ combo.setText(getInitialUserID());
+ combo.addModifyListener(e -> updateOkButton());
return combo;
}
@@ -174,18 +188,10 @@
@Override
protected void okPressed()
{
- String userID;
- if (userIDControl instanceof Combo)
- {
- userID = ((Combo)userIDControl).getText();
- }
- else
- {
- userID = ((Text)userIDControl).getText();
- }
+ String userID = getUserID();
String password = passwordControl.getText();
- credentials = createCredentials(userID, password.toCharArray());
+ credentials = createCredentials(userID, SecurityUtil.toCharArray(password));
users.remove(userID);
users.add(0, userID);
@@ -232,6 +238,24 @@
settings.put(key, users.toArray(new String[users.size()]));
}
+ /**
+ * @since 3.10
+ */
+ protected String getInitialUserID()
+ {
+ return users.get(0);
+ }
+
+ private String getUserID()
+ {
+ if (userIDControl instanceof Combo)
+ {
+ return ((Combo)userIDControl).getText();
+ }
+
+ return ((Text)userIDControl).getText();
+ }
+
private String getRealmKey()
{
String key = "realm";
@@ -247,4 +271,9 @@
{
return getDialogSettings("users");
}
+
+ private void updateOkButton()
+ {
+ getButton(IDialogConstants.OK_ID).setEnabled(getUserID().length() != 0);
+ }
}
diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsUpdateDialog.java b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsUpdateDialog.java
index fa3f2bc..30988f6 100644
--- a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsUpdateDialog.java
+++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/CredentialsUpdateDialog.java
@@ -15,6 +15,7 @@
import org.eclipse.net4j.util.security.IPasswordCredentials;
import org.eclipse.net4j.util.security.IPasswordCredentialsUpdate;
import org.eclipse.net4j.util.security.PasswordCredentialsUpdate;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.net4j.util.ui.UIUtil;
import org.eclipse.jface.dialogs.IDialogConstants;
@@ -72,7 +73,7 @@
protected IPasswordCredentials createCredentials(String userID, char[] password)
{
String newPassword = newPasswordControl.getText();
- return new PasswordCredentialsUpdate(userID, password, newPassword.toCharArray());
+ return new PasswordCredentialsUpdate(userID, password, SecurityUtil.toCharArray(newPassword));
}
@Override
diff --git a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/InteractiveCredentialsProvider.java b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/InteractiveCredentialsProvider.java
index a7d9a74..09f1a75 100644
--- a/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/InteractiveCredentialsProvider.java
+++ b/plugins/org.eclipse.net4j.util.ui/src/org/eclipse/net4j/util/ui/security/InteractiveCredentialsProvider.java
@@ -17,6 +17,7 @@
import org.eclipse.net4j.util.security.IPasswordCredentialsProvider2;
import org.eclipse.net4j.util.security.IPasswordCredentialsUpdate;
import org.eclipse.net4j.util.security.IPasswordCredentialsUpdateProvider;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.net4j.util.ui.UIUtil;
import org.eclipse.jface.dialogs.IDialogConstants;
@@ -25,7 +26,6 @@
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import java.text.MessageFormat;
@@ -56,20 +56,15 @@
* @since 3.3
*/
@Override
- public IPasswordCredentials getCredentials(final String realm)
+ public IPasswordCredentials getCredentials(String realm)
{
- final IPasswordCredentials[] credentials = new IPasswordCredentials[1];
- final Display display = UIUtil.getDisplay();
- display.syncExec(new Runnable()
- {
- @Override
- public void run()
+ IPasswordCredentials[] credentials = new IPasswordCredentials[1];
+
+ UIUtil.syncExec(() -> {
+ CredentialsDialog dialog = new CredentialsDialog(UIUtil.getShell(), realm);
+ if (dialog.open() == CredentialsDialog.OK)
{
- CredentialsDialog dialog = new CredentialsDialog(UIUtil.getShell(), realm);
- if (dialog.open() == CredentialsDialog.OK)
- {
- credentials[0] = dialog.getCredentials();
- }
+ credentials[0] = dialog.getCredentials();
}
});
@@ -89,73 +84,68 @@
* @since 3.4
*/
@Override
- public IPasswordCredentialsUpdate getCredentialsUpdate(final String realm, final String userID, final CredentialsUpdateOperation operation)
+ public IPasswordCredentialsUpdate getCredentialsUpdate(String realm, String userID, CredentialsUpdateOperation operation)
{
- final IPasswordCredentialsUpdate[] update = { null };
- final Display display = UIUtil.getDisplay();
- display.syncExec(new Runnable()
- {
- @Override
- public void run()
+ IPasswordCredentialsUpdate[] update = { null };
+
+ UIUtil.syncExec(() -> {
+ Shell shell = UIUtil.getShell();
+
+ if (operation == CredentialsUpdateOperation.CHANGE_PASSWORD)
{
- Shell shell = UIUtil.getShell();
-
- if (operation == CredentialsUpdateOperation.CHANGE_PASSWORD)
+ CredentialsUpdateDialog dialog = new CredentialsUpdateDialog(shell, realm, userID);
+ if (dialog.open() == Window.OK)
{
- CredentialsUpdateDialog dialog = new CredentialsUpdateDialog(shell, realm, userID);
- if (dialog.open() == Window.OK)
- {
- update[0] = dialog.getCredentials();
- }
+ update[0] = dialog.getCredentials();
}
- else
+ }
+ else
+ {
+ CredentialsResetDialog dialog = new CredentialsResetDialog(shell, realm, userID);
+ if (dialog.open() == Window.OK)
{
- CredentialsResetDialog dialog = new CredentialsResetDialog(shell, realm, userID);
- if (dialog.open() == Window.OK)
+ update[0] = dialog.getCredentials();
+ String newPassword = SecurityUtil.toString(update[0].getNewPassword());
+
+ MessageDialog msg = new MessageDialog(shell, Messages.getString("InteractiveCredentialsProvider.0"), null, //$NON-NLS-1$
+ MessageFormat.format(Messages.getString("InteractiveCredentialsProvider.1"), //$NON-NLS-1$
+ userID, newPassword),
+ MessageDialog.INFORMATION, new String[] { Messages.getString("InteractiveCredentialsProvider.2"), //$NON-NLS-1$
+ IDialogConstants.OK_LABEL },
+ 0)
{
- update[0] = dialog.getCredentials();
- final String newPassword = new String(update[0].getNewPassword());
- MessageDialog msg = new MessageDialog(shell, Messages.getString("InteractiveCredentialsProvider.0"), null, //$NON-NLS-1$
- MessageFormat.format(Messages.getString("InteractiveCredentialsProvider.1"), //$NON-NLS-1$
- userID, newPassword),
- MessageDialog.INFORMATION, new String[] { Messages.getString("InteractiveCredentialsProvider.2"), //$NON-NLS-1$
- IDialogConstants.OK_LABEL },
- 0)
+ @Override
+ protected void buttonPressed(int buttonId)
{
-
- @Override
- protected void buttonPressed(int buttonId)
+ if (buttonId == 0)
{
- if (buttonId == 0)
- {
- copyToClipboard();
- // Don't close the dialog
- }
- else
- {
- // Close the dialog in the usual way
- super.buttonPressed(IDialogConstants.OK_ID);
- }
+ copyToClipboard();
+ // Don't close the dialog
}
-
- private void copyToClipboard()
+ else
{
- Clipboard clipboard = new Clipboard(getShell().getDisplay());
-
- try
- {
- clipboard.setContents(new Object[] { newPassword }, new Transfer[] { TextTransfer.getInstance() });
- }
- finally
- {
- clipboard.dispose();
- }
+ // Close the dialog in the usual way
+ super.buttonPressed(IDialogConstants.OK_ID);
}
- };
+ }
- msg.open();
- }
+ private void copyToClipboard()
+ {
+ Clipboard clipboard = new Clipboard(getShell().getDisplay());
+
+ try
+ {
+ clipboard.setContents(new Object[] { newPassword }, new Transfer[] { TextTransfer.getInstance() });
+ }
+ finally
+ {
+ clipboard.dispose();
+ }
+ }
+ };
+
+ msg.open();
}
}
});
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
index 2858f0d..0c89342 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
@@ -40,6 +40,7 @@
* Various static helper methods for dealing with Java reflection.
*
* @author Eike Stepper
+ * @since 3.14
*/
public final class ReflectUtil
{
@@ -115,7 +116,7 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
@@ -127,10 +128,24 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
+ /**
+ * @since 3.14
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T invokeMethod(String methodName, Object target)
+ {
+ if (target instanceof Class)
+ {
+ return (T)invokeMethod(getMethod((Class<?>)target, methodName), null);
+ }
+
+ return (T)invokeMethod(getMethod(target.getClass(), methodName), target);
+ }
+
public static Field getField(Class<?> c, String fieldName)
{
try
@@ -164,7 +179,7 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
@@ -214,7 +229,7 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
@@ -226,10 +241,36 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
+ /**
+ * @since 3.14
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T getValue(String fieldName, Object target)
+ {
+ if (target instanceof Class)
+ {
+ Field field = getField((Class<?>)target, fieldName);
+ if (field == null)
+ {
+ throw new ReflectionException("No such field: " + fieldName);
+ }
+
+ return (T)getValue(field, null);
+ }
+
+ Field field = getField(target.getClass(), fieldName);
+ if (field == null)
+ {
+ throw new ReflectionException("No such field: " + fieldName);
+ }
+
+ return (T)getValue(field, target);
+ }
+
public static void setValue(Field field, Object target, Object value)
{
setValue(field, target, value, false);
@@ -251,7 +292,7 @@
}
catch (Exception ex)
{
- throw WrappedException.wrap(ex);
+ throw ReflectionException.wrap(ex);
}
}
@@ -755,10 +796,61 @@
return type;
}
+ /**
+ * @since 3.14
+ */
public static PrimitiveType forClass(Class<?> clazz)
{
PrimitiveType result = INSTANCES.get(clazz);
return result == null ? NONE : result;
}
}
+
+ /**
+ * @author Eike Stepper
+ * @since 3.14
+ */
+ public static class ReflectionException extends RuntimeException
+ {
+ private static final long serialVersionUID = 1L;
+
+ public ReflectionException()
+ {
+ }
+
+ public ReflectionException(String message, Exception cause)
+ {
+ super(message, cause);
+ }
+
+ public ReflectionException(String message)
+ {
+ super(message);
+ }
+
+ public ReflectionException(Exception cause)
+ {
+ super(cause);
+ }
+
+ public static ReflectionException wrap(Exception exception)
+ {
+ if (exception instanceof ReflectionException)
+ {
+ return (ReflectionException)exception;
+ }
+
+ return new ReflectionException(exception);
+ }
+
+ public static Exception unwrap(Exception exception)
+ {
+ if (exception instanceof ReflectionException)
+ {
+ return (Exception)((ReflectionException)exception).getCause();
+ }
+
+ return exception;
+ }
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/IManagedContainer.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/IManagedContainer.java
index 415e6cc..b16ca24 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/IManagedContainer.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/IManagedContainer.java
@@ -82,6 +82,11 @@
public Object getElement(String productGroup, String factoryType, String description, boolean activate)
throws FactoryNotFoundException, ProductCreationException;
+ /**
+ * @since 3.14
+ */
+ public <T> T getElementOrNull(String productGroup, String factoryType, String description);
+
public Object removeElement(String productGroup, String factoryType, String description);
/**
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/ManagedContainer.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/ManagedContainer.java
index 483334c..caba6da 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/ManagedContainer.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/container/ManagedContainer.java
@@ -365,6 +365,20 @@
return element;
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> T getElementOrNull(String productGroup, String factoryType, String description)
+ {
+ try
+ {
+ return (T)getElement(productGroup, factoryType, description);
+ }
+ catch (FactoryNotFoundException | ProductCreationException ex)
+ {
+ return null;
+ }
+ }
+
/**
* @since 3.2
*/
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 451c6a1..473e25d 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 @@
*
* @author Eike Stepper
*/
+@FunctionalInterface
public interface IListener extends EventListener
{
public void notifyEvent(IEvent event);
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileUserManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileUserManager.java
index d00017c..044e493 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileUserManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/FileUserManager.java
@@ -159,7 +159,7 @@
for (Entry<Object, Object> entry : properties.entrySet())
{
String userID = (String)entry.getKey();
- char[] password = ((String)entry.getValue()).toCharArray();
+ char[] password = SecurityUtil.toCharArray((String)entry.getValue());
users.put(userID, password);
}
}
@@ -193,7 +193,7 @@
for (Entry<String, char[]> entry : users.entrySet())
{
- properties.put(entry.getKey(), new String(entry.getValue()));
+ properties.put(entry.getKey(), SecurityUtil.toString(entry.getValue()));
}
String comment = MessageFormat.format("User database {0,date} {0,time,HH:mm:ss:SSS}", System.currentTimeMillis());
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentials.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentials.java
index 1ec4089..0cf5dd1 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentials.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentials.java
@@ -28,7 +28,7 @@
*/
public PasswordCredentials(String userID, String password)
{
- this(userID, password.toCharArray());
+ this(userID, SecurityUtil.toCharArray(password));
}
/**
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsProvider.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsProvider.java
index adda247..1d35069 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsProvider.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsProvider.java
@@ -42,7 +42,7 @@
*/
public PasswordCredentialsProvider(String userID, String password)
{
- this(userID, password == null ? null : password.toCharArray());
+ this(userID, SecurityUtil.toCharArray(password));
}
@Override
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsUpdate.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsUpdate.java
index e01791a..8ac1d0c 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsUpdate.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/PasswordCredentialsUpdate.java
@@ -28,7 +28,7 @@
public PasswordCredentialsUpdate(String userID, String password, String newPassword)
{
- this(userID, password.toCharArray(), newPassword.toCharArray());
+ this(userID, SecurityUtil.toCharArray(password), SecurityUtil.toCharArray(newPassword));
}
public PasswordCredentialsUpdate(String userID)
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/SecurityUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/SecurityUtil.java
index ed8e8b0..3b86804 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/SecurityUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/SecurityUtil.java
@@ -94,4 +94,30 @@
{
return pbeEncrypt(data, password, algorithmName, salt, count);
}
+
+ /**
+ * @since 3.14
+ */
+ public static String toString(char[] chars)
+ {
+ if (chars == null || chars.length == 0)
+ {
+ return null;
+ }
+
+ return new String(chars);
+ }
+
+ /**
+ * @since 3.14
+ */
+ public static char[] toCharArray(String str)
+ {
+ if (str == null || str.length() == 0)
+ {
+ return null;
+ }
+
+ return str.toCharArray();
+ }
}
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
index 05c1241..17b0605 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/security/UserManager.java
@@ -68,12 +68,12 @@
if (userPassword == null)
{
- throw new SecurityException("No such user: " + userID); //$NON-NLS-1$
+ throw new NotAuthenticatedException("No such user: " + userID); //$NON-NLS-1$
}
if (!Arrays.equals(userPassword, password))
{
- throw new SecurityException("Wrong password for user: " + userID); //$NON-NLS-1$
+ throw new NotAuthenticatedException("Wrong password for user: " + userID); //$NON-NLS-1$
}
}
diff --git a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/security/AuthenticationIndication.java b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/security/AuthenticationIndication.java
index 581640e..6454321 100644
--- a/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/security/AuthenticationIndication.java
+++ b/plugins/org.eclipse.net4j/src/org/eclipse/net4j/signal/security/AuthenticationIndication.java
@@ -23,6 +23,7 @@
import org.eclipse.net4j.util.security.DiffieHellman.Server.Challenge;
import org.eclipse.net4j.util.security.IPasswordCredentials;
import org.eclipse.net4j.util.security.IPasswordCredentialsProvider;
+import org.eclipse.net4j.util.security.SecurityUtil;
import org.eclipse.internal.net4j.bundle.OM;
@@ -103,7 +104,7 @@
throw new IllegalStateException("No userID provided"); //$NON-NLS-1$
}
- String password = new String(credentials.getPassword());
+ String password = SecurityUtil.toString(credentials.getPassword());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ExtendedDataOutputStream stream = new ExtendedDataOutputStream(baos);