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