Skip to content

Commit

Permalink
Merge pull request #2343 from dvargas46/develop
Browse files Browse the repository at this point in the history
add support for NTLM authentication
  • Loading branch information
ptrthomas committed Jun 22, 2023
2 parents c27a3df + 36e4928 commit f3304c5
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 1 deletion.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2270,6 +2270,7 @@ You can adjust configuration settings for the HTTP client used by Karate using t
`pauseIfNotPerf` | boolean | defaults to `false`, relevant only for performance-testing, see [`karate.pause()`](#karate-pause) and [`karate-gatling`](karate-gatling#think-time)
`xmlNamespaceAware` | boolean | defaults to `false`, to handle XML namespaces in [some special circumstances](https://github.com/karatelabs/karate/issues/1587)
`abortSuiteOnFailure` | boolean | defaults to `false`, to not attempt to run any more tests upon a failure
`ntlmAuth` | JSON | See [NTLM Authentication](#ntlm-authentication)

Examples:
```cucumber
Expand Down Expand Up @@ -2408,6 +2409,33 @@ karate.configure('ssl', { trustAll: true });

For end-to-end examples in the Karate demos, look at the files in [this folder](karate-demo/src/test/java/ssl).

### NTLM Authentication
Karate provides support for NTLM authentication using the Apache NTLMEngine implementation.

| Key | Type | Required? | Description |
|---------------|--------|-----------|----------------------------------------------------------------|
| `username` | string | required | NTLM username |
| `password` | string | required | NTLM password |
| `workstation` | string | optional | The workstation the authentication request is originating from |
| `domain` | string | optional | The domain to authenticate within |

Example:
```cucumber
# enable NTLM authentication for the remaining scenario requests
* configure ntlmAuth = { username: 'admin', password: 'secret', domain: 'my.domain', workstation: 'my-pc' }
# enable NTLM authentication with only credentials
* configure ntlmAuth = { username: 'admin', password: 'secret' }
# disable NTLM authentication
* configure ntlmAuth = null
```

```js
// enable NTLM authentication within js
karate.confgure('ntlmAuth', { username: 'admin', password: 'secret', domain: 'my.domain', workstation: 'my-pc' })
```

# Payload Assertions
## Prepare, Mutate, Assert.
Now it should be clear how Karate makes it easy to express JSON or XML. If you [read from a file](#reading-files), the advantage is that multiple scripts can re-use the same data.
Expand Down
64 changes: 64 additions & 0 deletions karate-core/src/main/java/com/intuit/karate/core/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,13 @@ public class Config {
// image comparison config
private Map<String, Object> imageComparisonOptions;

// ntlm authentication
private boolean ntlmEnabled = false;
private String ntlmUsername;
private String ntlmPassword;
private String ntlmDomain;
private String ntlmWorkstation;

public Config() {
// zero arg constructor
}
Expand Down Expand Up @@ -299,6 +306,18 @@ public boolean configure(String key, Variable value) { // TODO use enum
case "localAddress":
localAddress = value.getAsString();
return true;
case "ntlmAuth":
if (value.isNull()) {
ntlmEnabled = false;
} else {
Map<String, Object> map = value.getValue();
ntlmEnabled = true;
ntlmUsername = (String) map.get("username");
ntlmPassword = (String) map.get("password");
ntlmDomain = (String) map.get("domain");
ntlmWorkstation = (String) map.get("workstation");
}
return true;
default:
throw new RuntimeException("unexpected 'configure' key: '" + key + "'");
}
Expand Down Expand Up @@ -352,6 +371,11 @@ public Config(Config parent) {
continueAfterContinueOnStepFailure = parent.continueAfterContinueOnStepFailure;
abortSuiteOnFailure = parent.abortSuiteOnFailure;
imageComparisonOptions = parent.imageComparisonOptions;
ntlmEnabled = parent.ntlmEnabled;
ntlmUsername = parent.ntlmUsername;
ntlmPassword = parent.ntlmPassword;
ntlmDomain = parent.ntlmDomain;
ntlmWorkstation = parent.ntlmWorkstation;
}

public void setUrl(String url) {
Expand Down Expand Up @@ -590,4 +614,44 @@ public Map<String, Object> getImageComparisonOptions() {
return imageComparisonOptions;
}

public boolean isNtlmEnabled() {
return ntlmEnabled;
}

public void setNtlmEnabled(boolean ntlmEnabled) {
this.ntlmEnabled = ntlmEnabled;
}

public String getNtlmUsername() {
return ntlmUsername;
}

public void setNtlmUsername(String ntlmUsername) {
this.ntlmUsername = ntlmUsername;
}

public String getNtlmPassword() {
return ntlmPassword;
}

public void setNtlmPassword(String ntlmPassword) {
this.ntlmPassword = ntlmPassword;
}

public String getNtlmDomain() {
return ntlmDomain;
}

public void setNtlmDomain(String ntlmDomain) {
this.ntlmDomain = ntlmDomain;
}

public String getNtlmWorkstation() {
return ntlmWorkstation;
}

public void setNtlmWorkstation(String ntlmWorkstation) {
this.ntlmWorkstation = ntlmWorkstation;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@
import org.apache.http.HttpMessage;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
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.entity.EntityBuilder;
import org.apache.http.client.methods.CloseableHttpResponse;
Expand Down Expand Up @@ -192,6 +194,16 @@ private void configure(Config config) {
logger.warn("failed to resolve local address: {} - {}", config.getLocalAddress(), e.getMessage());
}
}
if (config.isNtlmEnabled()) {
List<String> authSchemes = new ArrayList<>();
authSchemes.add(AuthSchemes.NTLM);
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
NTCredentials ntCredentials = new NTCredentials(
config.getNtlmUsername(), config.getNtlmPassword(), config.getNtlmWorkstation(), config.getNtlmDomain());
credentialsProvider.setCredentials(AuthScope.ANY, ntCredentials);
clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
configBuilder.setTargetPreferredAuthSchemes(authSchemes);
}
clientBuilder.setDefaultRequestConfig(configBuilder.build());
SocketConfig.Builder socketBuilder = SocketConfig.custom().setSoTimeout(config.getConnectTimeout());
clientBuilder.setDefaultSocketConfig(socketBuilder.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,11 @@ void testSortArray() {
@Test
void testTypeConv() {
run("type-conv.feature");
}
}

@Test
void testConfigureNtlmAuthentication() {
run("ntlm-authentication.feature");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Feature: ntlm authentication

Scenario: various ways to configure ntlm authentication
* configure ntlmAuth = { username: 'admin', password: 'secret', domain: 'my.domain', workstation: 'my-pc' }
* configure ntlmAuth = { username: 'admin', password: 'secret' }
* configure ntlmAuth = null
* eval
"""
karate.configure('ntlmAuth', { username: 'admin', password: 'secret' })
"""

0 comments on commit f3304c5

Please sign in to comment.