All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.portal.license.util.LicenseUtil Maven / Gradle / Ivy

There is a newer version: 7.0.0-nightly
Show newest version
/**
 * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.portal.license.util;

import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
import com.liferay.portal.kernel.cluster.ClusterNode;
import com.liferay.portal.kernel.cluster.ClusterNodeResponse;
import com.liferay.portal.kernel.cluster.ClusterNodeResponses;
import com.liferay.portal.kernel.cluster.ClusterRequest;
import com.liferay.portal.kernel.cluster.FutureClusterResponses;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.Base64;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.Constants;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.Http;
import com.liferay.portal.kernel.util.MethodHandler;
import com.liferay.portal.kernel.util.MethodKey;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.ReleaseInfo;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.util.ClassLoaderUtil;
import com.liferay.portal.util.PortalUtil;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.util.PropsValues;
import com.liferay.util.Encryptor;

import java.io.File;
import java.io.InputStream;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URI;
import java.net.URL;

import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.X509EncodedKeySpec;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.KeyGenerator;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpParams;

/**
 * @author Amos Fong
 */
public class LicenseUtil {

	public static final String LICENSE_REPOSITORY_DIR =
		PropsValues.LIFERAY_HOME.concat("/data/license");

	public static final String LICENSE_SERVER_URL = GetterUtil.get(
		PropsUtil.get("license.server.url"), "https://www.liferay.com");

