View Javadoc
1   package org.metricshub.winrm.service;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * WinRM Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 - 2024 Metricshub
8    * ჻჻჻჻჻჻
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
21   */
22  
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.util.Arrays;
26  import java.util.Objects;
27  import org.metricshub.winrm.Utils;
28  import org.metricshub.winrm.WinRMHttpProtocolEnum;
29  import org.metricshub.winrm.WmiHelper;
30  
31  public class WinRMEndpoint {
32  
33  	private static final int DEFAULT_WIN_RM_HTTP_PORT = 5985;
34  	private static final int DEFAULT_WIN_RM_HTTPS_PORT = 5986;
35  
36  	private final String hostname;
37  	private final String endpoint;
38  	private final String domain;
39  	private final String username;
40  	private final char[] password;
41  	private final String namespace;
42  	private final String rawUsername;
43  	private final WinRMHttpProtocolEnum protocol;
44  
45  	/**
46  	 * Constructor of the endpoint and credentials for WinRM.
47  	 *
48  	 * @param protocol The protocol
49  	 * @param hostname The host name (mandatory)
50  	 * @param port The port
51  	 * @param username The user name (mandatory)
52  	 * @param password The password (mandatory)
53  	 * @param namespace The namespace default value: {@value WmiHelper#DEFAULT_NAMESPACE}
54  	 */
55  	public WinRMEndpoint(
56  		final WinRMHttpProtocolEnum protocol,
57  		final String hostname,
58  		final Integer port,
59  		final String username,
60  		final char[] password,
61  		final String namespace
62  	) {
63  		Utils.checkNonNull(hostname, "hostname");
64  		Utils.checkNonNull(username, "username");
65  		Utils.checkNonNull(password, "password");
66  
67  		this.hostname = hostname.replaceAll("\\s", Utils.EMPTY);
68  		this.password = password;
69  		rawUsername = username;
70  
71  		this.namespace = buildNamespace(namespace);
72  
73  		final String user = username.replaceAll("\\s", Utils.EMPTY);
74  		if (user.contains("\\")) {
75  			final String[] array = user.split("\\\\");
76  			domain = array[0];
77  			this.username = array[1];
78  		} else {
79  			domain = null;
80  			this.username = user;
81  		}
82  
83  		this.protocol = protocol != null ? protocol : WinRMHttpProtocolEnum.HTTP;
84  		final String endpointUrl = buildEndpointUrl(this.protocol, this.hostname, port);
85  
86  		endpoint = buildWSManEndpoint(endpointUrl);
87  	}
88  
89  	/** Get the hostname */
90  	public String getHostname() {
91  		return hostname;
92  	}
93  
94  	/** Get the endpoint in the form of http(s)://host:port/wsman */
95  	public String getEndpoint() {
96  		return endpoint;
97  	}
98  
99  	/** Get the domain from the raw username */
100 	public String getDomain() {
101 		return domain;
102 	}
103 
104 	/** get the username as indicated in the constructor (could be in domain\\user form) */
105 	public String getRawUsername() {
106 		return rawUsername;
107 	}
108 
109 	/** Get the username part of the raw username */
110 	public String getUsername() {
111 		return username;
112 	}
113 
114 	/** Get the password */
115 	public char[] getPassword() {
116 		return password;
117 	}
118 
119 	/** Get the namespace */
120 	public String getNamespace() {
121 		return namespace;
122 	}
123 
124 	/** Get the protocol */
125 	public WinRMHttpProtocolEnum getProtocol() {
126 		return protocol;
127 	}
128 
129 	/**
130 	 * Build the endpoint URL.
131 	 *
132 	 * @param protocol The HTTP protocol
133 	 * @param hostname The host name
134 	 * @param port The port
135 	 *
136 	 * @return the endpoint URL in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
137 	 */
138 	public static String buildEndpointUrl(
139 		final WinRMHttpProtocolEnum protocol,
140 		final String hostname,
141 		final Integer port
142 	) {
143 		final int endpointPort = getEndpointPort(protocol, port);
144 
145 		return String.format("%s://%s:%d", protocol.toString(), hostname, endpointPort);
146 	}
147 
148 	/**
149 	 *	Get the endpoint port:
150 	 *<ul>
151 	 * <li>The port if provided</li>
152 	 * <li>5986 if the protocol is HTTPS</li>
153 	 * <li>5985 otherwise</li>
154 	 *</ul>
155 	 * @param protocol The HTTP protocol
156 	 * @param port The port
157 	 *
158 	 * @return The endpoint port
159 	 */
160 	public static int getEndpointPort(final WinRMHttpProtocolEnum protocol, final Integer port) {
161 		if (port != null) {
162 			return port;
163 		}
164 		return protocol == WinRMHttpProtocolEnum.HTTPS ? DEFAULT_WIN_RM_HTTPS_PORT : DEFAULT_WIN_RM_HTTP_PORT;
165 	}
166 
167 	/**
168 	 * Get the namespace and replace '\' by '/' if necessary
169 	 * default: {@value WmiHelper#DEFAULT_NAMESPACE} if null
170 	 * @param namespace the provided namespace
171 	 *
172 	 * @return
173 	 */
174 	public static String buildNamespace(final String namespace) {
175 		final String cleanNamespace = namespace != null ? namespace.replaceAll("\\s", Utils.EMPTY) : Utils.EMPTY;
176 
177 		final String usedNamespace = Utils.isNotBlank(cleanNamespace) ? cleanNamespace : WmiHelper.DEFAULT_NAMESPACE;
178 
179 		return usedNamespace.replace('\\', '/');
180 	}
181 
182 	/**
183 	 * Build the WSMan URL endpoint.
184 	 *
185 	 * @param endpoint the endpoint in form of protocol://hostname:port (with protocol in HTTP or HTTPS).
186 	 *
187 	 * @return The external form of the endpoint URL
188 	 */
189 	private static String buildWSManEndpoint(final String endpoint) {
190 		try {
191 			return new URL(String.format("%s/wsman", endpoint)).toExternalForm();
192 		} catch (final MalformedURLException e) {
193 			throw new IllegalArgumentException(String.format("endpoint %s is invalid.", endpoint), e);
194 		}
195 	}
196 
197 	@Override
198 	public int hashCode() {
199 		final int prime = 31;
200 		int result = 1;
201 		result = prime * result + Arrays.hashCode(password);
202 		result = prime * result + Objects.hash(endpoint, namespace, rawUsername);
203 		return result;
204 	}
205 
206 	@Override
207 	public boolean equals(final Object obj) {
208 		if (this == obj) {
209 			return true;
210 		}
211 		if (obj == null) {
212 			return false;
213 		}
214 		if (!(obj instanceof WinRMEndpoint)) {
215 			return false;
216 		}
217 		final WinRMEndpoint other = (WinRMEndpoint) obj;
218 		return (
219 			Objects.equals(endpoint, other.endpoint) &&
220 			Objects.equals(namespace, other.namespace) &&
221 			Arrays.equals(password, other.password) &&
222 			Objects.equals(rawUsername, other.rawUsername)
223 		);
224 	}
225 
226 	@Override
227 	public String toString() {
228 		return new StringBuilder()
229 			.append("WinRMEndpoint [")
230 			.append("endpoint=")
231 			.append(endpoint)
232 			.append(", domain=")
233 			.append(domain)
234 			.append(", username=")
235 			.append(username)
236 			.append(", namespace=")
237 			.append(namespace)
238 			.append("]")
239 			.toString();
240 	}
241 }