localFiles = localFileToCopyList
+ .stream()
+ .filter(Utils::isNotBlank)
+ .collect(Collectors.toList());
+
+ // Copy the list specified list of files, and update the command accordingly
+ final String localFilesUpdatedCommand = WindowsRemoteProcessUtils.copyLocalFilesToShare(
+ command,
+ localFiles,
+ smbTempShare.getUncSharePath(),
+ smbTempShare.getRemotePath()
+ );
+
+ final Charset charset = WindowsRemoteProcessUtils.getWindowsEncodingCharset(
+ smbTempShare.getWindowsRemoteExecutor(),
+ TimeoutHelper.getRemainingTime(timeout, start, "No time left to retrieve the code set")
+ );
+
+ return smbTempShare
+ .getWindowsRemoteExecutor()
+ .executeCommand(
+ String.format("CMD.EXE /C (%s)", localFilesUpdatedCommand),
+ null,
+ charset,
+ TimeoutHelper.getRemainingTime(timeout, start, "No time left to execute command")
+ );
+ } catch (final WqlQuerySyntaxException e) {
+ throw new IOException(e);
+ }
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/exceptions/WinRMException.java b/src/main/java/org/metricshub/winrm/exceptions/WinRMException.java
index 72f5985..d3b32a3 100644
--- a/src/main/java/org/metricshub/winrm/exceptions/WinRMException.java
+++ b/src/main/java/org/metricshub/winrm/exceptions/WinRMException.java
@@ -1,42 +1,42 @@
-package org.metricshub.winrm.exceptions;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-public class WinRMException extends WindowsRemoteException {
-
- private static final long serialVersionUID = 1L;
-
- public WinRMException(final String message) {
- super(message);
- }
-
- public WinRMException(final String messageFromat, final Object... args) {
- super(messageFromat, args);
- }
-
- public WinRMException(final Throwable cause, final String message) {
- super(cause, message);
- }
-
- public WinRMException(final Throwable cause) {
- super(cause);
- }
-}
+package org.metricshub.winrm.exceptions;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+public class WinRMException extends WindowsRemoteException {
+
+ private static final long serialVersionUID = 1L;
+
+ public WinRMException(final String message) {
+ super(message);
+ }
+
+ public WinRMException(final String messageFromat, final Object... args) {
+ super(messageFromat, args);
+ }
+
+ public WinRMException(final Throwable cause, final String message) {
+ super(cause, message);
+ }
+
+ public WinRMException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/exceptions/WindowsRemoteException.java b/src/main/java/org/metricshub/winrm/exceptions/WindowsRemoteException.java
index a734176..36eedd2 100644
--- a/src/main/java/org/metricshub/winrm/exceptions/WindowsRemoteException.java
+++ b/src/main/java/org/metricshub/winrm/exceptions/WindowsRemoteException.java
@@ -1,46 +1,46 @@
-package org.metricshub.winrm.exceptions;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-public class WindowsRemoteException extends Exception {
-
- private static final long serialVersionUID = 1L;
-
- public WindowsRemoteException(final String message) {
- super(message);
- }
-
- public WindowsRemoteException(final String messageFromat, final Object... args) {
- super(String.format(messageFromat, args));
- }
-
- public WindowsRemoteException(final Throwable cause, final String message) {
- super(message, cause);
- }
-
- public WindowsRemoteException(final Throwable cause, final String messageFromat, final Object... args) {
- super(String.format(messageFromat, args), cause);
- }
-
- public WindowsRemoteException(final Throwable cause) {
- super(cause);
- }
-}
+package org.metricshub.winrm.exceptions;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+public class WindowsRemoteException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public WindowsRemoteException(final String message) {
+ super(message);
+ }
+
+ public WindowsRemoteException(final String messageFromat, final Object... args) {
+ super(String.format(messageFromat, args));
+ }
+
+ public WindowsRemoteException(final Throwable cause, final String message) {
+ super(message, cause);
+ }
+
+ public WindowsRemoteException(final Throwable cause, final String messageFromat, final Object... args) {
+ super(String.format(messageFromat, args), cause);
+ }
+
+ public WindowsRemoteException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.java b/src/main/java/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.java
index 23d978a..eeca9d3 100644
--- a/src/main/java/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.java
+++ b/src/main/java/org/metricshub/winrm/exceptions/WqlQuerySyntaxException.java
@@ -1,38 +1,37 @@
-package org.metricshub.winrm.exceptions;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-/**
- * Exception for a syntax error in the WQL Query parameter.
- *
- */
-public class WqlQuerySyntaxException extends Exception {
-
- private static final long serialVersionUID = 1L;
-
- public WqlQuerySyntaxException(final String wqlQuery) {
- super("Syntax error in WQL Query: " + wqlQuery);
- }
-
- public WqlQuerySyntaxException(final Throwable cause) {
- super(cause);
- }
-}
+package org.metricshub.winrm.exceptions;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+/**
+ * Exception for a syntax error in the WQL Query parameter.
+ */
+public class WqlQuerySyntaxException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public WqlQuerySyntaxException(final String wqlQuery) {
+ super("Syntax error in WQL Query: " + wqlQuery);
+ }
+
+ public WqlQuerySyntaxException(final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/light/AuthScheme.java b/src/main/java/org/metricshub/winrm/light/AuthScheme.java
index 6562785..105fae8 100644
--- a/src/main/java/org/metricshub/winrm/light/AuthScheme.java
+++ b/src/main/java/org/metricshub/winrm/light/AuthScheme.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,8 @@
* differ between NTLM and Kerberos. {@link WsmanClient} is otherwise mechanism-agnostic and just
* delegates to the scheme, so a new mechanism is added by implementing this interface rather than
* branching the client.
- *
- * All methods are called while {@code WsmanClient} holds its operation lock, so implementations
+ *
+ * All methods are called while {@code WsmanClient} holds its operation lock, so implementations
* need no internal synchronization.
*/
interface AuthScheme {
diff --git a/src/main/java/org/metricshub/winrm/light/ByteArrayUtils.java b/src/main/java/org/metricshub/winrm/light/ByteArrayUtils.java
index d468a14..54345a7 100644
--- a/src/main/java/org/metricshub/winrm/light/ByteArrayUtils.java
+++ b/src/main/java/org/metricshub/winrm/light/ByteArrayUtils.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,7 +66,8 @@ public static String formatHexDump(final byte[] array) {
final byte c = array[rowOffset + index];
builder.append((c >= 20 && c < 127) ? (char) c : '.');
- if (index % 8 == 7) builder.append(" ");
+ if (index % 8 == 7)
+ builder.append(" ");
}
}
}
diff --git a/src/main/java/org/metricshub/winrm/light/CipherGen.java b/src/main/java/org/metricshub/winrm/light/CipherGen.java
index 378670a..2bd0dc0 100644
--- a/src/main/java/org/metricshub/winrm/light/CipherGen.java
+++ b/src/main/java/org/metricshub/winrm/light/CipherGen.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -189,10 +189,9 @@ private byte[] getNTLMv2Blob() {
* client challenge.
*
* @param targetInformation
- * The target information block from the Type 2 message.
+ * The target information block from the Type 2 message.
* @param clientChallenge
- * The random 8-byte client challenge.
- *
+ * The random 8-byte client challenge.
* @return The blob, used in the calculation of the NTLMv2 Response.
*/
private static byte[] createBlob(
@@ -205,12 +204,12 @@ private static byte[] createBlob(
final byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
final byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
final byte[] blob = new byte[blobSignature.length +
- reserved.length +
- timestamp.length +
- 8 +
- unknown1.length +
- targetInformation.length +
- unknown2.length];
+ reserved.length +
+ timestamp.length +
+ 8 +
+ unknown1.length +
+ targetInformation.length +
+ unknown2.length];
int offset = 0;
System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length);
offset += blobSignature.length;
@@ -261,8 +260,8 @@ public byte[] getNTLM2SessionResponse() throws NtlmException {
* @param challenge
* @param clientChallenge
* @return The NTLM2 Session Response. This is placed in the NTLM response
- * field of the Type 3 message; the LM response field contains the
- * client challenge, null-padded to 24 bytes.
+ * field of the Type 3 message; the LM response field contains the
+ * client challenge, null-padded to 24 bytes.
*/
private static byte[] ntlm2SessionResponse(
final byte[] ntlmHash,
@@ -289,10 +288,9 @@ private static byte[] ntlm2SessionResponse(
* Creates the LM Response from the given hash and Type 2 challenge.
*
* @param hash
- * The LM or NTLM Hash.
+ * The LM or NTLM Hash.
* @param challenge
- * The server challenge from the Type 2 message.
- *
+ * The server challenge from the Type 2 message.
* @return The response (either LM or NTLM, depending on the provided hash).
*/
private static byte[] lmResponse(final byte[] hash, final byte[] challenge) throws NtlmException {
@@ -323,10 +321,9 @@ private static byte[] lmResponse(final byte[] hash, final byte[] challenge) thro
* Creates the LM Hash of the user's password.
*
* @param password
- * The password.
- *
+ * The password.
* @return The LM Hash of the given password, used in the calculation of the
- * LM Response.
+ * LM Response.
*/
private static byte[] lmHash(final String password) throws NtlmException {
try {
@@ -356,13 +353,12 @@ private static byte[] lmHash(final String password) throws NtlmException {
* Creates a DES encryption key from the given key material.
*
* @param bytes
- * A byte array containing the DES key material.
+ * A byte array containing the DES key material.
* @param offset
- * The offset in the given byte array at which the 7-byte key
- * material starts.
- *
+ * The offset in the given byte array at which the 7-byte key
+ * material starts.
* @return A DES encryption key created from the key material starting at
- * the specified offset in the given byte array.
+ * the specified offset in the given byte array.
*/
private static Key createDESKey(final byte[] bytes, final int offset) {
final byte[] keyBytes = new byte[7];
@@ -384,13 +380,13 @@ private static Key createDESKey(final byte[] bytes, final int offset) {
* Applies odd parity to the given byte array.
*
* @param bytes
- * The data whose parity bits are to be adjusted for odd parity.
+ * The data whose parity bits are to be adjusted for odd parity.
*/
private static void oddParity(final byte[] bytes) {
for (int i = 0; i < bytes.length; i++) {
final byte b = bytes[i];
- final boolean needsParity =
- (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0;
+ final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1))
+ & 0x01) == 0;
if (needsParity) {
bytes[i] |= (byte) 0x01;
} else {
@@ -484,10 +480,9 @@ public byte[] getLanManagerSessionKey() throws NtlmException {
* Creates the NTLM Hash of the user's password.
*
* @param password
- * The password.
- *
+ * The password.
* @return The NTLM Hash of the given password, used in the calculation of
- * the NTLM Response and the NTLMv2 and LMv2 Hashes.
+ * the NTLM Response and the NTLMv2 and LMv2 Hashes.
*/
private static byte[] ntlmHash(final String password) throws NtlmException {
if (NTLMEngineUtils.UNICODE_LITTLE_UNMARKED == null) {
@@ -503,7 +498,7 @@ private static byte[] ntlmHash(final String password) throws NtlmException {
* Creates the LMv2 Hash of the user's password.
*
* @return The LMv2 Hash, used in the calculation of the NTLMv2 and LMv2
- * Responses.
+ * Responses.
*/
private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash) throws NtlmException {
if (NTLMEngineUtils.UNICODE_LITTLE_UNMARKED == null) {
@@ -522,7 +517,7 @@ private static byte[] lmv2Hash(final String domain, final String user, final byt
* Creates the NTLMv2 Hash of the user's password.
*
* @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2
- * Responses.
+ * Responses.
*/
private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash) throws NtlmException {
if (NTLMEngineUtils.UNICODE_LITTLE_UNMARKED == null) {
@@ -542,14 +537,13 @@ private static byte[] ntlmv2Hash(final String domain, final String user, final b
* challenge.
*
* @param hash
- * The NTLMv2 Hash.
+ * The NTLMv2 Hash.
* @param clientData
- * The client data (blob or client challenge).
+ * The client data (blob or client challenge).
* @param challenge
- * The server challenge from the Type 2 message.
- *
+ * The server challenge from the Type 2 message.
* @return The response (either NTLMv2 or LMv2, depending on the client
- * data).
+ * data).
*/
private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData) {
final HMACMD5 hmacMD5 = new HMACMD5(hash);
diff --git a/src/main/java/org/metricshub/winrm/light/EncryptionUtils.java b/src/main/java/org/metricshub/winrm/light/EncryptionUtils.java
index 9108c14..315c070 100644
--- a/src/main/java/org/metricshub/winrm/light/EncryptionUtils.java
+++ b/src/main/java/org/metricshub/winrm/light/EncryptionUtils.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/metricshub/winrm/light/Envelopes.java b/src/main/java/org/metricshub/winrm/light/Envelopes.java
index 001e924..00b3483 100644
--- a/src/main/java/org/metricshub/winrm/light/Envelopes.java
+++ b/src/main/java/org/metricshub/winrm/light/Envelopes.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,8 +59,7 @@ private Envelopes() {}
// --- WQL ---------------------------------------------------------------
static String enumerateWql(final String url, final String namespace, final String wql, final long timeoutMs) {
- return (
- envelopeOpen(false) +
+ return (envelopeOpen(false) +
header(url, wmiResourceUri(namespace), ACTION_ENUMERATE, timeoutMs, null, null) +
"" +
"" +
@@ -68,88 +67,73 @@ static String enumerateWql(final String url, final String namespace, final Strin
"" +
escape(wql) +
"" +
- ""
- );
+ "");
}
static String pull(final String url, final String namespace, final String context, final long timeoutMs) {
- return (
- envelopeOpen(false) +
+ return (envelopeOpen(false) +
header(url, wmiResourceUri(namespace), ACTION_PULL, timeoutMs, null, null) +
"" +
"" +
escape(context) +
"" +
"32000" +
- ""
- );
+ "");
}
// --- Command shell -----------------------------------------------------
static String createShell(final String url, final String workingDirectory, final long timeoutMs) {
- final String optionSet =
- "" +
+ final String optionSet = "" +
"TRUE" +
"437" +
"";
final String workingDir = (workingDirectory == null || workingDirectory.trim().isEmpty())
? ""
: "" + escape(workingDirectory) + "";
- return (
- envelopeOpen(true) +
+ return (envelopeOpen(true) +
header(url, SHELL_RESOURCE_URI, ACTION_CREATE, timeoutMs, null, optionSet) +
"" +
"stdin" +
"stdout stderr" +
workingDir +
- ""
- );
+ "");
}
static String command(final String url, final String shellId, final String commandLine, final long timeoutMs) {
- final String optionSet =
- "" +
+ final String optionSet = "" +
"TRUE" +
"FALSE" +
"";
- return (
- envelopeOpen(true) +
+ return (envelopeOpen(true) +
header(url, SHELL_RESOURCE_URI, ACTION_COMMAND, timeoutMs, shellSelector(shellId), optionSet) +
"" +
escape(commandLine) +
- ""
- );
+ "");
}
static String receive(final String url, final String shellId, final String commandId, final long timeoutMs) {
- return (
- envelopeOpen(true) +
+ return (envelopeOpen(true) +
header(url, SHELL_RESOURCE_URI, ACTION_RECEIVE, timeoutMs, shellSelector(shellId), null) +
"stdout stderr"
- );
+ "\">stdout stderr");
}
static String signal(final String url, final String shellId, final String commandId, final long timeoutMs) {
- return (
- envelopeOpen(true) +
+ return (envelopeOpen(true) +
header(url, SHELL_RESOURCE_URI, ACTION_SIGNAL, timeoutMs, shellSelector(shellId), null) +
"" +
TERMINATE_CODE +
- ""
- );
+ "");
}
static String deleteShell(final String url, final String shellId, final long timeoutMs) {
- return (
- envelopeOpen(true) +
+ return (envelopeOpen(true) +
header(url, SHELL_RESOURCE_URI, ACTION_DELETE, timeoutMs, shellSelector(shellId), null) +
- ""
- );
+ "");
}
// --- helpers -----------------------------------------------------------
@@ -159,9 +143,8 @@ private static String wmiResourceUri(final String namespace) {
}
private static String shellSelector(final String shellId) {
- return (
- "" + escape(shellId) + ""
- );
+ return ("" + escape(shellId)
+ + "");
}
/**
@@ -182,8 +165,7 @@ private static String header(
final String selectorSet,
final String optionSet
) {
- return (
- "" +
+ return ("" +
"" +
url +
"" +
@@ -208,13 +190,11 @@ private static String header(
"" +
operationTimeout(timeoutMs) +
"" +
- ""
- );
+ "");
}
private static String envelopeOpen(final boolean shell) {
- return (
- ""
- );
+ ">");
}
private static String escape(final String s) {
diff --git a/src/main/java/org/metricshub/winrm/light/FallbackAuthScheme.java b/src/main/java/org/metricshub/winrm/light/FallbackAuthScheme.java
index efe7039..ac3b7e0 100644
--- a/src/main/java/org/metricshub/winrm/light/FallbackAuthScheme.java
+++ b/src/main/java/org/metricshub/winrm/light/FallbackAuthScheme.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,8 +26,8 @@
* Tries several {@link AuthScheme}s in the caller's order, using the first whose handshake succeeds
* (e.g. {@code [KERBEROS, NTLM]}: attempt Kerberos, fall back to NTLM). Once a scheme authenticates
* it becomes the active one for the rest of the connection; on reconnect the fallback runs again.
- *
- * Fallback triggers on a failed handshake — the common case being Kerberos unavailable (no TGT,
+ *
+ * Fallback triggers on a failed handshake — the common case being Kerberos unavailable (no TGT,
* no reachable KDC, unconfigured realm), which fails client-side before any SOAP is sent.
*/
final class FallbackAuthScheme implements AuthScheme {
@@ -70,7 +70,7 @@ public String authenticate(final HttpTransport transport) throws Exception {
}
throw new IllegalStateException(
"All requested authentication schemes failed" +
- (lastFailure == null ? "" : " (last: " + lastFailure.getMessage() + ")"),
+ (lastFailure == null ? "" : " (last: " + lastFailure.getMessage() + ")"),
lastFailure
);
}
diff --git a/src/main/java/org/metricshub/winrm/light/HMACMD5.java b/src/main/java/org/metricshub/winrm/light/HMACMD5.java
index 319dbf4..1722299 100644
--- a/src/main/java/org/metricshub/winrm/light/HMACMD5.java
+++ b/src/main/java/org/metricshub/winrm/light/HMACMD5.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@
/**
* Cryptography support - HMACMD5 - algorithmically based on various web
* resources by Karl Wright
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
diff --git a/src/main/java/org/metricshub/winrm/light/HttpTransport.java b/src/main/java/org/metricshub/winrm/light/HttpTransport.java
index 8cfd8d4..580dc98 100644
--- a/src/main/java/org/metricshub/winrm/light/HttpTransport.java
+++ b/src/main/java/org/metricshub/winrm/light/HttpTransport.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/metricshub/winrm/light/KerberosAuthScheme.java b/src/main/java/org/metricshub/winrm/light/KerberosAuthScheme.java
index ac3f30f..06de531 100644
--- a/src/main/java/org/metricshub/winrm/light/KerberosAuthScheme.java
+++ b/src/main/java/org/metricshub/winrm/light/KerberosAuthScheme.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,11 +45,11 @@
* obtains a TGT via JAAS ({@code Krb5LoginModule}) from a username+password (or a ticket cache),
* then a service ticket for {@code HTTP/} and emits the AP-REQ under the {@code Negotiate}
* header.
- *
- * HTTPS only. Like the CXF backend (which never implemented Kerberos message encryption over
+ *
+ * HTTPS only. Like the CXF backend (which never implemented Kerberos message encryption over
* HTTP), the SOAP travels plaintext inside TLS, so {@link #wrap}/{@link #unwrap} are pass-throughs.
- *
- *
Realm and KDC resolution is left to the ambient Kerberos configuration (a {@code krb5.conf} or
+ *
+ * Realm and KDC resolution is left to the ambient Kerberos configuration (a {@code krb5.conf} or
* the {@code java.security.krb5.*} system properties), exactly as the CXF path did — the library
* sets none itself.
*/
@@ -69,11 +69,11 @@ final class KerberosAuthScheme implements AuthScheme {
/**
* @param servicePrincipalHost the host whose {@code HTTP/} SPN to target — must be the FQDN
- * the KDC knows (never an IP)
- * @param username the account name (without any {@code DOMAIN\} prefix)
- * @param password the account password (unused when {@code ticketCache} is set)
- * @param ticketCache a Kerberos credential cache to reuse, or {@code null} to log in with
- * the password
+ * the KDC knows (never an IP)
+ * @param username the account name (without any {@code DOMAIN\} prefix)
+ * @param password the account password (unused when {@code ticketCache} is set)
+ * @param ticketCache a Kerberos credential cache to reuse, or {@code null} to log in with
+ * the password
*/
KerberosAuthScheme(
final String servicePrincipalHost,
@@ -182,11 +182,11 @@ public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {
options.put("doNotPrompt", "false");
}
return new AppConfigurationEntry[] {
- new AppConfigurationEntry(
- "com.sun.security.auth.module.Krb5LoginModule",
- AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
- options
- )
+ new AppConfigurationEntry(
+ "com.sun.security.auth.module.Krb5LoginModule",
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ options
+ )
};
}
};
diff --git a/src/main/java/org/metricshub/winrm/light/LightTls.java b/src/main/java/org/metricshub/winrm/light/LightTls.java
index a42413e..5315687 100644
--- a/src/main/java/org/metricshub/winrm/light/LightTls.java
+++ b/src/main/java/org/metricshub/winrm/light/LightTls.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,8 +29,8 @@
/**
* TLS setup for the light backend's HTTPS transport.
- *
- * Unlike the legacy CXF path (which trusts every certificate), the light backend validates by
+ *
+ * Unlike the legacy CXF path (which trusts every certificate), the light backend validates by
* default: it uses the JDK default {@link SSLSocketFactory}, so the platform trust store (and any
* {@code -Djavax.net.ssl.trustStore}) applies and the server hostname is verified during the
* handshake. Setting the system property {@value #INSECURE_PROPERTY} to {@code true} opts out —
diff --git a/src/main/java/org/metricshub/winrm/light/LightWinRMService.java b/src/main/java/org/metricshub/winrm/light/LightWinRMService.java
index 7ced0fb..458f12c 100644
--- a/src/main/java/org/metricshub/winrm/light/LightWinRMService.java
+++ b/src/main/java/org/metricshub/winrm/light/LightWinRMService.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,8 +45,8 @@
* replacement for the CXF-based {@code WinRMService} that shipped before 2.0.0: same public
* behaviour, no Apache CXF / JAX-WS / JAXB stack, and immune by construction to JAXP
* {@code ServiceLoader} poisoning (it uses the JDK-default XML factories).
- *
- *
Supports NTLM over HTTP (with message encryption) and over HTTPS (plaintext SOAP inside TLS,
+ *
+ * Supports NTLM over HTTP (with message encryption) and over HTTPS (plaintext SOAP inside TLS,
* validating the server certificate by default; see {@link LightTls}), and Kerberos over HTTPS
* (SPNEGO via the JDK GSS-API; see {@link KerberosAuthScheme}). A multi-scheme request such as
* {@code [KERBEROS, NTLM]} is tried in order with fallback.
@@ -65,12 +65,12 @@ private LightWinRMService(final WinRMEndpoint winRMEndpoint, final WsmanClient c
/**
* Create a light WinRM executor.
*
- * @param winRMEndpoint endpoint with credentials (mandatory)
- * @param timeout timeout in milliseconds (must be > 0)
- * @param ticketCache Kerberos ticket cache path (used by the Kerberos scheme; {@code null} logs
- * in with the password)
+ * @param winRMEndpoint endpoint with credentials (mandatory)
+ * @param timeout timeout in milliseconds (must be > 0)
+ * @param ticketCache Kerberos ticket cache path (used by the Kerberos scheme; {@code null} logs
+ * in with the password)
* @param authentications requested authentication schemes, tried in order (NTLM and/or Kerberos);
- * {@code null}/empty means NTLM only
+ * {@code null}/empty means NTLM only
* @return a new {@code LightWinRMService}
* @throws WinRMException on invalid arguments or an unsupported authentication request
*/
@@ -148,8 +148,8 @@ private static AuthScheme resolveAuthScheme(
// e.g. Kerberos requested over plain HTTP with no other scheme to fall back to.
throw new WinRMException(
"Kerberos over WinRM requires HTTPS (endpoint was " +
- winRMEndpoint.getEndpoint() +
- "): there is no Kerberos message encryption over plain HTTP. Use HTTPS, or add NTLM to the authentication list."
+ winRMEndpoint.getEndpoint() +
+ "): there is no Kerberos message encryption over plain HTTP. Use HTTPS, or add NTLM to the authentication list."
);
}
return schemes.size() == 1 ? schemes.get(0) : new FallbackAuthScheme(schemes);
diff --git a/src/main/java/org/metricshub/winrm/light/MD4.java b/src/main/java/org/metricshub/winrm/light/MD4.java
index e323247..a1dd746 100644
--- a/src/main/java/org/metricshub/winrm/light/MD4.java
+++ b/src/main/java/org/metricshub/winrm/light/MD4.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
* Code correctness was verified by looking at MD4.java from the jcifs
* library (http://jcifs.samba.org). It was massaged extensively to the
* final form found here by Karl Wright (kwright@metacarta.com).
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
@@ -106,8 +105,7 @@ private void processBuffer() {
final int[] d = new int[16];
for (int i = 0; i < 16; i++) {
- d[i] =
- (dataBuffer[i * 4] & 0xff) +
+ d[i] = (dataBuffer[i * 4] & 0xff) +
((dataBuffer[i * 4 + 1] & 0xff) << 8) +
((dataBuffer[i * 4 + 2] & 0xff) << 16) +
((dataBuffer[i * 4 + 3] & 0xff) << 24);
diff --git a/src/main/java/org/metricshub/winrm/light/NTLMEngineUtils.java b/src/main/java/org/metricshub/winrm/light/NTLMEngineUtils.java
index 3eb5b5e..3d8d8da 100644
--- a/src/main/java/org/metricshub/winrm/light/NTLMEngineUtils.java
+++ b/src/main/java/org/metricshub/winrm/light/NTLMEngineUtils.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,13 +62,18 @@ static String convertDomain(final String domain) {
// http://msdn.microsoft.com/en-us/library/cc236650%28v=prot.20%29.aspx
// [MS-NLMP] section 2.2.2.5
static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested
- static final int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message.
+ static final int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE
+ // message.
static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key
- static final int FLAG_REQUEST_NTLM_V1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both
- static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL.
- static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security
+ static final int FLAG_REQUEST_NTLM_V1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE
+ // both
+ static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by
+ // REQUEST_SIGN and REQUEST_SEAL.
+ static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session
+ // security
static final int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version
- static final int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present
+ static final int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is
+ // present
static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange
static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange
static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL
@@ -88,6 +93,7 @@ static String convertDomain(final String domain) {
/**
* Find the character set based on the flags.
+ *
* @param flags is the flags.
* @return the character set.
*/
diff --git a/src/main/java/org/metricshub/winrm/light/NTLMMessage.java b/src/main/java/org/metricshub/winrm/light/NTLMMessage.java
index 10bdd54..b96f426 100644
--- a/src/main/java/org/metricshub/winrm/light/NTLMMessage.java
+++ b/src/main/java/org/metricshub/winrm/light/NTLMMessage.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
/**
* NTLM message generation, base class
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
@@ -83,21 +82,22 @@ static int readULong(final byte[] src, final int index) {
if (src.length < index + 4) {
return 0;
}
- return (
- (src[index] & 0xff) |
- ((src[index + 1] & 0xff) << 8) |
- ((src[index + 2] & 0xff) << 16) |
- ((src[index + 3] & 0xff) << 24)
- );
+ return ((src[index] & 0xff)
+ |
+ ((src[index + 1] & 0xff) << 8)
+ |
+ ((src[index + 2] & 0xff) << 16)
+ |
+ ((src[index + 3] & 0xff) << 24));
}
/**
* Prepares the object to create a response of the given length.
*
* @param maxlength
- * the maximum length of the response to prepare,
- * including the type and the signature (which this method
- * adds).
+ * the maximum length of the response to prepare,
+ * including the type and the signature (which this method
+ * adds).
*/
void prepareResponse(final int maxlength, final int messageType) {
messageContents = new byte[maxlength];
@@ -110,7 +110,7 @@ void prepareResponse(final int maxlength, final int messageType) {
* Adds the given byte to the response.
*
* @param b
- * the byte to add.
+ * the byte to add.
*/
private void addByte(final byte b) {
messageContents[currentOutputPosition] = b;
@@ -121,7 +121,7 @@ private void addByte(final byte b) {
* Adds the given bytes to the response.
*
* @param bytes
- * the bytes to add.
+ * the bytes to add.
*/
void addBytes(final byte[] bytes) {
if (bytes == null) {
diff --git a/src/main/java/org/metricshub/winrm/light/NtlmAuthScheme.java b/src/main/java/org/metricshub/winrm/light/NtlmAuthScheme.java
index a81ca80..1983677 100644
--- a/src/main/java/org/metricshub/winrm/light/NtlmAuthScheme.java
+++ b/src/main/java/org/metricshub/winrm/light/NtlmAuthScheme.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,9 +32,12 @@ final class NtlmAuthScheme implements AuthScheme {
// Type 1 flags over plain HTTP: engine defaults + SIGN | SEAL | KEY_EXCH (matches
// NtlmMasqAsSpnegoScheme). Message sealing is what protects the SOAP over an unencrypted transport.
- private static final int TYPE1_FLAGS_ENCRYPTED = (int) (Type1Message.getDefaultFlags() |
- NTLMEngineUtils.NTLMSSP_NEGOTIATE_SIGN |
- NTLMEngineUtils.NTLMSSP_NEGOTIATE_SEAL |
+ private static final int TYPE1_FLAGS_ENCRYPTED = (int) (Type1Message.getDefaultFlags()
+ |
+ NTLMEngineUtils.NTLMSSP_NEGOTIATE_SIGN
+ |
+ NTLMEngineUtils.NTLMSSP_NEGOTIATE_SEAL
+ |
NTLMEngineUtils.NTLMSSP_NEGOTIATE_KEY_EXCH);
// Type 1 flags over HTTPS: engine defaults only. TLS already provides confidentiality/integrity, so
diff --git a/src/main/java/org/metricshub/winrm/light/NtlmCrypto.java b/src/main/java/org/metricshub/winrm/light/NtlmCrypto.java
index f32c5ee..ba83041 100644
--- a/src/main/java/org/metricshub/winrm/light/NtlmCrypto.java
+++ b/src/main/java/org/metricshub/winrm/light/NtlmCrypto.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,8 +33,7 @@
*/
final class NtlmCrypto {
- static final String ENCRYPTED_CONTENT_TYPE =
- "multipart/encrypted;protocol=\"application/HTTP-SPNEGO-session-encrypted\";boundary=\"Encrypted Boundary\"";
+ static final String ENCRYPTED_CONTENT_TYPE = "multipart/encrypted;protocol=\"application/HTTP-SPNEGO-session-encrypted\";boundary=\"Encrypted Boundary\"";
private static final String BOUNDARY_CR = "--Encrypted Boundary\r\n";
private static final String BOUNDARY_END = "--Encrypted Boundary--\r\n";
@@ -94,9 +93,9 @@ private static void verify(final WinRMSession session, final byte[] unsealed, fi
if (!Arrays.equals(checksum, expectedChecksum)) {
throw new IllegalStateException(
"Checksum mismatch\n" +
- ByteArrayUtils.formatHexDump(checksum) +
- "--\n" +
- ByteArrayUtils.formatHexDump(expectedChecksum)
+ ByteArrayUtils.formatHexDump(checksum) +
+ "--\n" +
+ ByteArrayUtils.formatHexDump(expectedChecksum)
);
}
if (expectedSeqNum != seqNum) {
@@ -107,7 +106,7 @@ private static void verify(final WinRMSession session, final byte[] unsealed, fi
/**
* @param outgoing true to sign an outgoing message (client signing key + client sealing stream),
- * false to verify an incoming one (server signing key + server sealing stream).
+ * false to verify an incoming one (server signing key + server sealing stream).
*/
private static void calculateSignature(
final WinRMSession session,
@@ -182,7 +181,7 @@ void skipOver(final String s) {
void skipUntil(final String s) {
final byte[] expected = s.getBytes(StandardCharsets.US_ASCII);
int next = index;
- outer:while (true) {
+ outer: while (true) {
for (int i = 0; i < expected.length; i++) {
if (next + i >= bytes.length) {
throw new IllegalStateException("Encrypted-response framing terminated early looking for delimiter");
diff --git a/src/main/java/org/metricshub/winrm/light/NtlmException.java b/src/main/java/org/metricshub/winrm/light/NtlmException.java
index 5b15d10..e00cb04 100644
--- a/src/main/java/org/metricshub/winrm/light/NtlmException.java
+++ b/src/main/java/org/metricshub/winrm/light/NtlmException.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/src/main/java/org/metricshub/winrm/light/Type1Message.java b/src/main/java/org/metricshub/winrm/light/Type1Message.java
index cfa3115..e74f48d 100644
--- a/src/main/java/org/metricshub/winrm/light/Type1Message.java
+++ b/src/main/java/org/metricshub/winrm/light/Type1Message.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
/**
* Type 1 message assembly class
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
@@ -45,22 +44,26 @@ class Type1Message extends NTLMMessage {
final String unqualifiedDomain = NTLMEngineUtils.convertDomain(domain);
hostBytes = unqualifiedHost != null ? unqualifiedHost.getBytes(NTLMEngineUtils.UNICODE_LITTLE_UNMARKED) : null;
- domainBytes =
- unqualifiedDomain != null
- ? unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(NTLMEngineUtils.UNICODE_LITTLE_UNMARKED)
- : null;
+ domainBytes = unqualifiedDomain != null
+ ? unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(NTLMEngineUtils.UNICODE_LITTLE_UNMARKED)
+ : null;
}
static int getDefaultFlags() {
return ( // Required flags
- NTLMEngineUtils.FLAG_REQUEST_NTLM_V1 |
- NTLMEngineUtils.FLAG_REQUEST_NTLM2_SESSION |
- NTLMEngineUtils.FLAG_REQUEST_VERSION |
- NTLMEngineUtils.FLAG_REQUEST_ALWAYS_SIGN |
- NTLMEngineUtils.FLAG_REQUEST_128BIT_KEY_EXCH |
- NTLMEngineUtils.FLAG_REQUEST_56BIT_ENCRYPTION |
- NTLMEngineUtils.FLAG_REQUEST_UNICODE_ENCODING
- );
+ NTLMEngineUtils.FLAG_REQUEST_NTLM_V1
+ |
+ NTLMEngineUtils.FLAG_REQUEST_NTLM2_SESSION
+ |
+ NTLMEngineUtils.FLAG_REQUEST_VERSION
+ |
+ NTLMEngineUtils.FLAG_REQUEST_ALWAYS_SIGN
+ |
+ NTLMEngineUtils.FLAG_REQUEST_128BIT_KEY_EXCH
+ |
+ NTLMEngineUtils.FLAG_REQUEST_56BIT_ENCRYPTION
+ |
+ NTLMEngineUtils.FLAG_REQUEST_UNICODE_ENCODING);
}
/**
diff --git a/src/main/java/org/metricshub/winrm/light/Type2Message.java b/src/main/java/org/metricshub/winrm/light/Type2Message.java
index 904f8d1..5f069c3 100644
--- a/src/main/java/org/metricshub/winrm/light/Type2Message.java
+++ b/src/main/java/org/metricshub/winrm/light/Type2Message.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,6 @@
/**
* Type 2 message class
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
diff --git a/src/main/java/org/metricshub/winrm/light/Type3Message.java b/src/main/java/org/metricshub/winrm/light/Type3Message.java
index bcaca9c..0af4499 100644
--- a/src/main/java/org/metricshub/winrm/light/Type3Message.java
+++ b/src/main/java/org/metricshub/winrm/light/Type3Message.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,6 @@
/**
* Type 3 message assembly class
- *
* Code from io.cloudsoft.winrm4j.client.ntlm.forks.httpclient.NTLMEngineImpl
* release 0.12.3 @link https://github.com/cloudsoft/winrm4j
* io.cloudsoft.winrm4j.client.ntlm.forks.httpclient is a fork of apache-httpclient 4.5.13
@@ -56,7 +55,8 @@ public class Type3Message extends NTLMMessage {
private final byte[] sessionKey;
private final byte[] exportedSessionKey;
- /** More primitive constructor: don't include cert or previous messages.
+ /**
+ * More primitive constructor: don't include cert or previous messages.
*/
Type3Message(
final String domain,
@@ -85,7 +85,7 @@ public class Type3Message extends NTLMMessage {
byte[] responseTargetInformation = targetInformation;
- // Create a cipher generator class. Use domain BEFORE it gets modified!
+ // Create a cipher generator class. Use domain BEFORE it gets modified!
final CipherGen gen = new CipherGen(
random,
currentTime,
@@ -103,9 +103,9 @@ public class Type3Message extends NTLMMessage {
try {
// This conditional may not work on Windows Server 2008 R2 and above, where it has not yet
// been tested
- if (
- ((type2Flags & NTLMEngineUtils.FLAG_TARGETINFO_PRESENT) != 0) && targetInformation != null && target != null
- ) {
+ if (((type2Flags & NTLMEngineUtils.FLAG_TARGETINFO_PRESENT) != 0)
+ && targetInformation != null
+ && target != null) {
// NTLMv2
ntResp = gen.getNTLMv2Response();
lmResp = gen.getLMv2Response();
@@ -250,31 +250,26 @@ protected void buildMessage() {
// Flags.
addULong(
/*
- //FLAG_WORKSTATION_PRESENT |
- //FLAG_DOMAIN_PRESENT |
-
- // Required flags
- (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) |
- (type2Flags & FLAG_REQUEST_NTLMv1) |
- (type2Flags & FLAG_REQUEST_NTLM2_SESSION) |
-
- // Protocol version request
- FLAG_REQUEST_VERSION |
-
- // Recommended privacy settings
- (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) |
- (type2Flags & FLAG_REQUEST_SEAL) |
- (type2Flags & FLAG_REQUEST_SIGN) |
-
- // These must be set according to documentation, based on use of SEAL above
- (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) |
- (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) |
- (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) |
-
- (type2Flags & FLAG_TARGETINFO_PRESENT) |
- (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) |
- (type2Flags & FLAG_REQUEST_TARGET)
- */
+ * //FLAG_WORKSTATION_PRESENT |
+ * //FLAG_DOMAIN_PRESENT |
+ * // Required flags
+ * (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) |
+ * (type2Flags & FLAG_REQUEST_NTLMv1) |
+ * (type2Flags & FLAG_REQUEST_NTLM2_SESSION) |
+ * // Protocol version request
+ * FLAG_REQUEST_VERSION |
+ * // Recommended privacy settings
+ * (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) |
+ * (type2Flags & FLAG_REQUEST_SEAL) |
+ * (type2Flags & FLAG_REQUEST_SIGN) |
+ * // These must be set according to documentation, based on use of SEAL above
+ * (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) |
+ * (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) |
+ * (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) |
+ * (type2Flags & FLAG_TARGETINFO_PRESENT) |
+ * (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) |
+ * (type2Flags & FLAG_REQUEST_TARGET)
+ */
type2Flags
);
diff --git a/src/main/java/org/metricshub/winrm/light/WinRMSession.java b/src/main/java/org/metricshub/winrm/light/WinRMSession.java
index 6f61260..ab165a7 100644
--- a/src/main/java/org/metricshub/winrm/light/WinRMSession.java
+++ b/src/main/java/org/metricshub/winrm/light/WinRMSession.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,14 +35,14 @@ final class WinRMSession {
// Protocol-defined constants: they MUST encode to the same bytes on every JVM, so pin US-ASCII
// rather than relying on the platform default charset (which could differ, e.g. UTF-16).
- private static final byte[] CLIENT_SIGNING =
- "session key to client-to-server signing key magic constant\0".getBytes(StandardCharsets.US_ASCII);
- private static final byte[] SERVER_SIGNING =
- "session key to server-to-client signing key magic constant\0".getBytes(StandardCharsets.US_ASCII);
- private static final byte[] CLIENT_SEALING =
- "session key to client-to-server sealing key magic constant\0".getBytes(StandardCharsets.US_ASCII);
- private static final byte[] SERVER_SEALING =
- "session key to server-to-client sealing key magic constant\0".getBytes(StandardCharsets.US_ASCII);
+ private static final byte[] CLIENT_SIGNING = "session key to client-to-server signing key magic constant\0"
+ .getBytes(StandardCharsets.US_ASCII);
+ private static final byte[] SERVER_SIGNING = "session key to server-to-client signing key magic constant\0"
+ .getBytes(StandardCharsets.US_ASCII);
+ private static final byte[] CLIENT_SEALING = "session key to client-to-server sealing key magic constant\0"
+ .getBytes(StandardCharsets.US_ASCII);
+ private static final byte[] SERVER_SEALING = "session key to server-to-client sealing key magic constant\0"
+ .getBytes(StandardCharsets.US_ASCII);
private final String domain;
private final String workstation;
diff --git a/src/main/java/org/metricshub/winrm/light/WsmanClient.java b/src/main/java/org/metricshub/winrm/light/WsmanClient.java
index 3a8b399..587584a 100644
--- a/src/main/java/org/metricshub/winrm/light/WsmanClient.java
+++ b/src/main/java/org/metricshub/winrm/light/WsmanClient.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -350,10 +350,9 @@ private static String text(final Document doc, final String localName) {
* backend does.
*/
static boolean hasEnumerationElement(final Document doc, final String localName) {
- return (
- doc.getElementsByTagNameNS(WS_ENUMERATION_NS, localName).getLength() > 0 ||
- doc.getElementsByTagNameNS(WSMAN_NS, localName).getLength() > 0
- );
+ return (doc.getElementsByTagNameNS(WS_ENUMERATION_NS, localName).getLength() > 0
+ ||
+ doc.getElementsByTagNameNS(WSMAN_NS, localName).getLength() > 0);
}
/** First text content of an element matched by both namespace and local name. */
diff --git a/src/main/java/org/metricshub/winrm/service/WinRMEndpoint.java b/src/main/java/org/metricshub/winrm/service/WinRMEndpoint.java
index 81aa82f..e4d9b55 100644
--- a/src/main/java/org/metricshub/winrm/service/WinRMEndpoint.java
+++ b/src/main/java/org/metricshub/winrm/service/WinRMEndpoint.java
@@ -1,248 +1,247 @@
-package org.metricshub.winrm.service;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Objects;
-import org.metricshub.winrm.Utils;
-import org.metricshub.winrm.WinRMHttpProtocolEnum;
-import org.metricshub.winrm.WmiHelper;
-
-public class WinRMEndpoint {
-
- private static final int DEFAULT_WIN_RM_HTTP_PORT = 5985;
- private static final int DEFAULT_WIN_RM_HTTPS_PORT = 5986;
-
- private final String hostname;
- private final String endpoint;
- private final String domain;
- private final String username;
- private final char[] password;
- private final String namespace;
- private final String rawUsername;
- private final WinRMHttpProtocolEnum protocol;
- private final int port;
-
- /**
- * Constructor of the endpoint and credentials for WinRM.
- *
- * @param protocol The protocol
- * @param hostname The host name (mandatory)
- * @param port The port
- * @param username The user name (mandatory)
- * @param password The password (mandatory)
- * @param namespace The namespace default value: {@value WmiHelper#DEFAULT_NAMESPACE}
- */
- public WinRMEndpoint(
- final WinRMHttpProtocolEnum protocol,
- final String hostname,
- final Integer port,
- final String username,
- final char[] password,
- final String namespace
- ) {
- Utils.checkNonNull(hostname, "hostname");
- Utils.checkNonNull(username, "username");
- Utils.checkNonNull(password, "password");
-
- this.hostname = hostname.replaceAll("\\s", Utils.EMPTY);
- this.password = password;
- rawUsername = username;
-
- this.namespace = buildNamespace(namespace);
-
- final String user = username.replaceAll("\\s", Utils.EMPTY);
- if (user.contains("\\")) {
- final String[] array = user.split("\\\\");
- domain = array[0];
- this.username = array[1];
- } else {
- domain = null;
- this.username = user;
- }
-
- this.protocol = protocol != null ? protocol : WinRMHttpProtocolEnum.HTTP;
- this.port = getEndpointPort(this.protocol, port);
- final String endpointUrl = buildEndpointUrl(this.protocol, this.hostname, port);
-
- endpoint = buildWSManEndpoint(endpointUrl);
- }
-
- /** Get the hostname */
- public String getHostname() {
- return hostname;
- }
-
- /** Get the endpoint in the form of http(s)://host:port/wsman */
- public String getEndpoint() {
- return endpoint;
- }
-
- /** Get the domain from the raw username */
- public String getDomain() {
- return domain;
- }
-
- /** get the username as indicated in the constructor (could be in domain\\user form) */
- public String getRawUsername() {
- return rawUsername;
- }
-
- /** Get the username part of the raw username */
- public String getUsername() {
- return username;
- }
-
- /** Get the password */
- public char[] getPassword() {
- return password;
- }
-
- /** Get the namespace */
- public String getNamespace() {
- return namespace;
- }
-
- /** Get the protocol */
- public WinRMHttpProtocolEnum getProtocol() {
- return protocol;
- }
-
- /** Get the resolved endpoint port (the port provided to the constructor, or the protocol default). */
- public int getPort() {
- return port;
- }
-
- /**
- * Build the endpoint URL.
- *
- * @param protocol The HTTP protocol
- * @param hostname The host name
- * @param port The port
- *
- * @return the endpoint URL in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
- */
- public static String buildEndpointUrl(
- final WinRMHttpProtocolEnum protocol,
- final String hostname,
- final Integer port
- ) {
- final int endpointPort = getEndpointPort(protocol, port);
-
- return String.format("%s://%s:%d", protocol.toString(), hostname, endpointPort);
- }
-
- /**
- * Get the endpoint port:
- *
- * - The port if provided
- * - 5986 if the protocol is HTTPS
- * - 5985 otherwise
- *
- * @param protocol The HTTP protocol
- * @param port The port
- *
- * @return The endpoint port
- */
- public static int getEndpointPort(final WinRMHttpProtocolEnum protocol, final Integer port) {
- if (port != null) {
- return port;
- }
- return protocol == WinRMHttpProtocolEnum.HTTPS ? DEFAULT_WIN_RM_HTTPS_PORT : DEFAULT_WIN_RM_HTTP_PORT;
- }
-
- /**
- * Get the namespace and replace '\' by '/' if necessary
- * default: {@value WmiHelper#DEFAULT_NAMESPACE} if null
- * @param namespace the provided namespace
- *
- * @return
- */
- public static String buildNamespace(final String namespace) {
- final String cleanNamespace = namespace != null ? namespace.replaceAll("\\s", Utils.EMPTY) : Utils.EMPTY;
-
- final String usedNamespace = Utils.isNotBlank(cleanNamespace) ? cleanNamespace : WmiHelper.DEFAULT_NAMESPACE;
-
- return usedNamespace.replace('\\', '/');
- }
-
- /**
- * Build the WSMan URL endpoint.
- *
- * @param endpoint the endpoint in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
- *
- * @return The external form of the endpoint URL
- */
- private static String buildWSManEndpoint(final String endpoint) {
- try {
- return new URL(String.format("%s/wsman", endpoint)).toExternalForm();
- } catch (final MalformedURLException e) {
- throw new IllegalArgumentException(String.format("endpoint %s is invalid.", endpoint), e);
- }
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Arrays.hashCode(password);
- result = prime * result + Objects.hash(endpoint, namespace, rawUsername);
- return result;
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof WinRMEndpoint)) {
- return false;
- }
- final WinRMEndpoint other = (WinRMEndpoint) obj;
- return (
- Objects.equals(endpoint, other.endpoint) &&
- Objects.equals(namespace, other.namespace) &&
- Arrays.equals(password, other.password) &&
- Objects.equals(rawUsername, other.rawUsername)
- );
- }
-
- @Override
- public String toString() {
- return new StringBuilder()
- .append("WinRMEndpoint [")
- .append("endpoint=")
- .append(endpoint)
- .append(", domain=")
- .append(domain)
- .append(", username=")
- .append(username)
- .append(", namespace=")
- .append(namespace)
- .append("]")
- .toString();
- }
-}
+package org.metricshub.winrm.service;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Objects;
+import org.metricshub.winrm.Utils;
+import org.metricshub.winrm.WinRMHttpProtocolEnum;
+import org.metricshub.winrm.WmiHelper;
+
+public class WinRMEndpoint {
+
+ private static final int DEFAULT_WIN_RM_HTTP_PORT = 5985;
+ private static final int DEFAULT_WIN_RM_HTTPS_PORT = 5986;
+
+ private final String hostname;
+ private final String endpoint;
+ private final String domain;
+ private final String username;
+ private final char[] password;
+ private final String namespace;
+ private final String rawUsername;
+ private final WinRMHttpProtocolEnum protocol;
+ private final int port;
+
+ /**
+ * Constructor of the endpoint and credentials for WinRM.
+ *
+ * @param protocol The protocol
+ * @param hostname The host name (mandatory)
+ * @param port The port
+ * @param username The user name (mandatory)
+ * @param password The password (mandatory)
+ * @param namespace The namespace default value: {@value WmiHelper#DEFAULT_NAMESPACE}
+ */
+ public WinRMEndpoint(
+ final WinRMHttpProtocolEnum protocol,
+ final String hostname,
+ final Integer port,
+ final String username,
+ final char[] password,
+ final String namespace
+ ) {
+ Utils.checkNonNull(hostname, "hostname");
+ Utils.checkNonNull(username, "username");
+ Utils.checkNonNull(password, "password");
+
+ this.hostname = hostname.replaceAll("\\s", Utils.EMPTY);
+ this.password = password;
+ rawUsername = username;
+
+ this.namespace = buildNamespace(namespace);
+
+ final String user = username.replaceAll("\\s", Utils.EMPTY);
+ if (user.contains("\\")) {
+ final String[] array = user.split("\\\\");
+ domain = array[0];
+ this.username = array[1];
+ } else {
+ domain = null;
+ this.username = user;
+ }
+
+ this.protocol = protocol != null ? protocol : WinRMHttpProtocolEnum.HTTP;
+ this.port = getEndpointPort(this.protocol, port);
+ final String endpointUrl = buildEndpointUrl(this.protocol, this.hostname, port);
+
+ endpoint = buildWSManEndpoint(endpointUrl);
+ }
+
+ /** Get the hostname */
+ public String getHostname() {
+ return hostname;
+ }
+
+ /** Get the endpoint in the form of http(s)://host:port/wsman */
+ public String getEndpoint() {
+ return endpoint;
+ }
+
+ /** Get the domain from the raw username */
+ public String getDomain() {
+ return domain;
+ }
+
+ /** get the username as indicated in the constructor (could be in domain\\user form) */
+ public String getRawUsername() {
+ return rawUsername;
+ }
+
+ /** Get the username part of the raw username */
+ public String getUsername() {
+ return username;
+ }
+
+ /** Get the password */
+ public char[] getPassword() {
+ return password;
+ }
+
+ /** Get the namespace */
+ public String getNamespace() {
+ return namespace;
+ }
+
+ /** Get the protocol */
+ public WinRMHttpProtocolEnum getProtocol() {
+ return protocol;
+ }
+
+ /** Get the resolved endpoint port (the port provided to the constructor, or the protocol default). */
+ public int getPort() {
+ return port;
+ }
+
+ /**
+ * Build the endpoint URL.
+ *
+ * @param protocol The HTTP protocol
+ * @param hostname The host name
+ * @param port The port
+ * @return the endpoint URL in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
+ */
+ public static String buildEndpointUrl(
+ final WinRMHttpProtocolEnum protocol,
+ final String hostname,
+ final Integer port
+ ) {
+ final int endpointPort = getEndpointPort(protocol, port);
+
+ return String.format("%s://%s:%d", protocol.toString(), hostname, endpointPort);
+ }
+
+ /**
+ * Get the endpoint port:
+ *
+ * - The port if provided
+ * - 5986 if the protocol is HTTPS
+ * - 5985 otherwise
+ *
+ *
+ * @param protocol The HTTP protocol
+ * @param port The port
+ * @return The endpoint port
+ */
+ public static int getEndpointPort(final WinRMHttpProtocolEnum protocol, final Integer port) {
+ if (port != null) {
+ return port;
+ }
+ return protocol == WinRMHttpProtocolEnum.HTTPS ? DEFAULT_WIN_RM_HTTPS_PORT : DEFAULT_WIN_RM_HTTP_PORT;
+ }
+
+ /**
+ * Get the namespace and replace '\' by '/' if necessary
+ * default: {@value WmiHelper#DEFAULT_NAMESPACE} if null
+ *
+ * @param namespace the provided namespace
+ * @return
+ */
+ public static String buildNamespace(final String namespace) {
+ final String cleanNamespace = namespace != null ? namespace.replaceAll("\\s", Utils.EMPTY) : Utils.EMPTY;
+
+ final String usedNamespace = Utils.isNotBlank(cleanNamespace) ? cleanNamespace : WmiHelper.DEFAULT_NAMESPACE;
+
+ return usedNamespace.replace('\\', '/');
+ }
+
+ /**
+ * Build the WSMan URL endpoint.
+ *
+ * @param endpoint the endpoint in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
+ * @return The external form of the endpoint URL
+ */
+ private static String buildWSManEndpoint(final String endpoint) {
+ try {
+ return new URL(String.format("%s/wsman", endpoint)).toExternalForm();
+ } catch (final MalformedURLException e) {
+ throw new IllegalArgumentException(String.format("endpoint %s is invalid.", endpoint), e);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + Arrays.hashCode(password);
+ result = prime * result + Objects.hash(endpoint, namespace, rawUsername);
+ return result;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof WinRMEndpoint)) {
+ return false;
+ }
+ final WinRMEndpoint other = (WinRMEndpoint) obj;
+ return (Objects.equals(endpoint, other.endpoint)
+ &&
+ Objects.equals(namespace, other.namespace)
+ &&
+ Arrays.equals(password, other.password)
+ &&
+ Objects.equals(rawUsername, other.rawUsername));
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder()
+ .append("WinRMEndpoint [")
+ .append("endpoint=")
+ .append(endpoint)
+ .append(", domain=")
+ .append(domain)
+ .append(", username=")
+ .append(username)
+ .append(", namespace=")
+ .append(namespace)
+ .append("]")
+ .toString();
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/service/WinRMExecutorFactory.java b/src/main/java/org/metricshub/winrm/service/WinRMExecutorFactory.java
index d63f227..3639be6 100644
--- a/src/main/java/org/metricshub/winrm/service/WinRMExecutorFactory.java
+++ b/src/main/java/org/metricshub/winrm/service/WinRMExecutorFactory.java
@@ -4,7 +4,7 @@
* ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
* WinRM Java Client
* ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
+ * Copyright (C) 2023 - 2026 MetricsHub
* ჻჻჻჻჻჻
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,13 +47,13 @@ private WinRMExecutorFactory() {}
/**
* Create a {@link WindowsRemoteExecutor} (light backend).
*
- * @param winRMEndpoint endpoint with credentials (mandatory)
- * @param timeout timeout in milliseconds (must be > 0)
- * @param ticketCache Kerberos ticket cache path (may be {@code null})
+ * @param winRMEndpoint endpoint with credentials (mandatory)
+ * @param timeout timeout in milliseconds (must be > 0)
+ * @param ticketCache Kerberos ticket cache path (may be {@code null})
* @param authentications requested authentication schemes (may be {@code null})
* @return a light-backed executor
* @throws WinRMException for any problem creating the executor, or when {@value #BACKEND_PROPERTY}
- * requests the removed CXF backend or an unknown value
+ * requests the removed CXF backend or an unknown value
*/
public static WindowsRemoteExecutor createInstance(
final WinRMEndpoint winRMEndpoint,
@@ -70,8 +70,8 @@ public static WindowsRemoteExecutor createInstance(
// switched to another implementation.
throw new WinRMException(
"The CXF WinRM backend was removed in winrm-java 2.0.0; remove the " +
- BACKEND_PROPERTY +
- " system property to use the light backend (or stay on winrm-java 1.x)."
+ BACKEND_PROPERTY +
+ " system property to use the light backend (or stay on winrm-java 1.x)."
);
}
throw new WinRMException(
diff --git a/src/main/java/org/metricshub/winrm/service/client/auth/AuthenticationEnum.java b/src/main/java/org/metricshub/winrm/service/client/auth/AuthenticationEnum.java
index c1a5533..51b63e3 100644
--- a/src/main/java/org/metricshub/winrm/service/client/auth/AuthenticationEnum.java
+++ b/src/main/java/org/metricshub/winrm/service/client/auth/AuthenticationEnum.java
@@ -1,47 +1,46 @@
-package org.metricshub.winrm.service.client.auth;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import java.util.Map;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-public enum AuthenticationEnum {
- NTLM,
- KERBEROS;
-
- private static final Map VALUES_OF = Stream
- .of(values())
- .collect(Collectors.toMap(AuthenticationEnum::name, Function.identity()));
-
- /**
- * Get the value of the enum Name regardless the cardinality.
- *
- * @param name The enum value name
- *
- * @return An optional with the enum value if found empty otherwise
- */
- public static Optional getValueOf(final String name) {
- return name != null ? Optional.ofNullable(VALUES_OF.get(name.trim().toUpperCase())) : Optional.empty();
- }
-}
+package org.metricshub.winrm.service.client.auth;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public enum AuthenticationEnum {
+ NTLM,
+ KERBEROS;
+
+ private static final Map VALUES_OF = Stream
+ .of(values())
+ .collect(Collectors.toMap(AuthenticationEnum::name, Function.identity()));
+
+ /**
+ * Get the value of the enum Name regardless the cardinality.
+ *
+ * @param name The enum value name
+ * @return An optional with the enum value if found empty otherwise
+ */
+ public static Optional getValueOf(final String name) {
+ return name != null ? Optional.ofNullable(VALUES_OF.get(name.trim().toUpperCase())) : Optional.empty();
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/shares/SmbTempShare.java b/src/main/java/org/metricshub/winrm/shares/SmbTempShare.java
index ee153ef..4327db5 100644
--- a/src/main/java/org/metricshub/winrm/shares/SmbTempShare.java
+++ b/src/main/java/org/metricshub/winrm/shares/SmbTempShare.java
@@ -1,318 +1,314 @@
-package org.metricshub.winrm.shares;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2024 Metricshub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import com.hierynomus.security.bc.BCSecurityProvider;
-import com.hierynomus.smbj.SMBClient;
-import com.hierynomus.smbj.SmbConfig;
-import com.hierynomus.smbj.auth.AuthenticationContext;
-import com.hierynomus.smbj.connection.Connection;
-import com.hierynomus.smbj.session.Session;
-import com.hierynomus.smbj.share.DiskShare;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.metricshub.winrm.Utils;
-import org.metricshub.winrm.WindowsRemoteExecutor;
-import org.metricshub.winrm.WindowsTempShare;
-import org.metricshub.winrm.exceptions.WinRMException;
-import org.metricshub.winrm.exceptions.WindowsRemoteException;
-import org.metricshub.winrm.service.WinRMEndpoint;
-import org.metricshub.winrm.service.WinRMExecutorFactory;
-import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
-
-public class SmbTempShare extends WindowsTempShare implements AutoCloseable {
-
- private final WinRMEndpoint winRMEndpoint;
- private final SMBClient smbClient;
- private final Connection connection;
- private final Session session;
- private final DiskShare diskShare;
-
- /**
- * The SmbTempShare constructor.
- *
- * @param windowsRemoteExecutor WinRM executor (CXF or light backend)
- * @param winRMEndpoint Endpoint with credentials
- * @param smbClient The SMB client
- * @param connection The SMB connection
- * @param session The SMB session
- * @param diskShare The SMB disk share
- * @param shareNameOrUnc The name of the share, or its full UNC path
- * @param remotePath The path on the remote system of the directory being shared
- */
- private SmbTempShare(
- final WindowsRemoteExecutor windowsRemoteExecutor,
- final WinRMEndpoint winRMEndpoint,
- final SMBClient smbClient,
- final Connection connection,
- final Session session,
- final DiskShare diskShare,
- final String shareNameOrUnc,
- final String remotePath
- ) {
- super(windowsRemoteExecutor, shareNameOrUnc, remotePath);
- this.winRMEndpoint = winRMEndpoint;
- this.smbClient = smbClient;
- this.connection = connection;
- this.session = session;
- this.diskShare = diskShare;
- }
-
- private static final ConcurrentHashMap CONNECTIONS_CACHE = new ConcurrentHashMap<>();
-
- private final AtomicInteger useCount = new AtomicInteger(1);
-
- /**
- * Create a SmbTempShare instance.
- * Get or create a temp share and connect to it with SMB.
- *
- * @param winRMEndpoint Endpoint with credentials (mandatory)
- * @param timeout Timeout in milliseconds (throws an IllegalArgumentException if negative or zero)
- * @param ticketCache The Ticket Cache path
- * @param authentications List of authentications. only NTLM if absent
- *
- * @return SmbTempShare instance
- *
- * @throws IOException If an I/O error occurred
- * @throws WinRMException For any problem encountered
- * @throws TimeoutException To notify userName of timeout.
- */
- public static SmbTempShare createInstance(
- final WinRMEndpoint winRMEndpoint,
- final long timeout,
- final Path ticketCache,
- final List authentications
- ) throws IOException, WinRMException, TimeoutException {
- Utils.checkNonNull(winRMEndpoint, "winRMEndpoint");
- Utils.checkNonNull(winRMEndpoint.getPassword(), "password");
- Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
-
- try {
- return CONNECTIONS_CACHE.compute(
- winRMEndpoint,
- (key, smb) -> {
- if (smb == null) {
- WindowsRemoteExecutor windowsRemoteExecutor = null;
- SMBClient smbClient = null;
- Connection connection = null;
- Session session = null;
- DiskShare diskShare = null;
-
- try {
- // Honour the backend toggle: SMB file transfer is always smbj, but the WinRM command
- // orchestration follows the selected backend (so "light" does not fall back to CXF).
- windowsRemoteExecutor =
- WinRMExecutorFactory.createInstance(winRMEndpoint, timeout, ticketCache, authentications);
-
- final WindowsTempShare windowsTempShare = getOrCreateShare(
- windowsRemoteExecutor,
- timeout,
- (w, r, s, t) -> {
- try {
- shareRemoteDirectory(w, r, s, t);
- } catch (final TimeoutException | WindowsRemoteException e) {
- throw new RuntimeException(e);
- }
- }
- );
-
- final SmbConfig smbConfig = SmbConfig
- .builder()
- .withSecurityProvider(new BCSecurityProvider())
- .withTimeout(timeout, TimeUnit.SECONDS)
- .build();
-
- final AuthenticationContext authenticationContext = new AuthenticationContext(
- winRMEndpoint.getUsername(),
- winRMEndpoint.getPassword(),
- winRMEndpoint.getDomain()
- );
-
- smbClient = createSmbClient(smbConfig);
- connection = smbClient.connect(winRMEndpoint.getHostname());
- session = connection.authenticate(authenticationContext);
- diskShare = (DiskShare) session.connectShare(windowsTempShare.getShareName());
-
- return new SmbTempShare(
- windowsRemoteExecutor,
- winRMEndpoint,
- smbClient,
- connection,
- session,
- diskShare,
- windowsTempShare.getUncSharePath(),
- windowsTempShare.getRemotePath()
- );
- } catch (final RuntimeException e) {
- closeResources(windowsRemoteExecutor, smbClient, connection, session, diskShare);
-
- throw e;
- } catch (final Exception e) {
- closeResources(windowsRemoteExecutor, smbClient, connection, session, diskShare);
-
- throw new RuntimeException(e);
- }
- } else {
- synchronized (smb) {
- smb.incrementUseCount();
-
- return smb;
- }
- }
- }
- );
- } catch (final RuntimeException e) {
- final Throwable cause = e.getCause();
-
- if (cause instanceof IOException) {
- throw (IOException) cause;
- }
-
- if (cause instanceof TimeoutException) {
- throw (TimeoutException) cause;
- }
-
- if (cause instanceof WindowsRemoteException) {
- throw (WinRMException) cause;
- }
-
- throw e;
- }
- }
-
- private static void closeResources(
- final WindowsRemoteExecutor windowsRemoteExecutor,
- final SMBClient smbClient,
- final Connection connection,
- final Session session,
- final DiskShare diskShare
- ) {
- try {
- if (diskShare != null) {
- diskShare.close();
- }
-
- if (session != null) {
- session.close();
- }
-
- if (connection != null) {
- connection.close();
- }
- } catch (final IOException ioe) {
- throw new RuntimeException(ioe);
- }
-
- if (smbClient != null) {
- smbClient.close();
- }
-
- if (windowsRemoteExecutor != null) {
- windowsRemoteExecutor.close();
- }
- }
-
- int getUseCount() {
- return useCount.get();
- }
-
- void incrementUseCount() {
- useCount.incrementAndGet();
- }
-
- /**
- * @return whether this WbemServices instance is connected and usable
- */
- boolean isConnected() {
- return getUseCount() > 0;
- }
-
- /**
- * Check if it's connected. If not, throw an IllegalStateException.
- */
- public void checkConnectedFirst() {
- if (!isConnected()) {
- throw new IllegalStateException("This instance has been closed and a new one must be created.");
- }
- }
-
- @Override
- public synchronized void close() throws IOException {
- if (useCount.decrementAndGet() == 0) {
- CONNECTIONS_CACHE.remove(winRMEndpoint);
-
- if (diskShare != null) {
- diskShare.close();
- }
-
- if (session != null) {
- session.close();
- }
-
- if (connection != null) {
- connection.close();
- }
-
- if (smbClient != null) {
- smbClient.close();
- }
-
- getWindowsRemoteExecutor().close();
- }
- }
-
- /**
- * Share the remote directory on the host.
- *
- * @param windowsRemoteExecutor WinRM executor (CXF or light backend).
- * @param remotePath The remote path.
- * @param shareName The Share Name.
- * @param timeout Timeout in milliseconds.
- *
- * @throws TimeoutException To notify userName of timeout.
- * @throws WindowsRemoteException For any problem encountered
- *
- */
- private static void shareRemoteDirectory(
- final WindowsRemoteExecutor windowsRemoteExecutor,
- final String remotePath,
- final String shareName,
- final long timeout
- ) throws TimeoutException, WindowsRemoteException {
- final String command = String.format(
- "net share %s=%s /grant:%s,Full",
- shareName,
- remotePath,
- windowsRemoteExecutor.getUsername()
- );
-
- windowsRemoteExecutor.executeCommand(command, null, null, timeout);
- }
-
- static SMBClient createSmbClient(final SmbConfig smbConfig) {
- return new SMBClient(smbConfig);
- }
-}
+package org.metricshub.winrm.shares;
+
+/*-
+ * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
+ * WinRM Java Client
+ * ჻჻჻჻჻჻
+ * Copyright 2023 - 2026 MetricsHub
+ * ჻჻჻჻჻჻
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
+ */
+
+import com.hierynomus.security.bc.BCSecurityProvider;
+import com.hierynomus.smbj.SMBClient;
+import com.hierynomus.smbj.SmbConfig;
+import com.hierynomus.smbj.auth.AuthenticationContext;
+import com.hierynomus.smbj.connection.Connection;
+import com.hierynomus.smbj.session.Session;
+import com.hierynomus.smbj.share.DiskShare;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.metricshub.winrm.Utils;
+import org.metricshub.winrm.WindowsRemoteExecutor;
+import org.metricshub.winrm.WindowsTempShare;
+import org.metricshub.winrm.exceptions.WinRMException;
+import org.metricshub.winrm.exceptions.WindowsRemoteException;
+import org.metricshub.winrm.service.WinRMEndpoint;
+import org.metricshub.winrm.service.WinRMExecutorFactory;
+import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
+
+public class SmbTempShare extends WindowsTempShare implements AutoCloseable {
+
+ private final WinRMEndpoint winRMEndpoint;
+ private final SMBClient smbClient;
+ private final Connection connection;
+ private final Session session;
+ private final DiskShare diskShare;
+
+ /**
+ * The SmbTempShare constructor.
+ *
+ * @param windowsRemoteExecutor WinRM executor (CXF or light backend)
+ * @param winRMEndpoint Endpoint with credentials
+ * @param smbClient The SMB client
+ * @param connection The SMB connection
+ * @param session The SMB session
+ * @param diskShare The SMB disk share
+ * @param shareNameOrUnc The name of the share, or its full UNC path
+ * @param remotePath The path on the remote system of the directory being shared
+ */
+ private SmbTempShare(
+ final WindowsRemoteExecutor windowsRemoteExecutor,
+ final WinRMEndpoint winRMEndpoint,
+ final SMBClient smbClient,
+ final Connection connection,
+ final Session session,
+ final DiskShare diskShare,
+ final String shareNameOrUnc,
+ final String remotePath
+ ) {
+ super(windowsRemoteExecutor, shareNameOrUnc, remotePath);
+ this.winRMEndpoint = winRMEndpoint;
+ this.smbClient = smbClient;
+ this.connection = connection;
+ this.session = session;
+ this.diskShare = diskShare;
+ }
+
+ private static final ConcurrentHashMap CONNECTIONS_CACHE = new ConcurrentHashMap<>();
+
+ private final AtomicInteger useCount = new AtomicInteger(1);
+
+ /**
+ * Create a SmbTempShare instance.
+ * Get or create a temp share and connect to it with SMB.
+ *
+ * @param winRMEndpoint Endpoint with credentials (mandatory)
+ * @param timeout Timeout in milliseconds (throws an IllegalArgumentException if negative or zero)
+ * @param ticketCache The Ticket Cache path
+ * @param authentications List of authentications. only NTLM if absent
+ * @return SmbTempShare instance
+ * @throws IOException If an I/O error occurred
+ * @throws WinRMException For any problem encountered
+ * @throws TimeoutException To notify userName of timeout.
+ */
+ public static SmbTempShare createInstance(
+ final WinRMEndpoint winRMEndpoint,
+ final long timeout,
+ final Path ticketCache,
+ final List authentications
+ ) throws IOException, WinRMException, TimeoutException {
+ Utils.checkNonNull(winRMEndpoint, "winRMEndpoint");
+ Utils.checkNonNull(winRMEndpoint.getPassword(), "password");
+ Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
+
+ try {
+ return CONNECTIONS_CACHE.compute(
+ winRMEndpoint,
+ (key, smb) -> {
+ if (smb == null) {
+ WindowsRemoteExecutor windowsRemoteExecutor = null;
+ SMBClient smbClient = null;
+ Connection connection = null;
+ Session session = null;
+ DiskShare diskShare = null;
+
+ try {
+ // Honour the backend toggle: SMB file transfer is always smbj, but the WinRM command
+ // orchestration follows the selected backend (so "light" does not fall back to CXF).
+ windowsRemoteExecutor = WinRMExecutorFactory
+ .createInstance(winRMEndpoint, timeout, ticketCache, authentications);
+
+ final WindowsTempShare windowsTempShare = getOrCreateShare(
+ windowsRemoteExecutor,
+ timeout,
+ (w, r, s, t) -> {
+ try {
+ shareRemoteDirectory(w, r, s, t);
+ } catch (final TimeoutException | WindowsRemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ );
+
+ final SmbConfig smbConfig = SmbConfig
+ .builder()
+ .withSecurityProvider(new BCSecurityProvider())
+ .withTimeout(timeout, TimeUnit.SECONDS)
+ .build();
+
+ final AuthenticationContext authenticationContext = new AuthenticationContext(
+ winRMEndpoint.getUsername(),
+ winRMEndpoint.getPassword(),
+ winRMEndpoint.getDomain()
+ );
+
+ smbClient = createSmbClient(smbConfig);
+ connection = smbClient.connect(winRMEndpoint.getHostname());
+ session = connection.authenticate(authenticationContext);
+ diskShare = (DiskShare) session.connectShare(windowsTempShare.getShareName());
+
+ return new SmbTempShare(
+ windowsRemoteExecutor,
+ winRMEndpoint,
+ smbClient,
+ connection,
+ session,
+ diskShare,
+ windowsTempShare.getUncSharePath(),
+ windowsTempShare.getRemotePath()
+ );
+ } catch (final RuntimeException e) {
+ closeResources(windowsRemoteExecutor, smbClient, connection, session, diskShare);
+
+ throw e;
+ } catch (final Exception e) {
+ closeResources(windowsRemoteExecutor, smbClient, connection, session, diskShare);
+
+ throw new RuntimeException(e);
+ }
+ } else {
+ synchronized (smb) {
+ smb.incrementUseCount();
+
+ return smb;
+ }
+ }
+ }
+ );
+ } catch (final RuntimeException e) {
+ final Throwable cause = e.getCause();
+
+ if (cause instanceof IOException) {
+ throw (IOException) cause;
+ }
+
+ if (cause instanceof TimeoutException) {
+ throw (TimeoutException) cause;
+ }
+
+ if (cause instanceof WindowsRemoteException) {
+ throw (WinRMException) cause;
+ }
+
+ throw e;
+ }
+ }
+
+ private static void closeResources(
+ final WindowsRemoteExecutor windowsRemoteExecutor,
+ final SMBClient smbClient,
+ final Connection connection,
+ final Session session,
+ final DiskShare diskShare
+ ) {
+ try {
+ if (diskShare != null) {
+ diskShare.close();
+ }
+
+ if (session != null) {
+ session.close();
+ }
+
+ if (connection != null) {
+ connection.close();
+ }
+ } catch (final IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ if (smbClient != null) {
+ smbClient.close();
+ }
+
+ if (windowsRemoteExecutor != null) {
+ windowsRemoteExecutor.close();
+ }
+ }
+
+ int getUseCount() {
+ return useCount.get();
+ }
+
+ void incrementUseCount() {
+ useCount.incrementAndGet();
+ }
+
+ /**
+ * @return whether this WbemServices instance is connected and usable
+ */
+ boolean isConnected() {
+ return getUseCount() > 0;
+ }
+
+ /**
+ * Check if it's connected. If not, throw an IllegalStateException.
+ */
+ public void checkConnectedFirst() {
+ if (!isConnected()) {
+ throw new IllegalStateException("This instance has been closed and a new one must be created.");
+ }
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (useCount.decrementAndGet() == 0) {
+ CONNECTIONS_CACHE.remove(winRMEndpoint);
+
+ if (diskShare != null) {
+ diskShare.close();
+ }
+
+ if (session != null) {
+ session.close();
+ }
+
+ if (connection != null) {
+ connection.close();
+ }
+
+ if (smbClient != null) {
+ smbClient.close();
+ }
+
+ getWindowsRemoteExecutor().close();
+ }
+ }
+
+ /**
+ * Share the remote directory on the host.
+ *
+ * @param windowsRemoteExecutor WinRM executor (CXF or light backend).
+ * @param remotePath The remote path.
+ * @param shareName The Share Name.
+ * @param timeout Timeout in milliseconds.
+ * @throws TimeoutException To notify userName of timeout.
+ * @throws WindowsRemoteException For any problem encountered
+ */
+ private static void shareRemoteDirectory(
+ final WindowsRemoteExecutor windowsRemoteExecutor,
+ final String remotePath,
+ final String shareName,
+ final long timeout
+ ) throws TimeoutException, WindowsRemoteException {
+ final String command = String.format(
+ "net share %s=%s /grant:%s,Full",
+ shareName,
+ remotePath,
+ windowsRemoteExecutor.getUsername()
+ );
+
+ windowsRemoteExecutor.executeCommand(command, null, null, timeout);
+ }
+
+ static SMBClient createSmbClient(final SmbConfig smbConfig) {
+ return new SMBClient(smbConfig);
+ }
+}
diff --git a/src/main/java/org/metricshub/winrm/wql/WinRMWqlExecutor.java b/src/main/java/org/metricshub/winrm/wql/WinRMWqlExecutor.java
index e16e8e3..f2f9896 100644
--- a/src/main/java/org/metricshub/winrm/wql/WinRMWqlExecutor.java
+++ b/src/main/java/org/metricshub/winrm/wql/WinRMWqlExecutor.java
@@ -1,148 +1,148 @@
-package org.metricshub.winrm.wql;
-
-/*-
- * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
- * WinRM Java Client
- * ჻჻჻჻჻჻
- * Copyright 2023 - 2026 MetricsHub
- * ჻჻჻჻჻჻
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
- */
-
-import java.nio.file.Path;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeoutException;
-import java.util.stream.Collectors;
-import org.metricshub.winrm.Utils;
-import org.metricshub.winrm.WinRMHttpProtocolEnum;
-import org.metricshub.winrm.WindowsRemoteExecutor;
-import org.metricshub.winrm.WmiHelper;
-import org.metricshub.winrm.exceptions.WinRMException;
-import org.metricshub.winrm.exceptions.WindowsRemoteException;
-import org.metricshub.winrm.exceptions.WqlQuerySyntaxException;
-import org.metricshub.winrm.service.WinRMEndpoint;
-import org.metricshub.winrm.service.WinRMExecutorFactory;
-import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
-
-public class WinRMWqlExecutor {
-
- private final long executionTime;
- private final List headers;
- private final List> rows;
-
- /**
- * The WinRMWqlExecutor constructor
- *
- * @param executionTime The execution time in milliseconds
- * @param headers The headers list
- * @param rows The value rows list
- */
- public WinRMWqlExecutor(final long executionTime, final List headers, final List> rows) {
- this.executionTime = executionTime;
- this.headers = headers;
- this.rows = rows;
- }
-
- /**
- * Get the execution time of the query.
- * @return
- */
- public long getExecutionTime() {
- return executionTime;
- }
-
- /**
- * Get the headers of the query.
- * @return
- */
- public List getHeaders() {
- return headers;
- }
-
- /**
- * Get the result rows of the query.
- * @return
- */
- public List> getRows() {
- return rows;
- }
-
- /**
- * Execute a WQL query and process its result.
- *
- * @param protocol The HTTP protocol (HTTP by default)
- * @param hostname Host to connect to. (Mandatory)
- * @param port The port (5985 for HTPP or 5986 for HTTPS by default)
- * @param username The username name. (Mandatory)
- * @param password The password
- * @param namespace The namespace default value: {@value WmiHelper#DEFAULT_NAMESPACE}
- * @param wqlQuery The WQL query (Mandatory)
- * @param timeout The timeout in milliseconds (throws an IllegalArgumentException if negative or zero)
- * @param ticketCache The Ticket Cache path
- * @param authentications List of authentications. only NTLM if absent
- *
- * @return WinRMWqlExecutor result instance with header, rows and execution time.
- *
- * @throws WinRMException For any problem encountered on remote
- * @throws WqlQuerySyntaxException On WQL syntax errors
- * @throws TimeoutException To notify userName of timeout
- */
- public static WinRMWqlExecutor executeWql(
- final WinRMHttpProtocolEnum protocol,
- final String hostname,
- final Integer port,
- final String username,
- final char[] password,
- final String namespace,
- final String wqlQuery,
- final long timeout,
- final Path ticketCache,
- final List authentications
- ) throws WinRMException, WqlQuerySyntaxException, TimeoutException {
- Utils.checkNonNull(wqlQuery, "wqlQuery");
- Utils.checkArgumentNotZeroOrNegative(timeout, "timeout");
-
- final long start = Utils.getCurrentTimeMillis();
-
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(protocol, hostname, port, username, password, namespace);
-
- try (
- final WindowsRemoteExecutor winRMService = WinRMExecutorFactory.createInstance(
- winRMEndpoint,
- timeout,
- ticketCache,
- authentications
- )
- ) {
- final List
"
);
assertTrue(WsmanClient.hasEnumerationElement(doc, "EndOfSequence"));
}
@@ -63,17 +63,17 @@ void wmiPropertyNamedEndOfSequenceIsNotMistakenForTheMarker() throws Exception {
// and must not terminate the enumeration.
final Document doc = parse(
"" +
- "" +
- "" +
- "" +
- "oops" +
- "" +
- "" +
- ""
+ "" +
+ "" +
+ "" +
+ "oops" +
+ "" +
+ "" +
+ ""
);
assertFalse(WsmanClient.hasEnumerationElement(doc, "EndOfSequence"));
}
@@ -83,32 +83,32 @@ void wmiPropertyNamedEndOfSequenceIsNotMistakenForTheMarker() throws Exception {
@Test
void itemsCollectedFromBothNamespaceVariants() throws Exception {
// EnumerateResponse carries wsen:Items, PullResponse carries wsman:Items; both must yield rows.
- final String instance =
- "" +
+ final String instance = ""
+ +
"Spooler" +
"Running" +
"";
final Document wsenItems = parse(
"" +
- "" +
- "" +
- instance +
- "" +
- ""
+ "" +
+ "" +
+ instance +
+ "" +
+ ""
);
final Document wsmanItems = parse(
"" +
- "" +
- "" +
- instance +
- "" +
- ""
+ "" +
+ "" +
+ instance +
+ "" +
+ ""
);
for (final Document doc : List.of(wsenItems, wsmanItems)) {
@@ -126,18 +126,18 @@ void wmiPropertyNamedItemsIsNotMistakenForTheWrapper() throws Exception {
// second Items wrapper producing phantom rows.
final Document doc = parse(
"" +
- "" +
- "" +
- "" +
- "real-row" +
- "phantom" +
- "" +
- "" +
- ""
+ "" +
+ "" +
+ "" +
+ "real-row" +
+ "phantom" +
+ "" +
+ "" +
+ ""
);
final List> rows = new ArrayList<>();
WsmanClient.collectItems(doc, rows);
@@ -153,14 +153,15 @@ void faultSummaryCarriesWsmanFaultDetailWithWbemMnemonic() throws Exception {
// matching WBEM_E_* in the exception message — the detail Message text must surface.
final Document doc = parse(
"" +
- "" +
- "The WS-Management service cannot process the request." +
- "" +
- "" +
- "The WMI service or the WMI provider returned an unknown error: WBEM_E_INVALID_CLASS" +
- "" +
- "" +
- ""
+ "" +
+ "The WS-Management service cannot process the request."
+ +
+ "" +
+ "" +
+ "The WMI service or the WMI provider returned an unknown error: WBEM_E_INVALID_CLASS" +
+ "" +
+ "" +
+ ""
);
final String summary = WsmanClient.faultSummary(500, doc);
assertTrue(summary.contains("HTTP 500"), summary);
@@ -175,18 +176,18 @@ void faultSummaryDoesNotDuplicateDetailAlreadyInReason() throws Exception {
final String message = "The WMI service or the WMI provider returned an unknown error: WBEM_E_INVALID_NAMESPACE";
final Document doc = parse(
"" +
- "" +
- "" +
- message +
- " " +
- "" +
- "" +
- "" +
- message +
- " " +
- "" +
- "" +
- ""
+ "" +
+ "" +
+ message +
+ " " +
+ "" +
+ "" +
+ "" +
+ message +
+ " " +
+ "" +
+ "" +
+ ""
);
final String summary = WsmanClient.faultSummary(500, doc);
final int first = summary.indexOf("WBEM_E_INVALID_NAMESPACE");
@@ -199,9 +200,9 @@ void faultSummaryDoesNotDuplicateDetailAlreadyInReason() throws Exception {
void faultSummaryWithoutWsmanFaultDetailStillReadable() throws Exception {
final Document doc = parse(
"" +
- "" +
- "Some transport-level failure" +
- ""
+ "" +
+ "Some transport-level failure" +
+ ""
);
assertEquals("HTTP 500: Some transport-level failure", WsmanClient.faultSummary(500, doc));
}
diff --git a/src/test/java/org/metricshub/winrm/light/WsmanProtocolTest.java b/src/test/java/org/metricshub/winrm/light/WsmanProtocolTest.java
index 3b236cb..9a275ba 100644
--- a/src/test/java/org/metricshub/winrm/light/WsmanProtocolTest.java
+++ b/src/test/java/org/metricshub/winrm/light/WsmanProtocolTest.java
@@ -70,41 +70,41 @@ void wqlPagesAcrossEnumerateAndPullsOverEncryptedNtlm() throws Exception {
200,
envelope(
"" +
- "uuid:CTX-1" +
- "" +
- service("Spooler", "Running") +
- "" +
- ""
+ WSEN +
+ "\" xmlns:wsman=\"" +
+ WSMAN +
+ "\">" +
+ "uuid:CTX-1" +
+ "" +
+ service("Spooler", "Running") +
+ "" +
+ ""
)
)
.enqueue(
200,
envelope(
"" +
- "uuid:CTX-2" +
- "" +
- service("WinRM", "Running") +
- service("Wecsvc", "Stopped") +
- "" +
- ""
+ WSEN +
+ "\">" +
+ "uuid:CTX-2" +
+ "" +
+ service("WinRM", "Running") +
+ service("Wecsvc", "Stopped") +
+ "" +
+ ""
)
)
.enqueue(
200,
envelope(
"" +
- "" +
- ""
+ WSEN +
+ "\" xmlns:wsman=\"" +
+ WSMAN +
+ "\">" +
+ "" +
+ ""
)
);
@@ -290,19 +290,16 @@ private static String envelope(final String body) {
}
private static String service(final String name, final String state) {
- return (
- "" +
+ return ("" +
"" +
name +
"" +
state +
- ""
- );
+ "");
}
private static String resourceCreated(final String shellId) {
- return (
- "" +
@@ -314,51 +311,42 @@ private static String resourceCreated(final String shellId) {
"" +
shellId +
"" +
- ""
- );
+ "");
}
private static String commandResponse(final String commandId) {
- return (
- "" +
commandId +
- ""
- );
+ "");
}
private static String receiveResponse(final String commandId, final String streams, final String commandState) {
- return (
- "" +
streams +
(commandState == null ? "" : commandState) +
- ""
- );
+ "");
}
private static String stream(final String name, final byte[] content) {
- return (
- "" +
Base64.getEncoder().encodeToString(content) +
- ""
- );
+ "");
}
private static String done(final String commandId, final int exitCode) {
- return (
- "" +
exitCode +
- ""
- );
+ "");
}
private static String fault(final String code, final String reason) {
@@ -366,8 +354,7 @@ private static String fault(final String code, final String reason) {
}
private static String fault(final String code, final String reason, final String detailMessage) {
- return (
- "" +
"s:Receiver" +
@@ -382,7 +369,6 @@ private static String fault(final String code, final String reason, final String
"" +
(detailMessage == null ? reason : detailMessage) +
"" +
- ""
- );
+ "");
}
}
diff --git a/src/test/java/org/metricshub/winrm/service/WinRMEndpointTest.java b/src/test/java/org/metricshub/winrm/service/WinRMEndpointTest.java
index 17122a1..80d913e 100644
--- a/src/test/java/org/metricshub/winrm/service/WinRMEndpointTest.java
+++ b/src/test/java/org/metricshub/winrm/service/WinRMEndpointTest.java
@@ -1,138 +1,138 @@
-package org.metricshub.winrm.service;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.metricshub.winrm.Utils.EMPTY;
-import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTP;
-import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
-import static org.metricshub.winrm.service.WinRMEndpoint.buildEndpointUrl;
-import static org.metricshub.winrm.service.WinRMEndpoint.buildNamespace;
-import static org.metricshub.winrm.service.WinRMEndpoint.getEndpointPort;
-
-import org.junit.jupiter.api.Test;
-
-class WinRMEndpointTest {
-
- private static final String HOSTNAME = "host";
- private static final int PORT = 443;
- private static final String USER = "user";
- private static final char[] PASSWORD = { 'p', 'a', 's', 's' };
-
- @Test
- void testWinRMEndpoint() {
- //check arguments
- assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, null, 5985, USER, PASSWORD, null));
-
- assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, HOSTNAME, 5985, null, PASSWORD, null));
-
- assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, HOSTNAME, 5985, USER, null, null));
-
- // Case user name in form of domain\\user
- {
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(
- null,
- " \t\r\n host \t\r\n ",
- null,
- " \t\r\n domain \t\r\n \\ \t\r\n user \t\r\n ",
- PASSWORD,
- null
- );
-
- assertEquals(HOSTNAME, winRMEndpoint.getHostname());
- assertEquals("http://host:5985/wsman", winRMEndpoint.getEndpoint());
- assertEquals("domain", winRMEndpoint.getDomain());
- assertEquals(USER, winRMEndpoint.getUsername());
- assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
- assertEquals("ROOT/CIMV2", winRMEndpoint.getNamespace());
- assertEquals(HTTP, winRMEndpoint.getProtocol());
- }
- {
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTPS, HOSTNAME, PORT, "domain\\user", PASSWORD, "root");
-
- assertEquals(HOSTNAME, winRMEndpoint.getHostname());
- assertEquals("https://host:443/wsman", winRMEndpoint.getEndpoint());
- assertEquals("domain", winRMEndpoint.getDomain());
- assertEquals(USER, winRMEndpoint.getUsername());
- assertEquals("root", winRMEndpoint.getNamespace());
- assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
- assertEquals(HTTPS, winRMEndpoint.getProtocol());
- }
-
- // Case user name without domain
- {
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(null, HOSTNAME, null, USER, PASSWORD, "root/cimv2");
-
- assertEquals(HOSTNAME, winRMEndpoint.getHostname());
- assertEquals("http://host:5985/wsman", winRMEndpoint.getEndpoint());
- assertNull(winRMEndpoint.getDomain());
- assertEquals(USER, winRMEndpoint.getUsername());
- assertEquals("root/cimv2", winRMEndpoint.getNamespace());
- assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
- assertEquals(HTTP, winRMEndpoint.getProtocol());
- }
- {
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTP, HOSTNAME, PORT, USER, PASSWORD, "SRV\\Microsoft");
-
- assertEquals(HOSTNAME, winRMEndpoint.getHostname());
- assertEquals("http://host:443/wsman", winRMEndpoint.getEndpoint());
- assertNull(winRMEndpoint.getDomain());
- assertEquals(USER, winRMEndpoint.getUsername());
- assertEquals("SRV/Microsoft", winRMEndpoint.getNamespace());
- assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
- assertEquals(HTTP, winRMEndpoint.getProtocol());
- }
- }
-
- @Test
- void testBuildEndpointUrl() {
- assertEquals("HTTP://host:5985", buildEndpointUrl(HTTP, HOSTNAME, null));
- assertEquals("HTTPS://host:5986", buildEndpointUrl(HTTPS, HOSTNAME, null));
- assertEquals("HTTP://host:443", buildEndpointUrl(HTTP, HOSTNAME, PORT));
- assertEquals("HTTPS://host:443", buildEndpointUrl(HTTPS, HOSTNAME, PORT));
- }
-
- @Test
- void testGetEndPointPort() {
- // case port provided
- assertEquals(PORT, getEndpointPort(null, PORT));
- assertEquals(PORT, getEndpointPort(HTTPS, PORT));
- assertEquals(PORT, getEndpointPort(HTTP, PORT));
-
- assertEquals(5985, getEndpointPort(null, null));
- assertEquals(5985, getEndpointPort(HTTP, null));
- assertEquals(5986, getEndpointPort(HTTPS, null));
- }
-
- @Test
- void testGetPort() {
- assertEquals(5985, new WinRMEndpoint(HTTP, HOSTNAME, null, USER, PASSWORD, null).getPort());
- assertEquals(5986, new WinRMEndpoint(HTTPS, HOSTNAME, null, USER, PASSWORD, null).getPort());
- assertEquals(PORT, new WinRMEndpoint(HTTP, HOSTNAME, PORT, USER, PASSWORD, null).getPort());
- assertEquals(PORT, new WinRMEndpoint(HTTPS, HOSTNAME, PORT, USER, PASSWORD, null).getPort());
- }
-
- @Test
- void testUnderscoreHostnameEndpoint() {
- // Regression guard for the light backend default: WinRMEndpoint accepts NetBIOS-style names with
- // underscores and exposes a usable hostname/port, whereas java.net.URI cannot classify such a host
- // (URI.create(endpoint).getHost() is null). The light backend must rely on these accessors.
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTP, "server_name", 5999, USER, PASSWORD, null);
- assertEquals("server_name", winRMEndpoint.getHostname());
- assertEquals(5999, winRMEndpoint.getPort());
- assertNull(java.net.URI.create(winRMEndpoint.getEndpoint()).getHost());
- }
-
- @Test
- void testBuildNamespace() {
- assertEquals("ROOT/CIMV2", buildNamespace(null));
- assertEquals("ROOT/CIMV2", buildNamespace(EMPTY));
- assertEquals("ROOT/CIMV2", buildNamespace(" \t\r\n "));
-
- //case namespace provided
- assertEquals("root", buildNamespace("root"));
- assertEquals("root/cimv2", buildNamespace(" \t\r\n root \t\r\n / \t\r\n cimv2 \t\r\n "));
- assertEquals("Srv/StandardCimv2", buildNamespace("Srv\\StandardCimv2"));
- }
-}
+package org.metricshub.winrm.service;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.metricshub.winrm.Utils.EMPTY;
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTP;
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
+import static org.metricshub.winrm.service.WinRMEndpoint.buildEndpointUrl;
+import static org.metricshub.winrm.service.WinRMEndpoint.buildNamespace;
+import static org.metricshub.winrm.service.WinRMEndpoint.getEndpointPort;
+
+import org.junit.jupiter.api.Test;
+
+class WinRMEndpointTest {
+
+ private static final String HOSTNAME = "host";
+ private static final int PORT = 443;
+ private static final String USER = "user";
+ private static final char[] PASSWORD = { 'p', 'a', 's', 's' };
+
+ @Test
+ void testWinRMEndpoint() {
+ // check arguments
+ assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, null, 5985, USER, PASSWORD, null));
+
+ assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, HOSTNAME, 5985, null, PASSWORD, null));
+
+ assertThrows(IllegalArgumentException.class, () -> new WinRMEndpoint(HTTP, HOSTNAME, 5985, USER, null, null));
+
+ // Case user name in form of domain\\user
+ {
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(
+ null,
+ " \t\r\n host \t\r\n ",
+ null,
+ " \t\r\n domain \t\r\n \\ \t\r\n user \t\r\n ",
+ PASSWORD,
+ null
+ );
+
+ assertEquals(HOSTNAME, winRMEndpoint.getHostname());
+ assertEquals("http://host:5985/wsman", winRMEndpoint.getEndpoint());
+ assertEquals("domain", winRMEndpoint.getDomain());
+ assertEquals(USER, winRMEndpoint.getUsername());
+ assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
+ assertEquals("ROOT/CIMV2", winRMEndpoint.getNamespace());
+ assertEquals(HTTP, winRMEndpoint.getProtocol());
+ }
+ {
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTPS, HOSTNAME, PORT, "domain\\user", PASSWORD, "root");
+
+ assertEquals(HOSTNAME, winRMEndpoint.getHostname());
+ assertEquals("https://host:443/wsman", winRMEndpoint.getEndpoint());
+ assertEquals("domain", winRMEndpoint.getDomain());
+ assertEquals(USER, winRMEndpoint.getUsername());
+ assertEquals("root", winRMEndpoint.getNamespace());
+ assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
+ assertEquals(HTTPS, winRMEndpoint.getProtocol());
+ }
+
+ // Case user name without domain
+ {
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(null, HOSTNAME, null, USER, PASSWORD, "root/cimv2");
+
+ assertEquals(HOSTNAME, winRMEndpoint.getHostname());
+ assertEquals("http://host:5985/wsman", winRMEndpoint.getEndpoint());
+ assertNull(winRMEndpoint.getDomain());
+ assertEquals(USER, winRMEndpoint.getUsername());
+ assertEquals("root/cimv2", winRMEndpoint.getNamespace());
+ assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
+ assertEquals(HTTP, winRMEndpoint.getProtocol());
+ }
+ {
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTP, HOSTNAME, PORT, USER, PASSWORD, "SRV\\Microsoft");
+
+ assertEquals(HOSTNAME, winRMEndpoint.getHostname());
+ assertEquals("http://host:443/wsman", winRMEndpoint.getEndpoint());
+ assertNull(winRMEndpoint.getDomain());
+ assertEquals(USER, winRMEndpoint.getUsername());
+ assertEquals("SRV/Microsoft", winRMEndpoint.getNamespace());
+ assertArrayEquals(PASSWORD, winRMEndpoint.getPassword());
+ assertEquals(HTTP, winRMEndpoint.getProtocol());
+ }
+ }
+
+ @Test
+ void testBuildEndpointUrl() {
+ assertEquals("HTTP://host:5985", buildEndpointUrl(HTTP, HOSTNAME, null));
+ assertEquals("HTTPS://host:5986", buildEndpointUrl(HTTPS, HOSTNAME, null));
+ assertEquals("HTTP://host:443", buildEndpointUrl(HTTP, HOSTNAME, PORT));
+ assertEquals("HTTPS://host:443", buildEndpointUrl(HTTPS, HOSTNAME, PORT));
+ }
+
+ @Test
+ void testGetEndPointPort() {
+ // case port provided
+ assertEquals(PORT, getEndpointPort(null, PORT));
+ assertEquals(PORT, getEndpointPort(HTTPS, PORT));
+ assertEquals(PORT, getEndpointPort(HTTP, PORT));
+
+ assertEquals(5985, getEndpointPort(null, null));
+ assertEquals(5985, getEndpointPort(HTTP, null));
+ assertEquals(5986, getEndpointPort(HTTPS, null));
+ }
+
+ @Test
+ void testGetPort() {
+ assertEquals(5985, new WinRMEndpoint(HTTP, HOSTNAME, null, USER, PASSWORD, null).getPort());
+ assertEquals(5986, new WinRMEndpoint(HTTPS, HOSTNAME, null, USER, PASSWORD, null).getPort());
+ assertEquals(PORT, new WinRMEndpoint(HTTP, HOSTNAME, PORT, USER, PASSWORD, null).getPort());
+ assertEquals(PORT, new WinRMEndpoint(HTTPS, HOSTNAME, PORT, USER, PASSWORD, null).getPort());
+ }
+
+ @Test
+ void testUnderscoreHostnameEndpoint() {
+ // Regression guard for the light backend default: WinRMEndpoint accepts NetBIOS-style names with
+ // underscores and exposes a usable hostname/port, whereas java.net.URI cannot classify such a host
+ // (URI.create(endpoint).getHost() is null). The light backend must rely on these accessors.
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(HTTP, "server_name", 5999, USER, PASSWORD, null);
+ assertEquals("server_name", winRMEndpoint.getHostname());
+ assertEquals(5999, winRMEndpoint.getPort());
+ assertNull(java.net.URI.create(winRMEndpoint.getEndpoint()).getHost());
+ }
+
+ @Test
+ void testBuildNamespace() {
+ assertEquals("ROOT/CIMV2", buildNamespace(null));
+ assertEquals("ROOT/CIMV2", buildNamespace(EMPTY));
+ assertEquals("ROOT/CIMV2", buildNamespace(" \t\r\n "));
+
+ // case namespace provided
+ assertEquals("root", buildNamespace("root"));
+ assertEquals("root/cimv2", buildNamespace(" \t\r\n root \t\r\n / \t\r\n cimv2 \t\r\n "));
+ assertEquals("Srv/StandardCimv2", buildNamespace("Srv\\StandardCimv2"));
+ }
+}
diff --git a/src/test/java/org/metricshub/winrm/service/WinRMExecutorFactoryTest.java b/src/test/java/org/metricshub/winrm/service/WinRMExecutorFactoryTest.java
index 554afb5..29baec9 100644
--- a/src/test/java/org/metricshub/winrm/service/WinRMExecutorFactoryTest.java
+++ b/src/test/java/org/metricshub/winrm/service/WinRMExecutorFactoryTest.java
@@ -35,8 +35,7 @@ void lightBackendSelectedForHttpNtlm() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.NTLM)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
assertEquals("testhost", executor.getHostname());
}
@@ -52,8 +51,7 @@ void defaultBackendIsLight() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.NTLM)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
}
}
@@ -65,13 +63,12 @@ void cxfBackendRejectedWithRemovalMessage() {
System.setProperty(WinRMExecutorFactory.BACKEND_PROPERTY, "cxf");
final WinRMException e = assertThrows(
WinRMException.class,
- () ->
- WinRMExecutorFactory.createInstance(
- endpoint(WinRMHttpProtocolEnum.HTTP),
- 30000L,
- null,
- List.of(AuthenticationEnum.NTLM)
- )
+ () -> WinRMExecutorFactory.createInstance(
+ endpoint(WinRMHttpProtocolEnum.HTTP),
+ 30000L,
+ null,
+ List.of(AuthenticationEnum.NTLM)
+ )
);
assertTrue(e.getMessage().contains("removed in winrm-java 2.0.0"), e.getMessage());
}
@@ -86,8 +83,7 @@ void defaultBackendAcceptsHttps() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.NTLM)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
}
}
@@ -101,8 +97,7 @@ void lightBackendAcceptsHttps() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.NTLM)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
}
}
@@ -114,13 +109,12 @@ void kerberosOnlyOverHttpRejected() {
System.setProperty(WinRMExecutorFactory.BACKEND_PROPERTY, "light");
assertThrows(
WinRMException.class,
- () ->
- WinRMExecutorFactory.createInstance(
- endpoint(WinRMHttpProtocolEnum.HTTP),
- 30000L,
- null,
- List.of(AuthenticationEnum.KERBEROS)
- )
+ () -> WinRMExecutorFactory.createInstance(
+ endpoint(WinRMHttpProtocolEnum.HTTP),
+ 30000L,
+ null,
+ List.of(AuthenticationEnum.KERBEROS)
+ )
);
}
@@ -135,8 +129,7 @@ void mixedKerberosNtlmFallsBackToNtlmOverHttp() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.KERBEROS, AuthenticationEnum.NTLM)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
}
}
@@ -152,8 +145,7 @@ void kerberosOverHttpsAccepted() throws Exception {
30000L,
null,
List.of(AuthenticationEnum.KERBEROS)
- )
- ) {
+ )) {
assertInstanceOf(LightWinRMService.class, executor);
}
}
@@ -165,13 +157,12 @@ void unsupportedBackendValueRejected() {
System.setProperty(WinRMExecutorFactory.BACKEND_PROPERTY, "cxff");
assertThrows(
WinRMException.class,
- () ->
- WinRMExecutorFactory.createInstance(
- endpoint(WinRMHttpProtocolEnum.HTTP),
- 30000L,
- null,
- List.of(AuthenticationEnum.NTLM)
- )
+ () -> WinRMExecutorFactory.createInstance(
+ endpoint(WinRMHttpProtocolEnum.HTTP),
+ 30000L,
+ null,
+ List.of(AuthenticationEnum.NTLM)
+ )
);
}
diff --git a/src/test/java/org/metricshub/winrm/service/client/auth/AuthenticationEnumTest.java b/src/test/java/org/metricshub/winrm/service/client/auth/AuthenticationEnumTest.java
index 127dae2..8dddcaa 100644
--- a/src/test/java/org/metricshub/winrm/service/client/auth/AuthenticationEnumTest.java
+++ b/src/test/java/org/metricshub/winrm/service/client/auth/AuthenticationEnumTest.java
@@ -1,27 +1,27 @@
-package org.metricshub.winrm.service.client.auth;
-
-import static java.util.Optional.empty;
-import static java.util.Optional.of;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.metricshub.winrm.Utils.EMPTY;
-import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;
-import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
-import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.getValueOf;
-
-import org.junit.jupiter.api.Test;
-
-class AuthenticationEnumTest {
-
- @Test
- void testGetValueOf() {
- assertEquals(empty(), getValueOf(null));
- assertEquals(empty(), getValueOf(EMPTY));
- assertEquals(empty(), getValueOf("unknown"));
- assertEquals(of(NTLM), getValueOf(" ntlm "));
- assertEquals(of(NTLM), getValueOf(" Ntlm "));
- assertEquals(of(NTLM), getValueOf(" NTLM "));
- assertEquals(of(KERBEROS), getValueOf(" kerberos "));
- assertEquals(of(KERBEROS), getValueOf(" Kerberos "));
- assertEquals(of(KERBEROS), getValueOf(" KERBEROS "));
- }
-}
+package org.metricshub.winrm.service.client.auth;
+
+import static java.util.Optional.empty;
+import static java.util.Optional.of;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.metricshub.winrm.Utils.EMPTY;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.KERBEROS;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.getValueOf;
+
+import org.junit.jupiter.api.Test;
+
+class AuthenticationEnumTest {
+
+ @Test
+ void testGetValueOf() {
+ assertEquals(empty(), getValueOf(null));
+ assertEquals(empty(), getValueOf(EMPTY));
+ assertEquals(empty(), getValueOf("unknown"));
+ assertEquals(of(NTLM), getValueOf(" ntlm "));
+ assertEquals(of(NTLM), getValueOf(" Ntlm "));
+ assertEquals(of(NTLM), getValueOf(" NTLM "));
+ assertEquals(of(KERBEROS), getValueOf(" kerberos "));
+ assertEquals(of(KERBEROS), getValueOf(" Kerberos "));
+ assertEquals(of(KERBEROS), getValueOf(" KERBEROS "));
+ }
+}
diff --git a/src/test/java/org/metricshub/winrm/shares/SmbTempShareTest.java b/src/test/java/org/metricshub/winrm/shares/SmbTempShareTest.java
index 7896093..f27b481 100644
--- a/src/test/java/org/metricshub/winrm/shares/SmbTempShareTest.java
+++ b/src/test/java/org/metricshub/winrm/shares/SmbTempShareTest.java
@@ -1,140 +1,139 @@
-package org.metricshub.winrm.shares;
-
-import static java.nio.file.Paths.get;
-import static java.util.Collections.singletonList;
-import static java.util.concurrent.TimeUnit.SECONDS;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.metricshub.winrm.WindowsTempShare.getOrCreateShare;
-import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
-import static org.metricshub.winrm.shares.SmbTempShare.createInstance;
-import static org.metricshub.winrm.shares.SmbTempShare.createSmbClient;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-
-import com.hierynomus.security.bc.BCSecurityProvider;
-import com.hierynomus.smbj.SMBClient;
-import com.hierynomus.smbj.SmbConfig;
-import com.hierynomus.smbj.SmbConfig.Builder;
-import com.hierynomus.smbj.auth.AuthenticationContext;
-import com.hierynomus.smbj.connection.Connection;
-import com.hierynomus.smbj.session.Session;
-import com.hierynomus.smbj.share.DiskShare;
-import java.nio.file.Path;
-import java.util.List;
-import org.junit.jupiter.api.Test;
-import org.metricshub.winrm.ShareRemoteDirectoryConsumer;
-import org.metricshub.winrm.WindowsRemoteExecutor;
-import org.metricshub.winrm.WindowsTempShare;
-import org.metricshub.winrm.service.WinRMEndpoint;
-import org.metricshub.winrm.service.WinRMExecutorFactory;
-import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
-import org.mockito.MockedStatic;
-
-class SmbTempShareTest {
-
- @SuppressWarnings("unchecked")
- @Test
- void testCreateInstance() throws Exception {
- final String hostname = "host";
- final String username = "user";
- final char[] password = "pwd".toCharArray();
- final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(null, hostname, null, "domain\\" + username, password, null);
- final long timeout = 30 * 1000L;
- final Path ticketCache = get("path");
- final List authentications = singletonList(NTLM);
-
- //check arguments
- assertThrows(IllegalArgumentException.class, () -> createInstance(null, timeout, ticketCache, authentications));
-
- assertThrows(
- IllegalArgumentException.class,
- () -> createInstance(winRMEndpoint, -1L, ticketCache, authentications)
- );
-
- assertThrows(IllegalArgumentException.class, () -> createInstance(winRMEndpoint, 0L, ticketCache, authentications));
-
- try (
- final MockedStatic mockedFactory = mockStatic(WinRMExecutorFactory.class);
- final MockedStatic mockedSmbTempShare = mockStatic(SmbTempShare.class);
- final MockedStatic mockedWindowsTempShare = mockStatic(WindowsTempShare.class);
- final MockedStatic mockedSmbConfig = mockStatic(SmbConfig.class)
- ) {
- final WindowsRemoteExecutor executor = mock(WindowsRemoteExecutor.class);
- mockedFactory
- .when(() -> WinRMExecutorFactory.createInstance(winRMEndpoint, timeout, null, null))
- .thenReturn(executor);
-
- final WindowsTempShare windowsTempShare = mock(WindowsTempShare.class);
- mockedWindowsTempShare
- .when(() -> getOrCreateShare(eq(executor), anyLong(), any(ShareRemoteDirectoryConsumer.class)))
- .thenReturn(windowsTempShare);
- doReturn("\\\\2001-db8--85b-3c51-f5ff-ffdb.ipv6-literal.net\\SEN_ShareFor_PC-TEST$")
- .when(windowsTempShare)
- .getUncSharePath();
- doReturn("Windows\\Temp\\SEN_ShareFor_TEST$").when(windowsTempShare).getRemotePath();
- doReturn("SEN_ShareFor_PC-TEST$").when(windowsTempShare).getShareName();
-
- final Builder smbConfigBuilder = mock(Builder.class);
- mockedSmbConfig.when(SmbConfig::builder).thenReturn(smbConfigBuilder);
-
- doReturn(smbConfigBuilder).when(smbConfigBuilder).withSecurityProvider(any(BCSecurityProvider.class));
-
- doReturn(smbConfigBuilder).when(smbConfigBuilder).withTimeout(anyLong(), eq(SECONDS));
-
- final SmbConfig smbConfig = mock(SmbConfig.class);
- doReturn(smbConfig).when(smbConfigBuilder).build();
-
- final SMBClient smbClient = mock(SMBClient.class);
- mockedSmbTempShare.when(() -> createSmbClient(smbConfig)).thenReturn(smbClient);
-
- final Connection connection = mock(Connection.class);
- doReturn(connection).when(smbClient).connect(anyString());
-
- final Session session = mock(Session.class);
- doReturn(session).when(connection).authenticate(any(AuthenticationContext.class));
-
- final DiskShare diskShare = mock(DiskShare.class);
- doReturn(diskShare).when(session).connectShare(anyString());
-
- mockedSmbTempShare
- .when(() -> createInstance(any(WinRMEndpoint.class), anyLong(), isNull(), isNull()))
- .thenCallRealMethod();
-
- final SmbTempShare smbTempShare1 = createInstance(winRMEndpoint, timeout, null, null);
- assertNotNull(smbTempShare1);
- assertEquals(1, smbTempShare1.getUseCount());
- assertEquals(executor, smbTempShare1.getWindowsRemoteExecutor());
- assertTrue(smbTempShare1.isConnected());
-
- final SmbTempShare smbTempShare2 = createInstance(winRMEndpoint, timeout, null, null);
- assertNotNull(smbTempShare2);
- assertEquals(2, smbTempShare1.getUseCount());
- assertEquals(2, smbTempShare2.getUseCount());
- assertEquals(executor, smbTempShare2.getWindowsRemoteExecutor());
- assertTrue(smbTempShare1.isConnected());
- assertTrue(smbTempShare2.isConnected());
-
- smbTempShare1.close();
- assertTrue(smbTempShare1.isConnected());
- assertTrue(smbTempShare2.isConnected());
- assertEquals(1, smbTempShare1.getUseCount());
- assertEquals(1, smbTempShare2.getUseCount());
-
- smbTempShare2.close();
- assertFalse(smbTempShare1.isConnected());
- assertFalse(smbTempShare2.isConnected());
- assertEquals(0, smbTempShare1.getUseCount());
- assertEquals(0, smbTempShare2.getUseCount());
- }
- }
-}
+package org.metricshub.winrm.shares;
+
+import static java.nio.file.Paths.get;
+import static java.util.Collections.singletonList;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.metricshub.winrm.WindowsTempShare.getOrCreateShare;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+import static org.metricshub.winrm.shares.SmbTempShare.createInstance;
+import static org.metricshub.winrm.shares.SmbTempShare.createSmbClient;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+
+import com.hierynomus.security.bc.BCSecurityProvider;
+import com.hierynomus.smbj.SMBClient;
+import com.hierynomus.smbj.SmbConfig;
+import com.hierynomus.smbj.SmbConfig.Builder;
+import com.hierynomus.smbj.auth.AuthenticationContext;
+import com.hierynomus.smbj.connection.Connection;
+import com.hierynomus.smbj.session.Session;
+import com.hierynomus.smbj.share.DiskShare;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.metricshub.winrm.ShareRemoteDirectoryConsumer;
+import org.metricshub.winrm.WindowsRemoteExecutor;
+import org.metricshub.winrm.WindowsTempShare;
+import org.metricshub.winrm.service.WinRMEndpoint;
+import org.metricshub.winrm.service.WinRMExecutorFactory;
+import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
+import org.mockito.MockedStatic;
+
+class SmbTempShareTest {
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void testCreateInstance() throws Exception {
+ final String hostname = "host";
+ final String username = "user";
+ final char[] password = "pwd".toCharArray();
+ final WinRMEndpoint winRMEndpoint = new WinRMEndpoint(null, hostname, null, "domain\\" + username, password, null);
+ final long timeout = 30 * 1000L;
+ final Path ticketCache = get("path");
+ final List authentications = singletonList(NTLM);
+
+ // check arguments
+ assertThrows(IllegalArgumentException.class, () -> createInstance(null, timeout, ticketCache, authentications));
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> createInstance(winRMEndpoint, -1L, ticketCache, authentications)
+ );
+
+ assertThrows(IllegalArgumentException.class, () -> createInstance(winRMEndpoint, 0L, ticketCache, authentications));
+
+ try (
+ final MockedStatic mockedFactory = mockStatic(WinRMExecutorFactory.class);
+ final MockedStatic mockedSmbTempShare = mockStatic(SmbTempShare.class);
+ final MockedStatic mockedWindowsTempShare = mockStatic(WindowsTempShare.class);
+ final MockedStatic mockedSmbConfig = mockStatic(SmbConfig.class)) {
+ final WindowsRemoteExecutor executor = mock(WindowsRemoteExecutor.class);
+ mockedFactory
+ .when(() -> WinRMExecutorFactory.createInstance(winRMEndpoint, timeout, null, null))
+ .thenReturn(executor);
+
+ final WindowsTempShare windowsTempShare = mock(WindowsTempShare.class);
+ mockedWindowsTempShare
+ .when(() -> getOrCreateShare(eq(executor), anyLong(), any(ShareRemoteDirectoryConsumer.class)))
+ .thenReturn(windowsTempShare);
+ doReturn("\\\\2001-db8--85b-3c51-f5ff-ffdb.ipv6-literal.net\\SEN_ShareFor_PC-TEST$")
+ .when(windowsTempShare)
+ .getUncSharePath();
+ doReturn("Windows\\Temp\\SEN_ShareFor_TEST$").when(windowsTempShare).getRemotePath();
+ doReturn("SEN_ShareFor_PC-TEST$").when(windowsTempShare).getShareName();
+
+ final Builder smbConfigBuilder = mock(Builder.class);
+ mockedSmbConfig.when(SmbConfig::builder).thenReturn(smbConfigBuilder);
+
+ doReturn(smbConfigBuilder).when(smbConfigBuilder).withSecurityProvider(any(BCSecurityProvider.class));
+
+ doReturn(smbConfigBuilder).when(smbConfigBuilder).withTimeout(anyLong(), eq(SECONDS));
+
+ final SmbConfig smbConfig = mock(SmbConfig.class);
+ doReturn(smbConfig).when(smbConfigBuilder).build();
+
+ final SMBClient smbClient = mock(SMBClient.class);
+ mockedSmbTempShare.when(() -> createSmbClient(smbConfig)).thenReturn(smbClient);
+
+ final Connection connection = mock(Connection.class);
+ doReturn(connection).when(smbClient).connect(anyString());
+
+ final Session session = mock(Session.class);
+ doReturn(session).when(connection).authenticate(any(AuthenticationContext.class));
+
+ final DiskShare diskShare = mock(DiskShare.class);
+ doReturn(diskShare).when(session).connectShare(anyString());
+
+ mockedSmbTempShare
+ .when(() -> createInstance(any(WinRMEndpoint.class), anyLong(), isNull(), isNull()))
+ .thenCallRealMethod();
+
+ final SmbTempShare smbTempShare1 = createInstance(winRMEndpoint, timeout, null, null);
+ assertNotNull(smbTempShare1);
+ assertEquals(1, smbTempShare1.getUseCount());
+ assertEquals(executor, smbTempShare1.getWindowsRemoteExecutor());
+ assertTrue(smbTempShare1.isConnected());
+
+ final SmbTempShare smbTempShare2 = createInstance(winRMEndpoint, timeout, null, null);
+ assertNotNull(smbTempShare2);
+ assertEquals(2, smbTempShare1.getUseCount());
+ assertEquals(2, smbTempShare2.getUseCount());
+ assertEquals(executor, smbTempShare2.getWindowsRemoteExecutor());
+ assertTrue(smbTempShare1.isConnected());
+ assertTrue(smbTempShare2.isConnected());
+
+ smbTempShare1.close();
+ assertTrue(smbTempShare1.isConnected());
+ assertTrue(smbTempShare2.isConnected());
+ assertEquals(1, smbTempShare1.getUseCount());
+ assertEquals(1, smbTempShare2.getUseCount());
+
+ smbTempShare2.close();
+ assertFalse(smbTempShare1.isConnected());
+ assertFalse(smbTempShare2.isConnected());
+ assertEquals(0, smbTempShare1.getUseCount());
+ assertEquals(0, smbTempShare2.getUseCount());
+ }
+ }
+}
diff --git a/src/test/java/org/metricshub/winrm/wql/WinRMWqlExecutorTest.java b/src/test/java/org/metricshub/winrm/wql/WinRMWqlExecutorTest.java
index 5090ddd..7aa6afd 100644
--- a/src/test/java/org/metricshub/winrm/wql/WinRMWqlExecutorTest.java
+++ b/src/test/java/org/metricshub/winrm/wql/WinRMWqlExecutorTest.java
@@ -1,120 +1,120 @@
-package org.metricshub.winrm.wql;
-
-import static java.nio.file.Paths.get;
-import static java.util.Arrays.asList;
-import static java.util.Collections.singletonList;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
-import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
-import static org.metricshub.winrm.wql.WinRMWqlExecutor.executeWql;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.junit.jupiter.api.Test;
-import org.metricshub.winrm.WindowsRemoteExecutor;
-import org.metricshub.winrm.service.WinRMEndpoint;
-import org.metricshub.winrm.service.WinRMExecutorFactory;
-import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
-import org.mockito.MockedStatic;
-
-class WinRMWqlExecutorTest {
-
- @Test
- void testExecute() throws Exception {
- final String wqlQuery = "Select Name,Path from Win32_Share";
- final String hostname = "host";
- final String username = "user";
- final char[] password = "pass".toCharArray();
- final long timeout = 30 * 1000L;
- final Path ticketCache = get("path");
- final List authentications = singletonList(NTLM);
-
- // check arguments
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, null, 5986, username, password, null, wqlQuery, timeout, ticketCache, authentications)
- );
-
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, hostname, 5986, null, password, null, wqlQuery, timeout, ticketCache, authentications)
- );
-
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, hostname, 5986, username, null, null, wqlQuery, timeout, ticketCache, authentications)
- );
-
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, hostname, 5986, username, password, null, null, timeout, ticketCache, authentications)
- );
-
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, hostname, 5986, username, password, null, wqlQuery, -1L, ticketCache, authentications)
- );
-
- assertThrows(
- IllegalArgumentException.class,
- () -> executeWql(HTTPS, hostname, 5986, username, password, null, wqlQuery, 0L, ticketCache, authentications)
- );
-
- try (final MockedStatic mockedFactory = mockStatic(WinRMExecutorFactory.class)) {
- final WindowsRemoteExecutor executor = mock(WindowsRemoteExecutor.class);
-
- final List> result = new ArrayList<>();
- {
- final Map row = new HashMap<>();
- row.put("Name", "C$");
- row.put("Path", "C:\\");
- result.add(row);
- }
- {
- final Map row = new HashMap<>();
- row.put("Name", "SEN_ShareFor_PC$");
- row.put("Path", "C:\\Windows\\Temp\\SEN_ShareFor_PC$");
- result.add(row);
- }
-
- mockedFactory
- .when(() -> WinRMExecutorFactory.createInstance(any(WinRMEndpoint.class), anyLong(), isNull(), isNull()))
- .thenReturn(executor);
-
- doReturn(result).when(executor).executeWql(eq(wqlQuery), anyLong());
-
- final WinRMWqlExecutor actual = executeWql(
- null,
- hostname,
- null,
- username,
- password,
- null,
- wqlQuery,
- timeout,
- null,
- null
- );
-
- assertEquals(asList("Name", "Path"), actual.getHeaders());
-
- final List> rows = asList(
- asList("C$", "C:\\"),
- asList("SEN_ShareFor_PC$", "C:\\Windows\\Temp\\SEN_ShareFor_PC$")
- );
-
- assertEquals(rows, actual.getRows());
- }
- }
-}
+package org.metricshub.winrm.wql;
+
+import static java.nio.file.Paths.get;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.metricshub.winrm.WinRMHttpProtocolEnum.HTTPS;
+import static org.metricshub.winrm.service.client.auth.AuthenticationEnum.NTLM;
+import static org.metricshub.winrm.wql.WinRMWqlExecutor.executeWql;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.jupiter.api.Test;
+import org.metricshub.winrm.WindowsRemoteExecutor;
+import org.metricshub.winrm.service.WinRMEndpoint;
+import org.metricshub.winrm.service.WinRMExecutorFactory;
+import org.metricshub.winrm.service.client.auth.AuthenticationEnum;
+import org.mockito.MockedStatic;
+
+class WinRMWqlExecutorTest {
+
+ @Test
+ void testExecute() throws Exception {
+ final String wqlQuery = "Select Name,Path from Win32_Share";
+ final String hostname = "host";
+ final String username = "user";
+ final char[] password = "pass".toCharArray();
+ final long timeout = 30 * 1000L;
+ final Path ticketCache = get("path");
+ final List authentications = singletonList(NTLM);
+
+ // check arguments
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, null, 5986, username, password, null, wqlQuery, timeout, ticketCache, authentications)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, hostname, 5986, null, password, null, wqlQuery, timeout, ticketCache, authentications)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, hostname, 5986, username, null, null, wqlQuery, timeout, ticketCache, authentications)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, hostname, 5986, username, password, null, null, timeout, ticketCache, authentications)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, hostname, 5986, username, password, null, wqlQuery, -1L, ticketCache, authentications)
+ );
+
+ assertThrows(
+ IllegalArgumentException.class,
+ () -> executeWql(HTTPS, hostname, 5986, username, password, null, wqlQuery, 0L, ticketCache, authentications)
+ );
+
+ try (final MockedStatic mockedFactory = mockStatic(WinRMExecutorFactory.class)) {
+ final WindowsRemoteExecutor executor = mock(WindowsRemoteExecutor.class);
+
+ final List> result = new ArrayList<>();
+ {
+ final Map row = new HashMap<>();
+ row.put("Name", "C$");
+ row.put("Path", "C:\\");
+ result.add(row);
+ }
+ {
+ final Map row = new HashMap<>();
+ row.put("Name", "SEN_ShareFor_PC$");
+ row.put("Path", "C:\\Windows\\Temp\\SEN_ShareFor_PC$");
+ result.add(row);
+ }
+
+ mockedFactory
+ .when(() -> WinRMExecutorFactory.createInstance(any(WinRMEndpoint.class), anyLong(), isNull(), isNull()))
+ .thenReturn(executor);
+
+ doReturn(result).when(executor).executeWql(eq(wqlQuery), anyLong());
+
+ final WinRMWqlExecutor actual = executeWql(
+ null,
+ hostname,
+ null,
+ username,
+ password,
+ null,
+ wqlQuery,
+ timeout,
+ null,
+ null
+ );
+
+ assertEquals(asList("Name", "Path"), actual.getHeaders());
+
+ final List> rows = asList(
+ asList("C$", "C:\\"),
+ asList("SEN_ShareFor_PC$", "C:\\Windows\\Temp\\SEN_ShareFor_PC$")
+ );
+
+ assertEquals(rows, actual.getRows());
+ }
+ }
+}