Skip to content

Commit

Permalink
Merge pull request #15932 from iterate-ch/bugfix/CTERA-161-cookie
Browse files Browse the repository at this point in the history
Make sure to store cookies from a successful login only.
  • Loading branch information
dkocher committed May 14, 2024
2 parents 20ebab3 + 38d3d56 commit 83f3e3e
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
public class CteraAuthenticationHandler implements ServiceUnavailableRetryStrategy {
private static final Logger log = LogManager.getLogger(CteraAuthenticationHandler.class);

public static final String AUTH_PATH = "/ServicesPortal/api/login?format=jsonext";

private final CteraSession session;

private CteraTokens tokens = CteraTokens.EMPTY;
Expand All @@ -52,7 +54,7 @@ public void setTokens(final CteraTokens tokens) {
}

public void authenticate() throws BackgroundException {
final HttpPost login = new HttpPost("/ServicesPortal/api/login?format=jsonext");
final HttpPost login = new HttpPost(AUTH_PATH);
try {
login.setEntity(
new StringEntity(String.format("j_username=device%%5c%s&j_password=%s", tokens.getDeviceId(), tokens.getSharedSecret()),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ch.cyberduck.core.ctera;

/*
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.protocol.HttpContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;

public class CteraCookieInterceptor implements HttpResponseInterceptor {

private static final Logger log = LogManager.getLogger(CteraCookieInterceptor.class);

@Override
public void process(final HttpResponse response, final HttpContext context) throws HttpException, IOException {
if(response.containsHeader("Set-Cookie")) {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
if(StringUtils.equals(CteraAuthenticationHandler.AUTH_PATH, clientContext.getRequest().getRequestLine().getUri()) &&
response.getStatusLine().getStatusCode() == HttpStatus.SC_OK &&
HttpPost.METHOD_NAME.equals(clientContext.getRequest().getRequestLine().getMethod())) {
log.debug(String.format("Accept cookie %s from login response", response.getFirstHeader("Set-Cookie")));
}
else {
response.removeHeaders("Set-Cookie");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ protected DAVClient connect(final Proxy proxy, final HostKeyCallback key, final
configuration.disableRedirectHandling();
configuration.setServiceUnavailableRetryStrategy(new CustomServiceUnavailableRetryStrategy(host,
new ExecutionCountServiceUnavailableRetryStrategy(authentication)));
configuration.addInterceptorFirst(new CteraCookieInterceptor());
return new DAVClient(new HostUrlProvider().withUsername(false).get(host), configuration);
}

Expand Down
37 changes: 37 additions & 0 deletions ctera/src/test/java/ch/cyberduck/core/ctera/CteraSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,57 @@
* GNU General Public License for more details.
*/

import ch.cyberduck.core.Credentials;
import ch.cyberduck.core.DisabledCancelCallback;
import ch.cyberduck.core.DisabledHostKeyCallback;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.Host;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.dav.DAVListService;
import ch.cyberduck.core.exception.ConnectionCanceledException;
import ch.cyberduck.core.proxy.Proxy;
import ch.cyberduck.core.ssl.DefaultX509KeyManager;
import ch.cyberduck.core.ssl.DisabledX509TrustManager;
import ch.cyberduck.core.threading.CancelCallback;
import ch.cyberduck.test.IntegrationTest;

import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import java.util.EnumSet;

import static org.junit.Assert.*;

@Category(IntegrationTest.class)
public class CteraSessionTest extends AbstractCteraTest {

@Test
public void testLoginNonSAML() throws Exception {
new CteraListService(session).list(new Path(session.getHost().getDefaultPath(), EnumSet.of(Path.Type.directory)), new DisabledListProgressListener());
}

@Test
public void testLoginRefreshCookie() throws Exception {
final Host host = new Host(new CteraProtocol(), "mountainduck.ctera.me", new Credentials(
StringUtils.EMPTY, StringUtils.EMPTY,
PROPERTIES.get("ctera.token")
));
host.setDefaultPath("/ServicesPortal/webdav");
final CteraSession session = new CteraSession(host, new DisabledX509TrustManager(), new DefaultX509KeyManager());
assertNotNull(session.open(Proxy.DIRECT, new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()));
assertTrue(session.isConnected());
assertNotNull(session.getClient());
session.login(Proxy.DIRECT, new DisabledLoginCallback(), new CancelCallback() {
@Override
public void verify() throws ConnectionCanceledException {
fail("OAuth tokens need to be refreshed");
}
});
assertEquals("mountainduck@cterasendbox1.onmicrosoft.com", host.getCredentials().getUsername());
assertTrue(host.getCredentials().isSaved());
new DAVListService(session).list(new Path(host.getDefaultPath(), EnumSet.of(Path.Type.directory)), new DisabledListProgressListener());
session.close();
}
}

0 comments on commit 83f3e3e

Please sign in to comment.