Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow OAuth configuration in connection profiles using WebDAV. #16792

Merged
merged 1 commit into from
Jan 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import ch.cyberduck.core.dav.DAVSession;
import ch.cyberduck.core.dav.DAVTouchFeature;
import ch.cyberduck.core.exception.BackgroundException;
import ch.cyberduck.core.exception.ConnectionCanceledException;
import ch.cyberduck.core.features.AttributesFinder;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.features.Directory;
Expand All @@ -41,18 +40,13 @@
import ch.cyberduck.core.features.Upload;
import ch.cyberduck.core.features.Versioning;
import ch.cyberduck.core.features.Write;
import ch.cyberduck.core.http.CustomServiceUnavailableRetryStrategy;
import ch.cyberduck.core.http.DefaultHttpResponseExceptionMappingService;
import ch.cyberduck.core.http.ExecutionCountServiceUnavailableRetryStrategy;
import ch.cyberduck.core.http.HttpUploadFeature;
import ch.cyberduck.core.nextcloud.NextcloudDeleteFeature;
import ch.cyberduck.core.nextcloud.NextcloudListService;
import ch.cyberduck.core.nextcloud.NextcloudShareFeature;
import ch.cyberduck.core.nextcloud.NextcloudUrlProvider;
import ch.cyberduck.core.nextcloud.NextcloudWriteFeature;
import ch.cyberduck.core.oauth.OAuth2AuthorizationService;
import ch.cyberduck.core.oauth.OAuth2ErrorResponseInterceptor;
import ch.cyberduck.core.oauth.OAuth2RequestInterceptor;
import ch.cyberduck.core.ocs.OcsCapabilities;
import ch.cyberduck.core.ocs.OcsCapabilitiesRequest;
import ch.cyberduck.core.ocs.OcsCapabilitiesResponseHandler;
Expand All @@ -70,7 +64,6 @@
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpResponseException;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