	public static Map getClusterServerInfo(String clusterNodeId)
		throws Exception {

		List clusterNodes = ClusterExecutorUtil.getClusterNodes();

		ClusterNode clusterNode = null;

		for (ClusterNode curClusterNode : clusterNodes) {
			String curClusterNodeId = curClusterNode.getClusterNodeId();

			if (curClusterNodeId.equals(clusterNodeId)) {
				clusterNode = curClusterNode;

				break;
			}
		}

		if (clusterNode == null) {
			return null;
		}

		try {
			if (clusterNode.equals(ClusterExecutorUtil.getLocalClusterNode())) {
				return getServerInfo();
			}

			ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
				_getServerInfoMethodHandler, clusterNodeId);

			FutureClusterResponses futureClusterResponses =
				ClusterExecutorUtil.execute(clusterRequest);

			ClusterNodeResponses clusterNodeResponses =
				futureClusterResponses.get(20000, TimeUnit.MILLISECONDS);

			ClusterNodeResponse clusterNodeResponse =
				clusterNodeResponses.getClusterResponse(clusterNode);

			return (Map)clusterNodeResponse.getResult();
		}
		catch (Exception e) {
			_log.error(e, e);

			throw e;
		}
	}

	/**
	 * @deprecated As of 6.2.0, replaced by {@link PortalUtil#getComputerName()}
	 */
	public static String getHostName() {
		return PortalUtil.getComputerName();
	}

	public static Set getIpAddresses() {
		if (_ipAddresses != null) {
			return new HashSet(_ipAddresses);
		}

		_ipAddresses = new HashSet();

		try {
			List networkInterfaces = Collections.list(
				NetworkInterface.getNetworkInterfaces());

			for (NetworkInterface networkInterface : networkInterfaces) {
				List inetAddresses = Collections.list(
					networkInterface.getInetAddresses());

				for (InetAddress inetAddress : inetAddresses) {
					if (inetAddress.isLinkLocalAddress() ||
						inetAddress.isLoopbackAddress() ||
						!(inetAddress instanceof Inet4Address)) {

						continue;
					}

					_ipAddresses.add(inetAddress.getHostAddress());
				}
			}
		}
		catch (Exception e) {
			_log.error("Unable to read local server's IP addresses");

			_log.error(e, e);
		}

		return new HashSet(_ipAddresses);
	}

	public static Set getMacAddresses() {
		if (_macAddresses != null) {
			return new HashSet(_macAddresses);
		}

		Set macAddresses = new HashSet();

		String osName = System.getProperty("os.name");

		String executable = null;
		String arguments = null;

		if (StringUtil.startsWith(osName, "win")) {
			executable = "ipconfig";
			arguments = "/all";
		}
		else {
			if (StringUtil.startsWith(osName, "aix")) {
				executable = "netstat";
				arguments = "-ina";
			}
			else {
				executable = "ifconfig";
				arguments = "-a";
			}

			File sbinDir = new File("/sbin", executable);

			if (sbinDir.exists()) {
				executable = "/sbin/".concat(executable);
			}
		}

		try {
			Runtime runtime = Runtime.getRuntime();

			Process process = runtime.exec(
				new String[] {executable, arguments});

			macAddresses = getMacAddresses(osName, process.getInputStream());
		}
		catch (Exception e) {
			_log.error(e, e);
		}

		_macAddresses = macAddresses;

		return new HashSet(macAddresses);
	}

	public static Set getMacAddresses(
			String osName, InputStream processInputStream)
		throws Exception {

		Set macAddresses = new HashSet();

		Pattern macAddressPattern = _macAddressPattern1;

		if (StringUtil.startsWith(osName, "aix")) {
			macAddressPattern = _macAddressPattern2;
		}

		String processOutput = StringUtil.read(processInputStream);

		String[] lines = StringUtil.split(processOutput, CharPool.NEW_LINE);

		for (String line : lines) {
			Matcher matcher = macAddressPattern.matcher(line);

			if (!matcher.find()) {
				continue;
			}

			String macAddress = matcher.group(1);

			macAddress = StringUtil.toLowerCase(macAddress);
			macAddress = macAddress.replace(CharPool.DASH, CharPool.COLON);
			macAddress = macAddress.replace(CharPool.PERIOD, CharPool.COLON);

			StringBuilder sb = new StringBuilder(17);

			sb.append(macAddress);

			for (int i = 1; i < 5; ++i) {
				int pos = (i * 3) - 1;

				if (sb.charAt(pos) != CharPool.COLON) {
					sb.insert((i - 1) * 3, CharPool.NUMBER_0);
				}
			}

			if (sb.length() < 17) {
				sb.insert(15, CharPool.NUMBER_0);
			}

			macAddress = sb.toString();

			macAddresses.add(macAddress);
		}

		return macAddresses;
	}

	public static byte[] getServerIdBytes() throws Exception {
		if (_serverIdBytes != null) {
			return _serverIdBytes;
		}

		File serverIdFile = new File(
			LICENSE_REPOSITORY_DIR + "/server/serverId");

		if (!serverIdFile.exists()) {
			return new byte[0];
		}

		_serverIdBytes = FileUtil.getBytes(serverIdFile);

		return _serverIdBytes;
	}

	public static Map getServerInfo() {
		Map serverInfo = new HashMap();

		serverInfo.put("hostName", PortalUtil.getComputerName());
		serverInfo.put("ipAddresses", StringUtil.merge(getIpAddresses()));
		serverInfo.put("macAddresses", StringUtil.merge(getMacAddresses()));

		return serverInfo;
	}

	public static void registerOrder(HttpServletRequest request) {
		String orderUuid = ParamUtil.getString(request, "orderUuid");
		String productEntryName = ParamUtil.getString(
			request, "productEntryName");
		int maxServers = ParamUtil.getInteger(request, "maxServers");

		List clusterNodes = ClusterExecutorUtil.getClusterNodes();

		if ((clusterNodes.size() <= 1) || Validator.isNull(productEntryName) ||
			Validator.isNull(orderUuid)) {

			Map attributes = registerOrder(
				orderUuid, productEntryName, maxServers);

			for (Map.Entry entry : attributes.entrySet()) {
				request.setAttribute(entry.getKey(), entry.getValue());
			}
		}
		else {
			for (ClusterNode clusterNode : clusterNodes) {
				boolean register = ParamUtil.getBoolean(
					request, clusterNode.getClusterNodeId() + "_register");

				if (!register) {
					continue;
				}

				try {
					_registerClusterOrder(
						request, clusterNode, orderUuid, productEntryName,
						maxServers);
				}
				catch (Exception e) {
					_log.error(e, e);

					InetAddress inetAddress = clusterNode.getInetAddress();

					String message =
						"Error contacting " + inetAddress.getHostName();

					if (clusterNode.getPort() != -1) {
						message += StringPool.COLON + clusterNode.getPort();
					}

					request.setAttribute(
						clusterNode.getClusterNodeId() + "_ERROR_MESSAGE",
						message);
				}
			}
		}
	}

	public static Map registerOrder(
		String orderUuid, String productEntryName, int maxServers) {

		Map attributes = new HashMap();

		if (Validator.isNull(orderUuid)) {
			return attributes;
		}

		try {
			JSONObject jsonObject = _createRequest(
				orderUuid, productEntryName, maxServers);

			String response = sendRequest(jsonObject.toString());

			JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject(
				response);

			attributes.put(
				"ORDER_PRODUCT_ID", responseJSONObject.getString("productId"));
			attributes.put(
				"ORDER_PRODUCTS", _getOrderProducts(responseJSONObject));

			String errorMessage = responseJSONObject.getString("errorMessage");

			if (Validator.isNotNull(errorMessage)) {
				attributes.put("ERROR_MESSAGE", errorMessage);

				return attributes;
			}

			String licenseXML = responseJSONObject.getString("licenseXML");

			if (Validator.isNotNull(licenseXML)) {
				LicenseManagerUtil.registerLicense(responseJSONObject);

				attributes.clear();
				attributes.put(
					"SUCCESS_MESSAGE",
					"Your license has been successfully registered.");
			}
		}
		catch (Exception e) {
			_log.error(e, e);

			attributes.put(
				"ERROR_MESSAGE",
				"There was an error contacting " + LICENSE_SERVER_URL);
		}

		return attributes;
	}

	public static String sendRequest(String request) throws Exception {
		DefaultHttpClient defaultHttpClient = new DefaultHttpClient();

		try {
			String serverURL = LICENSE_SERVER_URL;

			if (!serverURL.endsWith(StringPool.SLASH)) {
				serverURL += StringPool.SLASH;
			}

			serverURL += "osb-portlet/license";

			URI uri = new URI(serverURL);

			HttpPost httpPost = new HttpPost(uri);

			if (Validator.isNotNull(_PROXY_URL)) {
				if (_log.isInfoEnabled()) {
					_log.info(
						"Using proxy " + _PROXY_URL + StringPool.COLON +
							_PROXY_PORT);
				}

				HttpHost httpHost = new HttpHost(_PROXY_URL, _PROXY_PORT);

				HttpParams httpParams = defaultHttpClient.getParams();

				httpParams.setParameter(
					ConnRoutePNames.DEFAULT_PROXY, httpHost);

				if (Validator.isNotNull(_PROXY_USER_NAME)) {
					CredentialsProvider credentialsProvider =
						defaultHttpClient.getCredentialsProvider();

					credentialsProvider.setCredentials(
						new AuthScope(_PROXY_URL, _PROXY_PORT),
						new UsernamePasswordCredentials(
							_PROXY_USER_NAME, _PROXY_PASSWORD));
				}
			}

			ByteArrayEntity byteArrayEntity = new ByteArrayEntity(
				_encryptRequest(serverURL, request));

			byteArrayEntity.setContentType(ContentTypes.APPLICATION_JSON);

			httpPost.setEntity(byteArrayEntity);

			HttpResponse httpResponse = defaultHttpClient.execute(httpPost);

			HttpEntity httpEntity = httpResponse.getEntity();

			String response = _decryptResponse(
				serverURL, httpEntity.getContent());

			if (_log.isDebugEnabled()) {
				_log.debug("Server response: " + response);
			}

			if (Validator.isNull(response)) {
				throw new Exception("Server response is null");
			}

			return response;
		}
		finally {
			ClientConnectionManager clientConnectionManager =
				defaultHttpClient.getConnectionManager();

			clientConnectionManager.shutdown();
		}
	}

	public static void writeServerProperties(byte[] serverIdBytes)
		throws Exception {

		File serverIdFile = new File(
			LICENSE_REPOSITORY_DIR + "/server/serverId");

		FileUtil.write(serverIdFile, serverIdBytes);
	}

	private static JSONObject _createRequest(
			String orderUuid, String productEntryName, int maxServers)
		throws Exception {

		JSONObject jsonObject = JSONFactoryUtil.createJSONObject();

		jsonObject.put("version", 1);
		jsonObject.put("orderUuid", orderUuid);
		jsonObject.put("liferayVersion", ReleaseInfo.getBuildNumber());

		if (Validator.isNull(productEntryName)) {
			jsonObject.put(Constants.CMD, "QUERY");
		}
		else {
			jsonObject.put(Constants.CMD, "REGISTER");

			if (productEntryName.startsWith("basic")) {
				jsonObject.put("productEntryName", "basic");

				if (productEntryName.equals("basic-cluster")) {
					jsonObject.put("cluster", true);
					jsonObject.put("maxServers", maxServers);
				}
				else if (productEntryName.startsWith("basic-")) {
					String[] productNameArray = StringUtil.split(
						productEntryName, StringPool.DASH);

					if (productNameArray.length >= 3) {
						jsonObject.put("offeringEntryId", productNameArray[1]);
						jsonObject.put("clusterId", productNameArray[2]);
					}
				}
			}
			else {
				jsonObject.put("productEntryName", productEntryName);
			}

			jsonObject.put("hostName", PortalUtil.getComputerName());
			jsonObject.put("ipAddresses", StringUtil.merge(getIpAddresses()));
			jsonObject.put("macAddresses", StringUtil.merge(getMacAddresses()));
			jsonObject.put("serverId", com.liferay.portal.license.LicenseManager.getServerId());
		}

		return jsonObject;
	}

	private static String _decryptResponse(
			String serverURL, InputStream inputStream)
		throws Exception {

		if (serverURL.startsWith(Http.HTTPS)) {
			return StringUtil.read(inputStream);
		}

		byte[] bytes = IOUtils.toByteArray(inputStream);

		if ((bytes == null) || (bytes.length <= 0)) {
			return null;
		}

		bytes = Encryptor.decryptUnencodedAsBytes(_symmetricKey, bytes);

		return new String(bytes, StringPool.UTF8);
	}

	private static byte[] _encryptRequest(String serverURL, String request)
		throws Exception {

		byte[] bytes = request.getBytes(StringPool.UTF8);

		if (serverURL.startsWith(Http.HTTPS)) {
			return bytes;
		}

		JSONObject jsonObject = JSONFactoryUtil.createJSONObject();

		bytes = Encryptor.encryptUnencoded(_symmetricKey, bytes);

		jsonObject.put("content", Base64.objectToString(bytes));
		jsonObject.put("key", _encryptedSymmetricKey);

		return jsonObject.toString().getBytes(StringPool.UTF8);
	}

	private static Map _getOrderProducts(
		JSONObject jsonObject) {

		JSONObject productsJSONObject = jsonObject.getJSONObject(
			"productsJSONObject");

		if (productsJSONObject == null) {
			return null;
		}

		Map sortedMap = new TreeMap(
			String.CASE_INSENSITIVE_ORDER);

		Iterator itr = productsJSONObject.keys();

		while (itr.hasNext()) {
			String key = itr.next();

			sortedMap.put(key, productsJSONObject.getString(key));
		}

		return sortedMap;
	}

	private static void _initKeys() {
		ClassLoader classLoader = ClassLoaderUtil.getPortalClassLoader();

		if ((classLoader == null) || (_encryptedSymmetricKey != null)) {
			return;
		}

		try {
			URL url = classLoader.getResource(
				"com/liferay/portal/license/public.key");

			byte[] bytes = IOUtils.toByteArray(url.openStream());

			X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
				bytes);

			KeyFactory keyFactory = KeyFactory.getInstance("RSA");

			PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

			KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");

			keyGenerator.init(128, new SecureRandom());

			_symmetricKey = keyGenerator.generateKey();

			byte[] encryptedSymmetricKey = Encryptor.encryptUnencoded(
				publicKey, _symmetricKey.getEncoded());

			_encryptedSymmetricKey = Base64.objectToString(
				encryptedSymmetricKey);
		}
		catch (Exception e) {
			_log.error(e, e);
		}
	}

	private static void _registerClusterOrder(
			HttpServletRequest request, ClusterNode clusterNode,
			String orderUuid, String productEntryName, int maxServers)
		throws Exception {

		MethodHandler methodHandler = new MethodHandler(
			_registerOrderMethodKey, orderUuid, productEntryName, maxServers);

		ClusterRequest clusterRequest = ClusterRequest.createUnicastRequest(
			methodHandler, clusterNode.getClusterNodeId());

		FutureClusterResponses futureClusterResponses =
			ClusterExecutorUtil.execute(clusterRequest);

		ClusterNodeResponses clusterNodeResponses = futureClusterResponses.get(
			20000, TimeUnit.MILLISECONDS);

		ClusterNodeResponse clusterNodeResponse =
			clusterNodeResponses.getClusterResponse(clusterNode);

		Map attributes =
			(Map)clusterNodeResponse.getResult();

		for (Map.Entry entry : attributes.entrySet()) {
			request.setAttribute(
				clusterNode.getClusterNodeId() + StringPool.UNDERLINE +
					entry.getKey(),
				entry.getValue());
		}
	}

	private static final String _PROXY_PASSWORD = GetterUtil.getString(
		PropsUtil.get("license.proxy.password"));

	private static final int _PROXY_PORT = GetterUtil.getInteger(
		PropsUtil.get("license.proxy.port"), 80);

	private static final String _PROXY_URL = PropsUtil.get("license.proxy.url");

	private static final String _PROXY_USER_NAME = GetterUtil.getString(
		PropsUtil.get("license.proxy.username"));

	private static Log _log = LogFactoryUtil.getLog(LicenseUtil.class);

	private static String _encryptedSymmetricKey;
	private static MethodHandler _getServerInfoMethodHandler =
		new MethodHandler(new MethodKey(LicenseUtil.class, "getServerInfo"));
	private static Set _ipAddresses;
	private static Set _macAddresses;
	private static Pattern _macAddressPattern1 = Pattern.compile(
		"\\s((\\p{XDigit}{1,2}(-|:)){5}(\\p{XDigit}{1,2}))(?:\\s|$)");
	private static Pattern _macAddressPattern2 = Pattern.compile(
		"\\s((\\p{XDigit}{1,2}(\\.)){5}(\\p{XDigit}{1,2}))(?:\\s|$)");
	private static MethodKey _registerOrderMethodKey = new MethodKey(
		LicenseUtil.class, "registerOrder", String.class, String.class,
		int.class);
	private static byte[] _serverIdBytes;
	private static Key _symmetricKey;

	static {
		_initKeys();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy