Update NTCredentials to determine workstation name at runtime

This change modifies the NTCredentials class to determine the local workstation name at runtime or request time, in line with the underlying NTLM implementation. The deprecated constructor with the workstation parameter is replaced with a new constructor that does not require the workstation parameter. Instead, it automatically retrieves the workstation name using the getWorkstationName() method.
This commit is contained in:
Arturo Bernal 2023-04-23 08:47:32 +02:00 committed by Oleg Kalnichevski
parent 94d73429dd
commit 1bd7f07d17
2 changed files with 57 additions and 18 deletions

View File

@ -27,6 +27,8 @@
package org.apache.hc.client5.http.auth;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.Principal;
import java.util.Locale;
import java.util.Objects;
@ -67,13 +69,15 @@ public class NTCredentials implements Credentials, Serializable {
* @param workstation The workstation the authentication request is originating from.
* Essentially, the computer name for this machine.
* @param domain The domain to authenticate within.
* @deprecated (5.3) Use {@link #NTCredentials(char[], String, String, String)}
*/
@Deprecated
public NTCredentials(
final String userName,
final char[] password,
final String workstation,
final String domain) {
this(userName, password, convertHost(workstation), domain, convertDomain(domain));
this(password, userName, domain, convertDomain(domain));
}
/**
@ -85,25 +89,47 @@ public class NTCredentials implements Credentials, Serializable {
* Essentially, the computer name for this machine.
* @param domain The domain to authenticate within.
* @param netbiosDomain The netbios version of the domain name.
@deprecated (5.3) Use {@link #NTCredentials(char[], String, String, String)}
*/
@Deprecated
public NTCredentials(
final String userName,
final char[] password,
final String workstation,
final String domain,
final String netbiosDomain) {
this(password, userName, domain, netbiosDomain);
}
/**
* Constructor to create an instance of NTCredentials.
*
* @param password The password to use for authentication. Must not be null.
* @param userName The user name for authentication. This should not include the domain to authenticate with.
* For example: "user" is correct whereas "DOMAIN\user" is not. Must not be null.
* @param domain The domain to authenticate within. Can be null.
* @param netbiosDomain An alternative representation of the domain name in NetBIOS format. Can be null.
* This parameter is provided to accommodate specific scenarios that require the NetBIOS version of the domain name.
* <p>
* This constructor creates a new instance of NTCredentials, determining the workstation name at runtime
* using the {@link #getWorkstationName()} method. The workstation name will be converted to uppercase
* using the {@link java.util.Locale#ROOT} locale.
* @since 5.3
*/
public NTCredentials(
final char[] password,
final String userName,
final String domain,
final String netbiosDomain) {
super();
Args.notNull(userName, "User name");
this.principal = new NTUserPrincipal(domain, userName);
this.password = password;
if (workstation != null) {
this.workstation = workstation.toUpperCase(Locale.ROOT);
} else {
this.workstation = null;
}
this.workstation = getWorkstationName().toUpperCase(Locale.ROOT);
this.netbiosDomain = netbiosDomain;
}
@Override
public Principal getUserPrincipal() {
return this.principal;
@ -192,15 +218,29 @@ public class NTCredentials implements Credentials, Serializable {
return value;
}
/** Convert host to standard form */
private static String convertHost(final String host) {
return stripDotSuffix(host);
}
/** Convert domain to standard form */
private static String convertDomain(final String domain) {
final String returnString = stripDotSuffix(domain);
return returnString == null ? returnString : returnString.toUpperCase(Locale.ROOT);
}
/**
* Retrieves the workstation name of the computer originating the request.
* This method attempts to get the local host name using the InetAddress class.
* If it fails to retrieve the host name due to an UnknownHostException, it returns "localhost" as a fallback.
*
* @return The unqualified workstation name as a String.
*/
private static String getWorkstationName() {
try {
final InetAddress addr = InetAddress.getLocalHost();
final String hostName = addr.getHostName();
// Ensure the hostname is unqualified by removing any domain part
return stripDotSuffix(hostName);
} catch (final UnknownHostException e) {
return "localhost";
}
}
}

View File

@ -63,7 +63,7 @@ public class TestCredentials {
Assertions.assertEquals(new NTUserPrincipal("DOMAIN", "name"),
creds1.getUserPrincipal());
Assertions.assertArrayEquals("pwd".toCharArray(), creds1.getPassword());
Assertions.assertEquals("[principal: DOMAIN\\name][workstation: LOCALHOST][netbiosDomain: DOMAIN]",
Assertions.assertEquals("[principal: DOMAIN\\name][workstation: "+ creds1.getWorkstation() +"][netbiosDomain: DOMAIN]",
creds1.toString());
final NTCredentials creds2 = new NTCredentials(
"name", null, null, null);
@ -71,7 +71,7 @@ public class TestCredentials {
Assertions.assertEquals(new NTUserPrincipal(null, "name"),
creds2.getUserPrincipal());
Assertions.assertNull(creds2.getPassword());
Assertions.assertEquals("[principal: name][workstation: null][netbiosDomain: null]",
Assertions.assertEquals("[principal: name][workstation: "+creds1.getWorkstation() +"][netbiosDomain: null]",
creds2.toString());
}
@ -155,8 +155,8 @@ public class TestCredentials {
Assertions.assertTrue(creds1.hashCode() == creds1.hashCode());
Assertions.assertTrue(creds1.hashCode() != creds2.hashCode());
Assertions.assertEquals(creds1.hashCode(), creds3.hashCode());
Assertions.assertNotEquals(creds1.hashCode(), creds4.hashCode());
Assertions.assertNotEquals(creds1.hashCode(), creds5.hashCode());
Assertions.assertEquals(creds1.hashCode(), creds4.hashCode());
Assertions.assertEquals(creds1.hashCode(), creds5.hashCode());
Assertions.assertNotEquals(creds1.hashCode(), creds6.hashCode());
Assertions.assertNotEquals(creds1.hashCode(), creds7.hashCode());
Assertions.assertEquals(creds8.hashCode(), creds5.hashCode());
@ -187,8 +187,8 @@ public class TestCredentials {
Assertions.assertEquals(creds1, creds1);
Assertions.assertNotEquals(creds1, creds2);
Assertions.assertEquals(creds1, creds3);
Assertions.assertNotEquals(creds1, creds4);
Assertions.assertNotEquals(creds1, creds5);
Assertions.assertEquals(creds1, creds4);
Assertions.assertEquals(creds1, creds5);
Assertions.assertNotEquals(creds1, creds6);
Assertions.assertNotEquals(creds1, creds7);
Assertions.assertEquals(creds8, creds5);
@ -223,5 +223,4 @@ public class TestCredentials {
final NTCredentials clone = (NTCredentials) inStream.readObject();
Assertions.assertEquals(orig, clone);
}
}