001
014
015 package com.liferay.portal.util;
016
017 import com.liferay.portal.json.JSONObjectImpl;
018 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
019 import com.liferay.portal.kernel.cluster.ClusterNode;
020 import com.liferay.portal.kernel.cluster.ClusterNodeResponse;
021 import com.liferay.portal.kernel.cluster.ClusterNodeResponses;
022 import com.liferay.portal.kernel.cluster.ClusterRequest;
023 import com.liferay.portal.kernel.cluster.FutureClusterResponses;
024 import com.liferay.portal.kernel.json.JSONObject;
025 import com.liferay.portal.kernel.license.util.LicenseManagerUtil;
026 import com.liferay.portal.kernel.log.Log;
027 import com.liferay.portal.kernel.log.LogFactoryUtil;
028 import com.liferay.portal.kernel.util.ArrayUtil;
029 import com.liferay.portal.kernel.util.Base64;
030 import com.liferay.portal.kernel.util.CharPool;
031 import com.liferay.portal.kernel.util.ClassLoaderUtil;
032 import com.liferay.portal.kernel.util.Constants;
033 import com.liferay.portal.kernel.util.ContentTypes;
034 import com.liferay.portal.kernel.util.FileUtil;
035 import com.liferay.portal.kernel.util.GetterUtil;
036 import com.liferay.portal.kernel.util.Http;
037 import com.liferay.portal.kernel.util.MethodHandler;
038 import com.liferay.portal.kernel.util.MethodKey;
039 import com.liferay.portal.kernel.util.ParamUtil;
040 import com.liferay.portal.kernel.util.ReleaseInfo;
041 import com.liferay.portal.kernel.util.StringPool;
042 import com.liferay.portal.kernel.util.StringUtil;
043 import com.liferay.portal.kernel.util.Validator;
044 import com.liferay.util.Encryptor;
045
046 import java.io.File;
047 import java.io.InputStream;
048
049 import java.net.Inet4Address;
050 import java.net.InetAddress;
051 import java.net.NetworkInterface;
052 import java.net.URI;
053 import java.net.URL;
054
055 import java.security.Key;
056 import java.security.KeyFactory;
057 import java.security.PublicKey;
058 import java.security.SecureRandom;
059 import java.security.spec.X509EncodedKeySpec;
060
061 import java.util.Arrays;
062 import java.util.Collections;
063 import java.util.HashMap;
064 import java.util.HashSet;
065 import java.util.Iterator;
066 import java.util.List;
067 import java.util.Map;
068 import java.util.Set;
069 import java.util.TreeMap;
070 import java.util.concurrent.TimeUnit;
071
072 import javax.crypto.KeyGenerator;
073
074 import javax.servlet.http.HttpServletRequest;
075
076 import org.apache.commons.io.IOUtils;
077 import org.apache.http.HttpEntity;
078 import org.apache.http.HttpHost;
079 import org.apache.http.HttpResponse;
080 import org.apache.http.auth.AuthScope;
081 import org.apache.http.auth.UsernamePasswordCredentials;
082 import org.apache.http.client.CredentialsProvider;
083 import org.apache.http.client.HttpClient;
084 import org.apache.http.client.methods.HttpPost;
085 import org.apache.http.conn.HttpClientConnectionManager;
086 import org.apache.http.entity.ByteArrayEntity;
087 import org.apache.http.impl.client.BasicCredentialsProvider;
088 import org.apache.http.impl.client.HttpClientBuilder;
089 import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
090
091
094 public class LicenseUtil {
095
096 public static final String LICENSE_REPOSITORY_DIR =
097 PropsValues.LIFERAY_HOME.concat("/data/license");
098
099 public static final String LICENSE_SERVER_URL = GetterUtil.get(
100 PropsUtil.get("license.server.url"), "https:
101
102 public static Map<String, String> getClusterServerInfo(String clusterNodeId)
103 throws Exception {
104
105 ClusterNode localClusterNode =
106 ClusterExecutorUtil.getLocalClusterNode();
107
108 String localClusterNodeId = localClusterNode.getClusterNodeId();
109
110 if (clusterNodeId.equals(localClusterNodeId)) {
111 return getServerInfo();
112 }
113
114 List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();
115
116 ClusterNode clusterNode = null;
117
118 for (ClusterNode curClusterNode : clusterNodes) {
119 String curClusterNodeId = curClusterNode.getClusterNodeId();
120
121 if (curClusterNodeId.equals(clusterNodeId)) {
122 clusterNode = curClusterNode;
123
124 break;
125 }
126 }
127
128 if (clusterNode == null) {
129 return null;
130 }
131
132 try {
133 ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
134 _getServerInfoMethodHandler, clusterNodeId);
135
136 FutureClusterResponses futureClusterResponses =
137 ClusterExecutorUtil.execute(clusterRequest);
138
139 ClusterNodeResponses clusterNodeResponses =
140 futureClusterResponses.get(20000, TimeUnit.MILLISECONDS);
141
142 ClusterNodeResponse clusterNodeResponse =
143 clusterNodeResponses.getClusterResponse(
144 clusterNode.getClusterNodeId());
145
146 return (Map<String, String>)clusterNodeResponse.getResult();
147 }
148 catch (Exception e) {
149 _log.error(e, e);
150
151 throw e;
152 }
153 }
154
155
158 @Deprecated
159 public static String getHostName() {
160 return PortalUtil.getComputerName();
161 }
162
163 public static Set<String> getIpAddresses() {
164 if (_ipAddresses != null) {
165 return new HashSet<>(_ipAddresses);
166 }
167
168 _ipAddresses = new HashSet<>();
169
170 try {
171 List<NetworkInterface> networkInterfaces = Collections.list(
172 NetworkInterface.getNetworkInterfaces());
173
174 for (NetworkInterface networkInterface : networkInterfaces) {
175 List<InetAddress> inetAddresses = Collections.list(
176 networkInterface.getInetAddresses());
177
178 for (InetAddress inetAddress : inetAddresses) {
179 if (inetAddress.isLinkLocalAddress() ||
180 inetAddress.isLoopbackAddress() ||
181 !(inetAddress instanceof Inet4Address)) {
182
183 continue;
184 }
185
186 _ipAddresses.add(inetAddress.getHostAddress());
187 }
188 }
189 }
190 catch (Exception e) {
191 _log.error("Unable to read local server's IP addresses");
192
193 _log.error(e, e);
194 }
195
196 return new HashSet<>(_ipAddresses);
197 }
198
199 public static Set<String> getMacAddresses() {
200 if (_macAddresses != null) {
201 return new HashSet<>(_macAddresses);
202 }
203
204 _macAddresses = new HashSet<>();
205
206 try {
207 List<NetworkInterface> networkInterfaces = Collections.list(
208 NetworkInterface.getNetworkInterfaces());
209
210 for (NetworkInterface networkInterface : networkInterfaces) {
211 byte[] hardwareAddress = networkInterface.getHardwareAddress();
212
213 if (ArrayUtil.isEmpty(hardwareAddress)) {
214 continue;
215 }
216
217 StringBuilder sb = new StringBuilder(
218 (hardwareAddress.length * 3) - 1);
219
220 String hexString = StringUtil.bytesToHexString(hardwareAddress);
221
222 for (int i = 0; i < hexString.length(); i += 2) {
223 if (i != 0) {
224 sb.append(CharPool.COLON);
225 }
226
227 sb.append(Character.toLowerCase(hexString.charAt(i)));
228 sb.append(Character.toLowerCase(hexString.charAt(i + 1)));
229 }
230
231 _macAddresses.add(sb.toString());
232 }
233 }
234 catch (Exception e) {
235 _log.error("Unable to read local server's MAC addresses");
236
237 _log.error(e, e);
238 }
239
240 return new HashSet<>(_macAddresses);
241 }
242
243 public static byte[] getServerIdBytes() throws Exception {
244 if (_serverIdBytes != null) {
245 return _serverIdBytes;
246 }
247
248 File serverIdFile = new File(
249 LICENSE_REPOSITORY_DIR + "/server/serverId");
250
251 if (!serverIdFile.exists()) {
252 return new byte[0];
253 }
254
255 _serverIdBytes = FileUtil.getBytes(serverIdFile);
256
257 return _serverIdBytes;
258 }
259
260 public static Map<String, String> getServerInfo() {
261 Map<String, String> serverInfo = new HashMap<>();
262
263 serverInfo.put("hostName", PortalUtil.getComputerName());
264 serverInfo.put("ipAddresses", StringUtil.merge(getIpAddresses()));
265 serverInfo.put("macAddresses", StringUtil.merge(getMacAddresses()));
266
267 return serverInfo;
268 }
269
270 public static void registerOrder(HttpServletRequest request) {
271 String orderUuid = ParamUtil.getString(request, "orderUuid");
272 String productEntryName = ParamUtil.getString(
273 request, "productEntryName");
274 int maxServers = ParamUtil.getInteger(request, "maxServers");
275
276 List<ClusterNode> clusterNodes = ClusterExecutorUtil.getClusterNodes();
277
278 if ((clusterNodes.size() <= 1) || Validator.isNull(productEntryName) ||
279 Validator.isNull(orderUuid)) {
280
281 Map<String, Object> attributes = registerOrder(
282 orderUuid, productEntryName, maxServers);
283
284 for (Map.Entry<String, Object> entry : attributes.entrySet()) {
285 request.setAttribute(entry.getKey(), entry.getValue());
286 }
287 }
288 else {
289 for (ClusterNode clusterNode : clusterNodes) {
290 boolean register = ParamUtil.getBoolean(
291 request, clusterNode.getClusterNodeId() + "_register");
292
293 if (!register) {
294 continue;
295 }
296
297 try {
298 _registerClusterOrder(
299 request, clusterNode, orderUuid, productEntryName,
300 maxServers);
301 }
302 catch (Exception e) {
303 _log.error(e, e);
304
305 InetAddress inetAddress = clusterNode.getBindInetAddress();
306
307 String message =
308 "Error contacting " + inetAddress.getHostName();
309
310 if (clusterNode.getPortalPort() != -1) {
311 message +=
312 StringPool.COLON + clusterNode.getPortalPort();
313 }
314
315 request.setAttribute(
316 clusterNode.getClusterNodeId() + "_ERROR_MESSAGE",
317 message);
318 }
319 }
320 }
321 }
322
323 public static Map<String, Object> registerOrder(
324 String orderUuid, String productEntryName, int maxServers) {
325
326 Map<String, Object> attributes = new HashMap<>();
327
328 if (Validator.isNull(orderUuid)) {
329 return attributes;
330 }
331
332 try {
333 JSONObject jsonObject = _createRequest(
334 orderUuid, productEntryName, maxServers);
335
336 String response = sendRequest(jsonObject.toString());
337
338 JSONObject responseJSONObject = new JSONObjectImpl(response);
339
340 attributes.put(
341 "ORDER_PRODUCT_ID", responseJSONObject.getString("productId"));
342 attributes.put(
343 "ORDER_PRODUCTS", _getOrderProducts(responseJSONObject));
344
345 String errorMessage = responseJSONObject.getString("errorMessage");
346
347 if (Validator.isNotNull(errorMessage)) {
348 attributes.put("ERROR_MESSAGE", errorMessage);
349
350 return attributes;
351 }
352
353 String licenseXML = responseJSONObject.getString("licenseXML");
354
355 if (Validator.isNotNull(licenseXML)) {
356 LicenseManagerUtil.registerLicense(responseJSONObject);
357
358 attributes.clear();
359 attributes.put(
360 "SUCCESS_MESSAGE",
361 "Your license has been successfully registered.");
362 }
363 }
364 catch (Exception e) {
365 _log.error(e, e);
366
367 attributes.put(
368 "ERROR_MESSAGE",
369 "There was an error contacting " + LICENSE_SERVER_URL);
370 }
371
372 return attributes;
373 }
374
375 public static String sendRequest(String request) throws Exception {
376 HttpClient httpClient = null;
377
378 HttpClientConnectionManager httpClientConnectionManager =
379 new BasicHttpClientConnectionManager();
380
381 try {
382 HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
383
384 httpClientBuilder.setConnectionManager(httpClientConnectionManager);
385
386 String serverURL = LICENSE_SERVER_URL;
387
388 if (!serverURL.endsWith(StringPool.SLASH)) {
389 serverURL += StringPool.SLASH;
390 }
391
392 serverURL += "osb-portlet/license";
393
394 URI uri = new URI(serverURL);
395
396 HttpPost httpPost = new HttpPost(uri);
397
398 CredentialsProvider credentialsProvider =
399 new BasicCredentialsProvider();
400
401 HttpHost proxyHttpHost = null;
402
403 if (Validator.isNotNull(_PROXY_URL)) {
404 if (_log.isInfoEnabled()) {
405 _log.info(
406 "Using proxy " + _PROXY_URL + StringPool.COLON +
407 _PROXY_PORT);
408 }
409
410 proxyHttpHost = new HttpHost(_PROXY_URL, _PROXY_PORT);
411
412 if (Validator.isNotNull(_PROXY_USER_NAME)) {
413 credentialsProvider.setCredentials(
414 new AuthScope(_PROXY_URL, _PROXY_PORT),
415 new UsernamePasswordCredentials(
416 _PROXY_USER_NAME, _PROXY_PASSWORD));
417 }
418 }
419
420 httpClientBuilder.setDefaultCredentialsProvider(
421 credentialsProvider);
422 httpClientBuilder.setProxy(proxyHttpHost);
423
424 httpClient = httpClientBuilder.build();
425
426 ByteArrayEntity byteArrayEntity = new ByteArrayEntity(
427 _encryptRequest(serverURL, request));
428
429 byteArrayEntity.setContentType(ContentTypes.APPLICATION_JSON);
430
431 httpPost.setEntity(byteArrayEntity);
432
433 HttpResponse httpResponse = httpClient.execute(httpPost);
434
435 HttpEntity httpEntity = httpResponse.getEntity();
436
437 String response = _decryptResponse(
438 serverURL, httpEntity.getContent());
439
440 if (_log.isDebugEnabled()) {
441 _log.debug("Server response: " + response);
442 }
443
444 if (Validator.isNull(response)) {
445 throw new Exception("Server response is null");
446 }
447
448 return response;
449 }
450 finally {
451 if (httpClient != null) {
452 httpClientConnectionManager.shutdown();
453 }
454 }
455 }
456
457 public static void writeServerProperties(byte[] serverIdBytes)
458 throws Exception {
459
460 File serverIdFile = new File(
461 LICENSE_REPOSITORY_DIR + "/server/serverId");
462
463 FileUtil.write(serverIdFile, serverIdBytes);
464 }
465
466 private static JSONObject _createRequest(
467 String orderUuid, String productEntryName, int maxServers)
468 throws Exception {
469
470 JSONObject jsonObject = new JSONObjectImpl();
471
472 jsonObject.put("version", 1);
473 jsonObject.put("orderUuid", orderUuid);
474 jsonObject.put("liferayVersion", ReleaseInfo.getBuildNumber());
475
476 if (Validator.isNull(productEntryName)) {
477 jsonObject.put(Constants.CMD, "QUERY");
478 }
479 else {
480 jsonObject.put(Constants.CMD, "REGISTER");
481
482 if (productEntryName.startsWith("basic")) {
483 jsonObject.put("productEntryName", "basic");
484
485 if (productEntryName.equals("basic-cluster")) {
486 jsonObject.put("cluster", true);
487 jsonObject.put("maxServers", maxServers);
488 }
489 else if (productEntryName.startsWith("basic-")) {
490 String[] productNameArray = StringUtil.split(
491 productEntryName, StringPool.DASH);
492
493 if (productNameArray.length >= 3) {
494 jsonObject.put("offeringEntryId", productNameArray[1]);
495 jsonObject.put("clusterId", productNameArray[2]);
496 }
497 }
498 }
499 else {
500 jsonObject.put("productEntryName", productEntryName);
501 }
502
503 jsonObject.put("hostName", PortalUtil.getComputerName());
504 jsonObject.put("ipAddresses", StringUtil.merge(getIpAddresses()));
505 jsonObject.put("macAddresses", StringUtil.merge(getMacAddresses()));
506 jsonObject.put("serverId", com.liferay.portal.license.LicenseManager.getServerId());
507 }
508
509 return jsonObject;
510 }
511
512 private static String _decryptResponse(
513 String serverURL, InputStream inputStream)
514 throws Exception {
515
516 if (serverURL.startsWith(Http.HTTPS)) {
517 return StringUtil.read(inputStream);
518 }
519
520 byte[] bytes = IOUtils.toByteArray(inputStream);
521
522 if ((bytes == null) || (bytes.length <= 0)) {
523 return null;
524 }
525
526 bytes = Encryptor.decryptUnencodedAsBytes(_symmetricKey, bytes);
527
528 return new String(bytes, StringPool.UTF8);
529 }
530
531 private static byte[] _encryptRequest(String serverURL, String request)
532 throws Exception {
533
534 byte[] bytes = request.getBytes(StringPool.UTF8);
535
536 if (serverURL.startsWith(Http.HTTPS)) {
537 return bytes;
538 }
539
540 JSONObject jsonObject = new JSONObjectImpl();
541
542 bytes = Encryptor.encryptUnencoded(_symmetricKey, bytes);
543
544 jsonObject.put("content", Base64.objectToString(bytes));
545 jsonObject.put("key", _encryptedSymmetricKey);
546
547 return jsonObject.toString().getBytes(StringPool.UTF8);
548 }
549
550 private static Map<String, String> _getOrderProducts(
551 JSONObject jsonObject) {
552
553 JSONObject productsJSONObject = jsonObject.getJSONObject(
554 "productsJSONObject");
555
556 if (productsJSONObject == null) {
557 return null;
558 }
559
560 Map<String, String> sortedMap = new TreeMap<>(
561 String.CASE_INSENSITIVE_ORDER);
562
563 Iterator<String> itr = productsJSONObject.keys();
564
565 while (itr.hasNext()) {
566 String key = itr.next();
567
568 sortedMap.put(key, productsJSONObject.getString(key));
569 }
570
571 return sortedMap;
572 }
573
574 private static void _initKeys() {
575 ClassLoader classLoader = ClassLoaderUtil.getPortalClassLoader();
576
577 if ((classLoader == null) || (_encryptedSymmetricKey != null)) {
578 return;
579 }
580
581 try {
582 URL url = classLoader.getResource(
583 "com/liferay/portal/license/public.key");
584
585 byte[] bytes = IOUtils.toByteArray(url.openStream());
586
587 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
588 bytes);
589
590 KeyFactory keyFactory = KeyFactory.getInstance("RSA");
591
592 PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
593
594 KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
595
596 keyGenerator.init(128, new SecureRandom());
597
598 _symmetricKey = keyGenerator.generateKey();
599
600 byte[] encryptedSymmetricKey = Encryptor.encryptUnencoded(
601 publicKey, _symmetricKey.getEncoded());
602
603 _encryptedSymmetricKey = Base64.objectToString(
604 encryptedSymmetricKey);
605 }
606 catch (Exception e) {
607 _log.error(e, e);
608 }
609 }
610
611 private static void _registerClusterOrder(
612 HttpServletRequest request, ClusterNode clusterNode,
613 String orderUuid, String productEntryName, int maxServers)
614 throws Exception {
615
616 MethodHandler methodHandler = new MethodHandler(
617 _registerOrderMethodKey, orderUuid, productEntryName, maxServers);
618
619 ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
620 methodHandler, clusterNode.getClusterNodeId());
621
622 FutureClusterResponses futureClusterResponses =
623 ClusterExecutorUtil.execute(clusterRequest);
624
625 ClusterNodeResponses clusterNodeResponses = futureClusterResponses.get(
626 20000, TimeUnit.MILLISECONDS);
627
628 ClusterNodeResponse clusterNodeResponse =
629 clusterNodeResponses.getClusterResponse(
630 clusterNode.getClusterNodeId());
631
632 Map<String, Object> attributes =
633 (Map<String, Object>)clusterNodeResponse.getResult();
634
635 for (Map.Entry<String, Object> entry : attributes.entrySet()) {
636 request.setAttribute(
637 clusterNode.getClusterNodeId() + StringPool.UNDERLINE +
638 entry.getKey(),
639 entry.getValue());
640 }
641 }
642
643 private static final String _PROXY_PASSWORD = GetterUtil.getString(
644 PropsUtil.get("license.proxy.password"));
645
646 private static final int _PROXY_PORT = GetterUtil.getInteger(
647 PropsUtil.get("license.proxy.port"), 80);
648
649 private static final String _PROXY_URL = PropsUtil.get("license.proxy.url");
650
651 private static final String _PROXY_USER_NAME = GetterUtil.getString(
652 PropsUtil.get("license.proxy.username"));
653
654 private static final Log _log = LogFactoryUtil.getLog(LicenseUtil.class);
655
656 private static String _encryptedSymmetricKey;
657 private static final MethodHandler _getServerInfoMethodHandler =
658 new MethodHandler(new MethodKey(LicenseUtil.class, "getServerInfo"));
659 private static Set<String> _ipAddresses;
660 private static Set<String> _macAddresses;
661 private static final MethodKey _registerOrderMethodKey = new MethodKey(
662 LicenseUtil.class, "registerOrder", String.class, String.class,
663 int.class);
664 private static byte[] _serverIdBytes;
665 private static Key _symmetricKey;
666
667 static {
668 _initKeys();
669 }
670
671 }