diff --git a/plugins/org.eclipse.oomph.setup.core/META-INF/MANIFEST.MF b/plugins/org.eclipse.oomph.setup.core/META-INF/MANIFEST.MF index 9b3444359..f7590260f 100644 --- a/plugins/org.eclipse.oomph.setup.core/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.oomph.setup.core/META-INF/MANIFEST.MF @@ -36,7 +36,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.24.0,4.0.0)", org.eclipse.oomph.setup.p2;bundle-version="[1.20.0,2.0.0)", org.eclipse.oomph.preferences;bundle-version="[1.14.0,2.0.0)", org.eclipse.core.net;bundle-version="[1.2.0,2.0.0)" -Import-Package: org.bouncycastle.openpgp;version="[1.65.0,2.0.0)" +Import-Package: org.apache.hc.client5.http.cookie;version="[5.1.3,6.0.0)", + org.apache.hc.client5.http.impl.cookie;version="[5.1.3,6.0.0)", + org.bouncycastle.openpgp;version="[1.65.0,2.0.0)" Bundle-RequiredExecutionEnvironment: JavaSE-11 Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.oomph.setup.internal.core;version="1.29.0";x-internal:=true, diff --git a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/util/ECFURIHandlerImpl.java b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/util/ECFURIHandlerImpl.java index 05eda054a..3b26161b1 100644 --- a/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/util/ECFURIHandlerImpl.java +++ b/plugins/org.eclipse.oomph.setup.core/src/org/eclipse/oomph/setup/internal/core/util/ECFURIHandlerImpl.java @@ -23,6 +23,7 @@ import org.eclipse.oomph.util.OS; import org.eclipse.oomph.util.ObjectUtil; import org.eclipse.oomph.util.PropertiesUtil; +import org.eclipse.oomph.util.ReflectUtil; import org.eclipse.oomph.util.StringUtil; import org.eclipse.oomph.util.WorkerPool; @@ -49,6 +50,7 @@ import org.eclipse.ecf.core.util.ProxyAddress; import org.eclipse.ecf.filetransfer.BrowseFileTransferException; import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IIncomingFileTransfer; import org.eclipse.ecf.filetransfer.IRemoteFile; import org.eclipse.ecf.filetransfer.IRemoteFileInfo; import org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter; @@ -63,6 +65,7 @@ import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent; import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemBrowseEvent; import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemEvent; +import org.eclipse.ecf.filetransfer.identity.IFileID; import org.eclipse.ecf.provider.filetransfer.identity.FileTransferID; import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; import org.eclipse.ecf.provider.filetransfer.util.ProxySetupHelper; @@ -72,6 +75,8 @@ import org.eclipse.equinox.security.storage.StorageException; import org.eclipse.osgi.util.NLS; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.cookie.Cookie; import org.osgi.framework.Version; import java.io.ByteArrayInputStream; @@ -81,14 +86,20 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.net.CookieManager; +import java.net.CookieStore; +import java.net.HttpCookie; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -115,6 +126,8 @@ public class ECFURIHandlerImpl extends URIHandlerImpl implements URIResolver public static final String OPTION_MONITOR = "OPTION_MONITOR"; //$NON-NLS-1$ + public static final CookieStore COOKIE_STORE = FileTransferListener.DELEGATING_COOKIE_STORE; + public static final String OPTION_LOGIN_URI = "OPTION_LOGIN_URI"; //$NON-NLS-1$ public static final String OPTION_FORM_URI = "OPTION_FORM_URI"; //$NON-NLS-1$ @@ -448,6 +461,11 @@ private AuthorizationHandler getAuthorizatonHandler(Map options) return defaultAuthorizationHandler; } + private static String getHost(java.net.URI uri) + { + return uri.getHost(); + } + private static String getHost(URI uri) { String authority = uri.authority(); @@ -807,6 +825,11 @@ public String toString() */ private static final class FileTransferListener implements IFileTransferListener, ConnectionListener { + @SuppressWarnings("all") + private static final BasicCookieStore COOKIE_STORE = new BasicCookieStore(); + + private static final DelegatingCookieStore DELEGATING_COOKIE_STORE = new DelegatingCookieStore(COOKIE_STORE); + public final CountDownLatch receiveLatch = new CountDownLatch(1); public final String expectedETag; @@ -842,6 +865,8 @@ public void handleTransferEvent(IFileTransferEvent event) receiveLatch.countDown(); return; } + + applyCookieStore(connectStartEvent); } else if (event instanceof IIncomingFileTransferReceiveStartEvent) { @@ -941,6 +966,103 @@ private static String getValue(Map responseHeaders, String key) return null; } + private static void applyCookieStore(final IFileTransferConnectStartEvent connectStartEvent) + { + IIncomingFileTransfer fileTransfer = ObjectUtil.adapt(connectStartEvent, IIncomingFileTransfer.class); + final IFileID fileID = connectStartEvent.getFileID(); + try + { + if (fileTransfer != null) + { + Object httpClient = ReflectUtil.getValue("httpClient", fileTransfer); //$NON-NLS-1$ + + if (TRACE) + { + System.out.println(NLS.bind(Messages.ECFURIHandlerImpl_ManageCookies_message, fileID.getURI(), httpClient)); + } + + ReflectUtil.setValue(ReflectUtil.getField(httpClient.getClass(), "cookieStore"), httpClient, new org.apache.hc.client5.http.cookie.CookieStore() //$NON-NLS-1$ + { + @Override + @SuppressWarnings("all") + public List getCookies() + { + return COOKIE_STORE.getCookies(); + } + + @Override + @SuppressWarnings("all") + public boolean clearExpired(Date date) + { + synchronized (COOKIE_STORE) + { + List originalCookies = new ArrayList<>(COOKIE_STORE.getCookies()); + COOKIE_STORE.clearExpired(date); + List remainingCookies = COOKIE_STORE.getCookies(); + originalCookies.removeAll(remainingCookies); + + for (Cookie cookie : originalCookies) + { + HttpCookie httpCookie = createCookie(cookie); + DELEGATING_COOKIE_STORE.basicRemove(null, new HttpCookie(cookie.getName(), cookie.getValue())); + } + + return !originalCookies.isEmpty(); + } + } + + @Override + @SuppressWarnings("all") + public void clear() + { + COOKIE_STORE.clear(); + DELEGATING_COOKIE_STORE.basicRemoveAll(); + } + + @Override + @SuppressWarnings("all") + public void addCookie(Cookie cookie) + { + try + { + java.net.URI uri = fileID.getURI(); + HttpCookie httpCookie = createCookie(cookie); + DELEGATING_COOKIE_STORE.basicAdd(uri, httpCookie); + } + catch (Exception ex) + { + // Ignore bad information. + } + + COOKIE_STORE.addCookie(cookie); + } + + public HttpCookie createCookie(Cookie cookie) + { + HttpCookie httpCookie = new HttpCookie(cookie.getName(), cookie.getValue()); + httpCookie.setDomain(cookie.getDomain()); + httpCookie.setPath(cookie.getPath()); + return httpCookie; + } + }, true); + } + } + catch (Throwable throwable) + { + if (TRACE) + { + try + { + System.out.println(NLS.bind(Messages.ECFURIHandlerImpl_FailedToManage_message, fileID.getURI())); + } + catch (URISyntaxException ex) + { + System.out.println(NLS.bind(Messages.ECFURIHandlerImpl_BadFileID_message, fileID)); + } + } + } + } + @Override public void await() throws InterruptedException { @@ -964,6 +1086,111 @@ public int getErrorCode() { return ((IncomingFileTransferException)exception).getErrorCode(); } + + /** + * @author Ed Merks + */ + private static class DelegatingCookieStore implements CookieStore + { + private final CookieStore delegate = new CookieManager().getCookieStore(); + + private final BasicCookieStore basicCookieStore; + + public DelegatingCookieStore(BasicCookieStore basicCookieStore) + { + this.basicCookieStore = basicCookieStore; + } + + @Override + public void add(java.net.URI uri, HttpCookie httpCookie) + { + basicAdd(uri, httpCookie); + basicCookieStore.addCookie(createCookie(uri, httpCookie)); + } + + public void basicAdd(java.net.URI uri, HttpCookie httpCookie) + { + if (TRACE) + { + System.out.println(NLS.bind(Messages.ECFURIHandlerImpl_AddingCookie_message, uri, httpCookie)); + } + + delegate.add(uri, httpCookie); + } + + @Override + public List get(java.net.URI uri) + { + return delegate.get(uri); + } + + @Override + public List getCookies() + { + return delegate.getCookies(); + } + + @Override + public List getURIs() + { + return delegate.getURIs(); + } + + @Override + public boolean remove(java.net.URI uri, HttpCookie httpCookie) + { + org.apache.hc.client5.http.impl.cookie.BasicClientCookie basicClientCookie = createCookie(uri, httpCookie); + basicClientCookie.setExpiryDate(new Date(System.currentTimeMillis() - 1000)); + basicCookieStore.addCookie(basicClientCookie); + return basicRemove(uri, httpCookie); + } + + public boolean basicRemove(java.net.URI uri, HttpCookie cookie) + { + if (TRACE) + { + System.out.println(NLS.bind(Messages.ECFURIHandlerImpl_AddingCookie_message, uri, cookie)); + } + + return delegate.remove(uri, cookie); + } + + @Override + public boolean removeAll() + { + basicCookieStore.clear(); + return basicRemoveAll(); + } + + public boolean basicRemoveAll() + { + return delegate.removeAll(); + } + + private org.apache.hc.client5.http.impl.cookie.BasicClientCookie createCookie(java.net.URI uri, HttpCookie httpCookie) + { + org.apache.hc.client5.http.impl.cookie.BasicClientCookie basicClientCookie = new org.apache.hc.client5.http.impl.cookie.BasicClientCookie( + httpCookie.getName(), httpCookie.getValue()); + basicClientCookie.setPath(httpCookie.getPath()); + if (uri != null) + { + basicClientCookie.setDomain(uri.getHost()); + } + + if (httpCookie.hasExpired()) + { + basicClientCookie.setExpiryDate(new Date(System.currentTimeMillis() - 1000)); + } + + return basicClientCookie; + } + + @Override + public String toString() + { + return getCookies().toString(); + } + } } /** @@ -2707,6 +2934,21 @@ public boolean process() throws IOException // Return here so that we don't needlessly put the same authorization back the map. return true; } + + java.net.URI javaNetFormURI; + try + { + javaNetFormURI = new java.net.URI(formURI.toString()); + } + catch (URISyntaxException ex) + { + throw new IOExceptionWithCause(ex); + } + + for (HttpCookie httpCookie : COOKIE_STORE.get(javaNetFormURI)) + { + COOKIE_STORE.remove(javaNetFormURI, httpCookie); + } } URI formActionURI = readForm(formURI); @@ -2906,6 +3148,35 @@ private boolean postForm(URI formActionURI) throws IOException connection.setDoOutput(true); connection.setInstanceFollowRedirects(false); + java.net.URI uri; + try + { + uri = url.toURI(); + } + catch (URISyntaxException ex) + { + throw new IOExceptionWithCause(ex); + } + + // Be sure to add cookies, e.g., any cookies returned when the form was read earlier. + List cookies = COOKIE_STORE.get(uri); + for (HttpCookie httpCookie : cookies) + { + connection.addRequestProperty("Cookie", httpCookie.toString().replace("\"", "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + if (TRACE) + { + StringBuilder details = new StringBuilder(); + for (HttpCookie httpCookie : cookies) + { + details.append(StringUtil.NL).append(" ").append(httpCookie); //$NON-NLS-1$ + } + + System.out.println(tracePrefix + + (details.length() == 0 ? Messages.ECFURIHandlerImpl_UsingNoCookies_message : Messages.ECFURIHandlerImpl_UsingCookies_message + details)); + } + handleProxy(connection); String form = getForm(parameterValues, secureParameters, true); @@ -2927,6 +3198,27 @@ private boolean postForm(URI formActionURI) throws IOException { // Look for the cookies... Map> headerFields = connection.getHeaderFields(); + List list = headerFields.get("Set-Cookie"); //$NON-NLS-1$ + if (list != null) + { + for (String value : list) + { + List httpCookies = HttpCookie.parse(value); + for (HttpCookie httpCookie : httpCookies) + { + httpCookie.setDomain(getHost(uri)); + + // Some sites serve up bogus expiry information that results in the cookie not being added to the store. + if (httpCookie.getMaxAge() == 0) + { + httpCookie.setMaxAge(-1); + } + + ECFURIHandlerImpl.COOKIE_STORE.add(uri, httpCookie); + result = true; + } + } + } // Allow subclasses to also inspect the header fields. if (result) diff --git a/plugins/org.eclipse.oomph.setup.editor/src/org/eclipse/oomph/setup/presentation/SetupEditor.java b/plugins/org.eclipse.oomph.setup.editor/src/org/eclipse/oomph/setup/presentation/SetupEditor.java index 7d58bdf76..d265c2cc3 100644 --- a/plugins/org.eclipse.oomph.setup.editor/src/org/eclipse/oomph/setup/presentation/SetupEditor.java +++ b/plugins/org.eclipse.oomph.setup.editor/src/org/eclipse/oomph/setup/presentation/SetupEditor.java @@ -6227,13 +6227,21 @@ private void applyCookies() { for (HttpCookie httpCookie : cookieStore.get(uri)) { - { - Browser.setCookie(httpCookie.getValue(), uri.toString()); - } + Browser.setCookie(httpCookie.getValue(), uri.toString()); } } } } + + List uris = ECFURIHandlerImpl.COOKIE_STORE.getURIs(); + for (java.net.URI cookieURI : uris) + { + String url = cookieURI.toString(); + for (HttpCookie httpCookie : ECFURIHandlerImpl.COOKIE_STORE.get(cookieURI)) + { + Browser.setCookie(httpCookie.getValue(), url); + } + } } private ToolItem createItem(int style, String imageKey, String toolTipText, SelectionListener selectionListener) diff --git a/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog Online).launch b/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog Online).launch index e4716c6fb..607dbe886 100644 --- a/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog Online).launch +++ b/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog Online).launch @@ -3,47 +3,47 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -52,18 +52,18 @@ - - + + - - - - + + + + - - + + @@ -93,7 +93,7 @@ - + diff --git a/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog).launch b/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog).launch index 4e235223c..478046970 100644 --- a/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog).launch +++ b/plugins/org.eclipse.oomph.setup/Setup (Installer Dialog).launch @@ -3,31 +3,31 @@ - - - - - - - + + + + + + + - + - - - - - - - - + + + + + + + + - + @@ -57,7 +57,7 @@ - + diff --git a/plugins/org.eclipse.oomph.ui/IDE.launch b/plugins/org.eclipse.oomph.ui/IDE.launch index e07c0aa2d..28b93dd50 100644 --- a/plugins/org.eclipse.oomph.ui/IDE.launch +++ b/plugins/org.eclipse.oomph.ui/IDE.launch @@ -30,7 +30,7 @@ - + diff --git a/products/org.eclipse.oomph.setup.installer.product/Installer.p2.inf b/products/org.eclipse.oomph.setup.installer.product/Installer.p2.inf index 6c317b430..3d7e954ae 100644 --- a/products/org.eclipse.oomph.setup.installer.product/Installer.p2.inf +++ b/products/org.eclipse.oomph.setup.installer.product/Installer.p2.inf @@ -2,6 +2,7 @@ properties.0.name = org.eclipse.oomph.p2.iu.compatibility properties.0.value = Major instructions.configure=\ + setProgramProperty(propName:org.eclipse.ecf.provider.filetransfer.excludeContributors,propValue:org.eclipse.ecf.provider.filetransfer.httpclientjava);\ setProgramProperty(propName:eclipse.p2.max.threads,propValue:10);\ setProgramProperty(propName:oomph.p2.repository.retry,propValue:2);\ setProgramProperty(propName:org.eclipse.update.reconcile,propValue:false);\ @@ -13,6 +14,7 @@ instructions.configure=\ setProgramProperty(propName:oomph.setup.jre.choice,propValue:true); instructions.unconfigure=\ + setProgramProperty(propName:org.eclipse.ecf.provider.filetransfer.excludeContributors,propValue:);\ setProgramProperty(propName:eclipse.p2.max.threads,propValue:);\ setProgramProperty(propName:oomph.p2.repository.retry,propValue:);\ setProgramProperty(propName:org.eclipse.update.reconcile,propValue:);\