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