Skip to content
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
7 changes: 3 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ Consequences:
### ⚠️ Breaking — the CXF backend was removed

Version 2.0.0 removes the legacy Apache CXF backend. The dependency-free client introduced in the
previous release is the only implementation; the public API is unchanged, so calling code is
unaffected. Consequences:
previous release is the only implementation; the documented entry points are unchanged, so typical
calling code is unaffected (though a few CXF/SMB-only public types were removed — see Removed).
Consequences:

- **WinRM over HTTPS with self-signed certificates**: unlike the CXF-based client — which silently
trusted every TLS certificate and skipped hostname verification — this client **validates the
Expand All @@ -56,8 +57,6 @@ unaffected. Consequences:
(`-Djavax.net.ssl.trustStore=...`); or
- disable TLS validation with `-Dorg.metricshub.winrm.tls.insecure=true`
(**insecure — for testing only**).
- Setting `-Dorg.metricshub.winrm.backend=cxf` now fails with a clear error instead of selecting
the removed backend: remove the property (or stay on winrm-java 1.x).
- The jar shrinks dramatically: the Apache CXF / JAX-WS / JAXB stack is gone, and with the SMB
file copy replaced by a WinRM-native transfer (see above), the library has **zero runtime
dependencies**.
Expand Down
7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
![GitHub top language](https://img.shields.io/github/languages/top/metricshub/winrm-java)
![License](https://img.shields.io/github/license/metricshub/winrm-java)

This project uses [WS-Man Client](https://github.com/OpenNMS/wsman) and [winrm4j](https://github.com/cloudsoft/winrm4j/)

See **[Project Documentation](https://metricshub.org/winrm-java)** and the [Javadoc](https://metricshub.org/winrm-java/apidocs) for more information on how to use this library in your code.

The Windows Remote Management (WinRM) Java Client is a library that enables to:
Expand All @@ -16,16 +14,15 @@ The Windows Remote Management (WinRM) Java Client is a library that enables to:
> ## ⚠️ Upgrading from 1.x
>
> Version 2.0.0 **removed the legacy Apache CXF backend**: the dependency-free **light** client is
> the only implementation (same public API — calling code is unaffected). Two consequences:
> the only implementation (same documented entry points; a few CXF/SMB-only public types were
> removed). The main consequence:
>
> * Unlike the CXF-based client, which silently trusted every TLS certificate, the light client
> **validates the server certificate and verifies the hostname by default**.
> **WinRM-over-HTTPS connections to hosts with self-signed or otherwise untrusted certificates
> will fail** during the TLS handshake unless you install the server certificate (or its issuing
> CA) into a Java trust store (e.g. `-Djavax.net.ssl.trustStore=...`) or disable TLS validation
> with `-Dorg.metricshub.winrm.tls.insecure=true` (**insecure — for testing only**).
> * Setting `-Dorg.metricshub.winrm.backend=cxf` now fails with a clear error instead of selecting
> the removed backend. Remove the property (or stay on winrm-java 1.x).

## The WinRM client

Expand Down
84 changes: 83 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@

<!-- Reproducible Build -->
<!-- See https://maven.apache.org/guides/mini/guide-reproducible-builds.html -->
<project.build.outputTimestamp>2025-04-03T12:15:29Z</project.build.outputTimestamp>
<!-- Also drives the Maven site copyright year and "Documentation as of" date; bump at release. -->
<project.build.outputTimestamp>2026-07-24T00:00:00Z</project.build.outputTimestamp>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -202,12 +203,82 @@
</executions>
</plugin>

<!-- site: pin a recent maven-site-plugin (the version inherited from oss-parent is too old
for the Doxia 2.0 report plugins and raises a project-info-reports LinkageError) and add
the Sentry skin's companion maven-skin-tools -->
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>4.0.0-M16</version>
<dependencies>
<dependency>
<groupId>org.sentrysoftware.maven</groupId>
<artifactId>maven-skin-tools</artifactId>
<version>1.8.00</version>
</dependency>
</dependencies>
</plugin>

</plugins>
</build>

<reporting>
<plugins>

<!-- Most report plugins (checkstyle, spotbugs, project-info-reports, jxr, javadoc) are
inherited from the oss-parent POM. The project-info-reports, jxr, javadoc and
surefire-report plugins below are declared (or their versions pinned) so the site
builds cleanly on the Doxia 2.0 stack that maven-site-plugin 4.0.0-M16 brings in, and
so the reports menu is fully populated. -->

<!-- Default project-info-reports (Summary, Dependencies, SCM, Licenses, Team, ...) -->
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.9.0</version>
<reportSets>
<reportSet>
<reports>
<report>ci-management</report>
<report>dependencies</report>
<report>dependency-info</report>
<report>distribution-management</report>
<report>issue-management</report>
<report>licenses</report>
<report>plugins</report>
<report>scm</report>
<report>summary</report>
<report>team</report>
</reports>
</reportSet>
</reportSets>
</plugin>

<!-- jxr: cross-referenced HTML source, linked from the checkstyle/pmd reports -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>3.6.0</version>
</plugin>

<!-- javadoc report (published at apidocs/) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>javadoc</report>
</reports>
</reportSet>
</reportSets>
</plugin>

<!-- surefire report: renders the unit-test results from target/surefire-reports -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>3.5.6</version>
</plugin>

<!-- pmd -->
<plugin>
<artifactId>maven-pmd-plugin</artifactId>
Expand All @@ -222,6 +293,17 @@
</configuration>
</plugin>

<!-- changelog: the inherited maven-changelog-plugin 3.0.0-M1 predates Doxia 2.0 and is not
part of the curated reports menu; disable it with an empty report set -->
<plugin>
<artifactId>maven-changelog-plugin</artifactId>
<reportSets>
<reportSet>
<reports />
</reportSet>
</reportSets>
</plugin>

</plugins>
</reporting>

Expand Down
111 changes: 111 additions & 0 deletions src/site/markdown/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
keywords: authentication, ntlm, kerberos, spnego, domain, realm, kdc, krb5, ticket cache

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add license headers to the new documentation pages

All seven newly added Markdown pages start directly with metadata and omit the required license header. Add the project header to each new file, using mvn license:update-file-header as prescribed, so the repository's license checks and file policy are satisfied.

AGENTS.md reference: AGENTS.md:L7-L7

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not making this change. The license-maven-plugin (inherited from the oss-parent POM) is configured to process only main/java/**/*.java, so mvn verify's check-file-header passes and mvn license:update-file-header does not touch Markdown. The pre-existing index.md and the sibling Jawk site follow the same no-header convention: a header would have to sit above the Doxia metadata block (keywords: / description:), which must be the first content of the file, and would break it. Happy to revisit if you'd prefer a dedicated header policy for site pages.

🤖 Addressed by Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up: I verified this empirically. Prepending an Apache-2.0 license header (as an HTML comment) above the front-matter and rebuilding the site breaks the page — Doxia only recognizes keywords:/description: as metadata when they are the very first content, so with a header prepended the page's <meta> tags disappear and the license text plus the raw keywords:/description: lines render as visible body text. Combined with the license-maven-plugin being scoped to main/java/**/*.java (it doesn't process Markdown, and mvn verify is green) and the sibling Jawk site following the same no-header convention, I'm keeping these site pages header-free. Happy to reconsider if you'd like a different policy (e.g. a footer comment).

🤖 Addressed by Claude Code

description: Authenticate to WinRM with NTLM or Kerberos (SPNEGO), including domain accounts and Kerberos configuration.

# Authentication

<!-- MACRO{toc|fromDepth=2|toDepth=3|id=toc} -->

The client authenticates with either **NTLM** or **Kerberos (SPNEGO)**. The scheme is chosen by the
`authentications` argument, a
`List<`[`AuthenticationEnum`](apidocs/org/metricshub/winrm/service/client/auth/AuthenticationEnum.html)`>`
that both `executeWql(...)` and `WinRMCommandExecutor.execute(...)` accept.

```java
import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;
import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;

singletonList(NTLM); // NTLM only (also the default when null or empty)
singletonList(KERBEROS); // Kerberos only
```

If the list is `null` or empty, **NTLM** is used.

## User name and domain

The user name may be given as `DOMAIN\user` or as a bare `user`. When a backslash is present, the
part before it is treated as the Windows domain and the part after it as the account name. In Java,
remember to escape the backslash in a string literal:

```java
"DOMAIN\\Administrator" // domain = DOMAIN, user = Administrator
"Administrator" // no domain
```

## NTLM

NTLM is the default. It works over both transports:

* **HTTP** — the WinRM payload is protected with **NTLM message encryption**, so credentials and
data are not sent in the clear even without TLS.
* **HTTPS** — NTLM runs inside the TLS tunnel. See [TLS / HTTPS](tls.html).

NTLM needs no extra configuration beyond the user name and password.

## Kerberos (SPNEGO)

Kerberos authentication uses SPNEGO through the JDK's GSS-API and **requires HTTPS**.

```java
import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;

executeWql(
HTTPS, "server.example.com", null,
"DOMAIN\\Administrator", password, null,
"SELECT Name FROM Win32_ComputerSystem",
30_000L,
ticketCache, // optional java.nio.file.Path to a ticket cache
singletonList(KERBEROS)
);
```

### Kerberos configuration

By default, Kerberos relies on the **ambient JDK Kerberos configuration** — the platform `krb5.conf`
(or the file named by `-Djava.security.krb5.conf`), or the realm and KDC given directly with
`-Djava.security.krb5.realm` and `-Djava.security.krb5.kdc`:

```bash
java -Djava.security.krb5.realm=EXAMPLE.COM \
-Djava.security.krb5.kdc=dc01.example.com \
-cp ... MyApp
```

The optional `ticketCache` parameter points to a Kerberos ticket cache to use for the connection.

## Choosing the scheme on the command line

The standalone jar selects the scheme with `--ntlm` (the default) or `--kerberos`. The two are
mutually exclusive, and `--kerberos` requires `--https`:

```bash
java -jar ${project.artifactId}-${project.version}-standalone.jar \
-h server.example.com -u 'DOMAIN\user' -pf password.txt \
--https --kerberos \
command whoami
```

Instead of relying on the ambient configuration, the CLI can set the JDK Kerberos configuration for
the current invocation:

| Option | Meaning |
| --- | --- |
| `--kerberos-kdc <host>` | Sets the KDC and, unless `--kerberos-realm` is given, infers the realm from the KDC's DNS suffix. |
| `--kerberos-realm <realm>` | Overrides the inferred realm. Requires `--kerberos-kdc`. |

```bash
java -jar ${project.artifactId}-${project.version}-standalone.jar \
-h server.internal.example.com -u 'DOMAIN\user' -pf password.txt \
--https --kerberos --kerberos-kdc dc01.internal.example.com \
command whoami
```

Here the realm is inferred as `INTERNAL.EXAMPLE.COM` by dropping the KDC's first DNS label and
upper-casing the rest. This follows a common Active Directory naming convention but is not
guaranteed by Kerberos — pass `--kerberos-realm` when the realm does not match the KDC's DNS suffix,
or when the KDC is not a fully qualified DNS name.

## See also

* [TLS / HTTPS](tls.html) — required for Kerberos and recommended for NTLM
* [Timeouts and Errors](timeouts-and-errors.html) — how authentication failures surface
Loading
Loading