Expand All @@ -84,8 +77,6 @@
public class OwncloudSession extends DAVSession {
private static final Logger log = LogManager.getLogger(OwncloudSession.class);

private OAuth2RequestInterceptor authorizationService;

protected final TusCapabilities tus = new TusCapabilities();
protected final OcsCapabilities ocs = new OcsCapabilities();

Expand All @@ -110,26 +101,11 @@ protected DAVClient connect(final ProxyFinder proxy, final HostKeyCallback key,
return client;
}

@Override
protected HttpClientBuilder getConfiguration(final ProxyFinder proxy, final LoginCallback prompt) throws ConnectionCanceledException {
final HttpClientBuilder configuration = super.getConfiguration(proxy, prompt);
if(host.getProtocol().isOAuthConfigurable()) {
authorizationService = new OAuth2RequestInterceptor(configuration.build(), host, prompt)
.withRedirectUri(host.getProtocol().getOAuthRedirectUrl());
if(host.getProtocol().getAuthorization() != null) {
authorizationService.withFlowType(OAuth2AuthorizationService.FlowType.valueOf(host.getProtocol().getAuthorization()));
}
configuration.addInterceptorLast(authorizationService);
configuration.setServiceUnavailableRetryStrategy(new CustomServiceUnavailableRetryStrategy(host,
new ExecutionCountServiceUnavailableRetryStrategy(new OAuth2ErrorResponseInterceptor(host, authorizationService))));
}
return configuration;
}

@Override
public void login(final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
super.login(prompt, cancel);
if(host.getProtocol().isOAuthConfigurable()) {
final Credentials credentials = authorizationService.validate();
final Credentials credentials = host.getCredentials();
final OAuthTokens oauth = credentials.getOauth();
try {
final String username = JWT.decode(oauth.getIdToken()).getClaim("preferred_username").asString();
Expand All @@ -141,7 +117,6 @@ public void login(final LoginCallback prompt, final CancelCallback cancel) throw
log.warn("Failure {} decoding JWT {}", e, oauth.getIdToken());
}
}
super.login(prompt, cancel);
try {
client.execute(new OcsCapabilitiesRequest(host), new OcsCapabilitiesResponseHandler(ocs));
}
Expand Down
5 changes: 5 additions & 0 deletions webdav/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
<artifactId>core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ch.cyberduck</groupId>
<artifactId>oauth</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ch.cyberduck</groupId>
<artifactId>test</artifactId>
Expand Down
23 changes: 21 additions & 2 deletions webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,20 @@
import ch.cyberduck.core.exception.ListCanceledException;
import ch.cyberduck.core.exception.LoginCanceledException;
import ch.cyberduck.core.features.*;
import ch.cyberduck.core.http.CustomServiceUnavailableRetryStrategy;
import ch.cyberduck.core.http.ExecutionCountServiceUnavailableRetryStrategy;
import ch.cyberduck.core.http.HttpExceptionMappingService;
import ch.cyberduck.core.http.HttpSession;
import ch.cyberduck.core.http.PreferencesRedirectCallback;
import ch.cyberduck.core.http.RedirectCallback;
import ch.cyberduck.core.oauth.OAuth2AuthorizationService;
import ch.cyberduck.core.oauth.OAuth2ErrorResponseInterceptor;
import ch.cyberduck.core.oauth.OAuth2RequestInterceptor;
import ch.cyberduck.core.preferences.HostPreferences;
import ch.cyberduck.core.preferences.PreferencesReader;
import ch.cyberduck.core.proxy.ProxyFinder;
import ch.cyberduck.core.shared.DefaultPathHomeFeature;
import ch.cyberduck.core.shared.DelegatingHomeFeature;
import ch.cyberduck.core.shared.WorkdirHomeFeature;
import ch.cyberduck.core.ssl.X509KeyManager;
import ch.cyberduck.core.ssl.X509TrustManager;
import ch.cyberduck.core.threading.CancelCallback;
Expand Down Expand Up @@ -90,6 +94,8 @@ public class DAVSession extends HttpSession<DAVClient> {
private final PreferencesReader preferences = new HostPreferences(host);
private final HttpCapabilities capabilities = new HttpCapabilities(preferences);

private OAuth2RequestInterceptor authorizationService;

public DAVSession(final Host host, final X509TrustManager trust, final X509KeyManager key) {
this(host, trust, key, new PreferencesRedirectCallback());
}
Expand All @@ -107,6 +113,16 @@ protected DAVClient connect(final ProxyFinder proxy, final HostKeyCallback key,

protected HttpClientBuilder getConfiguration(final ProxyFinder proxy, final LoginCallback prompt) throws ConnectionCanceledException {
final HttpClientBuilder configuration = builder.build(proxy, this, prompt);
if(host.getProtocol().isOAuthConfigurable()) {
authorizationService = new OAuth2RequestInterceptor(configuration.build(), host, prompt)
.withRedirectUri(host.getProtocol().getOAuthRedirectUrl());
if(host.getProtocol().getAuthorization() != null) {
authorizationService.withFlowType(OAuth2AuthorizationService.FlowType.valueOf(host.getProtocol().getAuthorization()));
}
configuration.addInterceptorLast(authorizationService);
configuration.setServiceUnavailableRetryStrategy(new CustomServiceUnavailableRetryStrategy(host,
new ExecutionCountServiceUnavailableRetryStrategy(new OAuth2ErrorResponseInterceptor(host, authorizationService))));
}
configuration.setRedirectStrategy(new DAVRedirectStrategy(redirect));
configuration.addInterceptorLast(new MicrosoftIISPersistentAuthResponseInterceptor());
return configuration;
Expand All @@ -124,8 +140,11 @@ protected void logout() throws BackgroundException {

@Override
public void login(final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
final Credentials credentials = host.getCredentials();
if(host.getProtocol().isOAuthConfigurable()) {
authorizationService.validate();
}
if(host.getProtocol().isPasswordConfigurable()) {
final Credentials credentials = host.getCredentials();
final String domain, username;
if(credentials.getUsername().contains("\\")) {
domain = StringUtils.substringBefore(credentials.getUsername(), "\\");
Expand Down
Loading