Skip to content

Commit

Permalink
Merge pull request #1531 in ITERATE/cyberduck from bugfix/MD-6410 to …
Browse files Browse the repository at this point in the history
…master

* commit 'b39ddf279deda0bb14560ea614032c4859fb9066':
  Add test for explicit NTLM backend authentication.
  Delete test.
  Rename property.
  Use static authentication provider for Integrated Windows Authentication with proxy instead of providers registered for target host authentication that do not have the WindowsNTLMSchemeFactory registered.
  Disable target host authentication using Windows Integrated Authentication by default.
  Formatting.
  Revert setting preferences.
  Enable reading domain NTLM settings from environment.
  Only enable IWA when enabled for target authentication.
  Add property `webdav.ntlm.iwa.enable`.
  Review.
  Fix test.
  Register credentials for authentication using NTLM/Negotiate using WindowsCredentialsProvider.
  Add Sharepoint Test
  Set authentication context.
  • Loading branch information
automerge committed Dec 20, 2018
2 parents c9ad771 + b39ddf2 commit 634e906
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ protected override void setDefaults()
// Enable Integrated Windows Authentication
this.setDefault("connection.proxy.windows.authentication.enable", true.ToString());

this.setDefault("webdav.ntlm.environment", false.ToString());
this.setDefault("webdav.ntlm.environment", true.ToString());
if (getBoolean("webdav.ntlm.environment"))
{
// NTLM Windows Domain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,45 +97,48 @@ public CallbackProxyAuthenticationStrategy(final ProxyCredentialsStore keychain,
public Queue<AuthOption> select(final Map<String, Header> challenges, final HttpHost authhost, final HttpResponse response, final HttpContext context) throws MalformedChallengeException {
final HttpClientContext clientContext = HttpClientContext.adapt(context);
final Queue<AuthOption> options = new LinkedList<AuthOption>();
final Lookup<AuthSchemeProvider> registry = clientContext.getAuthSchemeRegistry();
if(registry == null) {
return options;
}
final RequestConfig config = clientContext.getRequestConfig();
Collection<String> authPrefs = config.getProxyPreferredAuthSchemes();
if(authPrefs == null) {
authPrefs = DEFAULT_SCHEME_PRIORITY;
}

// if available try to authenticate with Integrated Windows Authentication
if(preferences.getBoolean("connection.proxy.windows.authentication.enable")) {
if(WinHttpClients.isWinAuthAvailable()) {
for(String s : IWA_SCHEME_PRIORITY) {
final Header challenge = challenges.get(s.toLowerCase(Locale.ROOT));
if(challenge != null) {
final AuthSchemeProvider provider = registry.lookup(s);
if(provider != null) {
final AuthScheme authScheme = provider.create(context);
authScheme.processChallenge(challenge);
final AuthScope authScope = new AuthScope(
authhost.getHostName(),
authhost.getPort(),
authScheme.getRealm(),
authScheme.getSchemeName());
if(log.isDebugEnabled()) {
log.debug(String.format("Add authentication options for scheme %s", authPrefs));
}
options.add(new AuthOption(authScheme, new WindowsCredentialsProvider(
null == clientContext.getCredentialsProvider() ? new BasicCredentialsProvider() : clientContext.getCredentialsProvider()).getCredentials(authScope)));
final AuthSchemeProvider provider;
switch(s) {
case AuthSchemes.SPNEGO:
provider = new BackportWindowsNegotiateSchemeFactory(null);
break;
default:
provider = new BackportWindowsNTLMSchemeFactory(null);
break;
}
if(log.isDebugEnabled()) {
log.debug(String.format("Use provider %s for challenge %s", provider, challenge));
}
final AuthScheme authScheme = provider.create(context);
authScheme.processChallenge(challenge);
final AuthScope authScope = new AuthScope(
authhost.getHostName(),
authhost.getPort(),
authScheme.getRealm(),
authScheme.getSchemeName());
if(log.isDebugEnabled()) {
log.debug(String.format("Add authentication options for scheme %s", authPrefs));
}
options.add(new AuthOption(authScheme, new WindowsCredentialsProvider(
null == clientContext.getCredentialsProvider() ? new BasicCredentialsProvider() : clientContext.getCredentialsProvider()).getCredentials(authScope)));
}
}
if(!options.isEmpty()) {
return options;
}
}
}

Credentials credentials = keychain.getCredentials(authhost.toURI());
if(StringUtils.isEmpty(credentials.getPassword())) {
try {
Expand All @@ -159,6 +162,11 @@ public Queue<AuthOption> select(final Map<String, Header> challenges, final Http
throw new MalformedChallengeException(ignored.getMessage(), ignored);
}
}
final Lookup<AuthSchemeProvider> registry = clientContext.getAuthSchemeRegistry();
if(registry == null) {
log.warn("Missing authentication scheme registry in client context");
return options;
}
if(log.isDebugEnabled()) {
log.debug(String.format("Authentication schemes in the order of preference: %s", authPrefs));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ public HttpClientBuilder build(final Proxy proxy, final TranscriptListener liste
Charset.forName(preferences.getProperty("http.credentials.charset"))))
.register(AuthSchemes.DIGEST, new DigestSchemeFactory(
Charset.forName(preferences.getProperty("http.credentials.charset"))))
.register(AuthSchemes.NTLM, WinHttpClients.isWinAuthAvailable() ?
.register(AuthSchemes.NTLM, preferences.getBoolean("webdav.ntlm.windows.authentication.enable") && WinHttpClients.isWinAuthAvailable() ?
new BackportWindowsNTLMSchemeFactory(null) :
new NTLMSchemeFactory())
.register(AuthSchemes.SPNEGO, WinHttpClients.isWinAuthAvailable() ?
.register(AuthSchemes.SPNEGO, preferences.getBoolean("webdav.ntlm.windows.authentication.enable") && WinHttpClients.isWinAuthAvailable() ?
new BackportWindowsNegotiateSchemeFactory(null) :
new SPNegoSchemeFactory())
.register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()).build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,11 @@ Current default browser view is outline view (0-List view, 1-Outline view, 2-Col
this.setDefault("webdav.ntlm.domain", StringUtils.EMPTY);
this.setDefault("webdav.ntlm.workstation", StringUtils.EMPTY);

/**
* Enable Integrated Windows Authentication (IWA) for target server authentication
*/
this.setDefault("webdav.ntlm.windows.authentication.enable", String.valueOf(false));

/*
Enable preemptive authentication if valid credentials are found
*/
Expand Down Expand Up @@ -941,7 +946,7 @@ Current default browser view is outline view (0-List view, 1-Outline view, 2-Col
this.setDefault("connection.proxy.enable", String.valueOf(true));
this.setDefault("connection.proxy.ntlm.domain", StringUtils.EMPTY);
/*
Integrated Windows Authentication
Integrated Windows Authentication (IWA)
*/
this.setDefault("connection.proxy.windows.authentication.enable", String.valueOf(false));

Expand Down
48 changes: 44 additions & 4 deletions webdav/src/main/java/ch/cyberduck/core/dav/DAVSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,18 @@
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.auth.win.WindowsCredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
import org.apache.http.impl.client.WinHttpClients;
import org.apache.log4j.Logger;

import javax.net.SocketFactory;
Expand Down Expand Up @@ -135,10 +144,41 @@ protected void logout() throws BackgroundException {

@Override
public void login(final Proxy proxy, final LoginCallback prompt, final CancelCallback cancel) throws BackgroundException {
client.setCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword(),
// Windows credentials. Provide empty string for NTLM domain by default.
preferences.getProperty("webdav.ntlm.workstation"),
preferences.getProperty("webdav.ntlm.domain"));
final CredentialsProvider provider = new BasicCredentialsProvider();
if(preferences.getBoolean("webdav.ntlm.windows.authentication.enable") && WinHttpClients.isWinAuthAvailable()) {
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM),
new WindowsCredentialsProvider(new BasicCredentialsProvider()).getCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM))
);
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.SPNEGO),
new WindowsCredentialsProvider(new SystemDefaultCredentialsProvider()).getCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.SPNEGO))
);
}
else {
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.NTLM),
new NTCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword(),
preferences.getProperty("webdav.ntlm.workstation"), preferences.getProperty("webdav.ntlm.domain"))
);
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.SPNEGO),
new NTCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword(),
preferences.getProperty("webdav.ntlm.workstation"), preferences.getProperty("webdav.ntlm.domain"))
);
}
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC),
new UsernamePasswordCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword()));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.DIGEST),
new UsernamePasswordCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword()));
provider.setCredentials(
new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.KERBEROS),
new UsernamePasswordCredentials(host.getCredentials().getUsername(), host.getCredentials().getPassword()));
client.setCredentials(provider);
if(preferences.getBoolean("webdav.basic.preemptive")) {
switch(proxy.getType()) {
case DIRECT:
Expand Down
12 changes: 12 additions & 0 deletions webdav/src/test/java/ch/cyberduck/core/dav/DAVSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,18 @@ public void testLoginBasicAuth() throws Exception {
session.close();
}

@Test
public void testLoginNTLM() throws Exception {
final Host host = new Host(new DAVProtocol(), "winbuild.iterate.ch", new Credentials(
System.getProperties().getProperty("webdav.iis.user"), System.getProperties().getProperty("webdav.iis.password")
));
host.setDefaultPath("/WebDAV");
final DAVSession session = new DAVSession(host);
session.open(Proxy.DIRECT, new DisabledHostKeyCallback(), new DisabledLoginCallback());
session.login(Proxy.DIRECT, new DisabledLoginCallback(), new DisabledCancelCallback());
session.close();
}

@Test
public void testTouch() throws Exception {
final Host host = new Host(new DAVProtocol(), "test.cyberduck.ch", new Credentials(
Expand Down

0 comments on commit 634e906

Please sign in to comment.