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