/******************************************************************************* * Copyright (c) May 18, 2011 Zend Technologies Ltd. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.zend.sdklib.internal.target; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import org.zend.sdklib.logger.Log; import org.zend.sdklib.manager.TargetsManager; import org.zend.sdklib.target.IZendTarget; import org.zend.sdklib.target.LicenseExpiredException; import org.zend.webapi.core.WebApiClient; import org.zend.webapi.core.WebApiException; import org.zend.webapi.core.connection.auth.BasicCredentials; import org.zend.webapi.core.connection.auth.WebApiCredentials; import org.zend.webapi.core.connection.data.SystemInfo; import org.zend.webapi.core.connection.data.values.LicenseInfoStatus; import org.zend.webapi.core.connection.data.values.ServerType; import org.zend.webapi.core.connection.data.values.WebApiVersion; import org.zend.webapi.core.connection.data.values.ZendServerVersion; import org.zend.webapi.core.connection.response.ResponseCode; /** * Represents a target in the environment * * @author Roy, 2011 */ public class ZendTarget implements IZendTarget { public static final String ENCRYPT = "encrypt."; public static final String TEMP = "temp."; public static final String OPERATING_SYSTEM = "operatingSystem"; public static final String SERVER_NAME = "serverName"; private static final String EXTRA = "extra."; private String id; private URL host; private URL defaultServerURL; private String key; private String secretKey; private Properties properties; private boolean isTemporary; /** * Mainly used for loading */ public ZendTarget() { // empty target this.properties = new Properties(); } /** * @param id * @param host * @param key * @param secretKey */ public ZendTarget(String id, URL host, String key, String secretKey) { this(id, host, null, key, secretKey); } /** * @param id * @param host * @param key * @param secretKey * @param temporary */ public ZendTarget(String id, URL host, String key, String secretKey, boolean temporary) { this(id, host, null, key, secretKey, temporary); } /** * @param id * @param host * @param defaultServerURL * @param key * @param secretKey */ public ZendTarget(String id, URL host, URL defaultServerURL, String key, String secretKey) { super(); this.id = id; this.host = host; this.defaultServerURL = defaultServerURL; this.key = key; this.secretKey = secretKey; this.properties = new Properties(); validateTarget(); } public ZendTarget(String id, URL host, URL defaultServerURL, String key, String secretKey, boolean temporary) { this(id, host, defaultServerURL, key, secretKey); this.isTemporary = temporary; } public boolean isTemporary() { return isTemporary; } /** * * @return null or success, or an error message otherwise */ public String validateTarget() { if (id == null || host == null || secretKey == null || key == null || key.length() == 0) { return "Target id, host, key name and secret must not be null."; } // id validation final char f = this.id.charAt(0); if (!Character.isJavaIdentifierStart(f) && !Character.isDigit(f)) { return "Target id must start with valid identifier: letter, number, $ or _"; } for (int i = 1; i < this.id.length(); i++) { char c = this.id.charAt(i); if (!Character.isJavaIdentifierPart(c)) { return "Target id is invalid: " + c; } } return null; } @Override public String getId() { return id; } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getHost() */ @Override public URL getHost() { return host; } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getAppHost() */ @Override public URL getDefaultServerURL() { if (defaultServerURL == null) { defaultServerURL = generateDefaultUrl(); } return defaultServerURL; } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getKey() */ @Override public String getKey() { return key; } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getSecretKey() */ @Override public String getSecretKey() { return secretKey; } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getServerName() */ public String getServerName() { return getProperty(SERVER_NAME); } /** * Set target host * * @param host */ public void setHost(URL host) { this.host = host; } /** * Set default server URL * * @param defaultServerURL */ public void setDefaultServerURL(URL defaultServerURL) { this.defaultServerURL = defaultServerURL; } /** * Set target key * * @param key */ public void setKey(String key) { this.key = key; } /** * Set target secret key * * @param secretKey */ public void setSecretKey(String secretKey) { this.secretKey = secretKey; } public void setServerName(String name) { addProperty(SERVER_NAME, name); } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#getProperty(java.lang.String) */ @Override public synchronized String getProperty(String key) { String value = properties.getProperty(EXTRA + key); if (value != null && key.startsWith(ENCRYPT)) { return decrypt(value); } return value; } /** * Adds an extra property to the target * * @param key * @param value */ public synchronized void addProperty(String key, String value) { if (key.startsWith(ENCRYPT)) { value = convertByteToHex(encrypt(value)); } properties.put(EXTRA + key, value); } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#load(java.io.InputStream) */ @Override public synchronized void load(InputStream is) throws IOException { Properties properties = new Properties(); properties.load(is); this.id = properties.getProperty("_id"); String encrypted = properties.getProperty("_encrypted"); if ("true".equals(encrypted)) { this.secretKey = decrypt(convertHexToByte(properties .getProperty("_secretKey"))); } else { this.secretKey = properties.getProperty("_secretKey"); } this.key = properties.getProperty("_key"); this.host = new URL(properties.getProperty("_host")); String url = properties.getProperty("_defaultServerURL"); if (url != null) { this.defaultServerURL = new URL(url); } final Set<String> stringPropertyNames = properties .stringPropertyNames(); for (String keyName : stringPropertyNames) { if (keyName.startsWith(EXTRA)) { this.properties.put(keyName, properties.getProperty(keyName)); } } } /* * (non-Javadoc) * * @see org.zend.sdklib.target.IZendTarget#store(java.io.OutputStream) */ @Override public synchronized void store(OutputStream os) throws IOException { if (!isTemporary) { Properties properties = new Properties(); properties.put("_id", getId()); properties.put("_key", getKey()); byte[] encryptedKey = encrypt(getSecretKey()); if (encryptedKey != null) { properties.put("_encrypted", "true"); properties.put("_secretKey", convertByteToHex(encryptedKey)); } else { properties.put("_encrypted", "false"); properties.put("_secretKey", getSecretKey()); } properties.put("_host", getHost().toString()); properties.put("_defaultServerURL", getDefaultServerURL() .toString()); properties.putAll(removeTempProperites(this.properties)); properties.store(os, "target properties for " + getId()); } } @Override public boolean connect(WebApiVersion version, ServerType serverType) throws WebApiException, LicenseExpiredException { WebApiCredentials credentials = new BasicCredentials(getKey(), getSecretKey()); try { String hostname = getHost().toString(); WebApiClient client = new WebApiClient(credentials, hostname, SSLContextInitializer.instance.getRestletContext()); if (version != WebApiVersion.UNKNOWN) { client.setCustomVersion(version); } client.setServerType(serverType); final SystemInfo info = client.getSystemInfo(); if (info.getLicenseInfo().getStatus() == LicenseInfoStatus.EXPIRED) { throw new LicenseExpiredException(info.getLicenseInfo() .getValidUntil()); } addProperty("edition", info.getEdition().name()); addProperty(OPERATING_SYSTEM, info.getOperatingSystem()); addProperty("phpVersion", info.getPhpVersion()); addProperty("status", info.getStatus().name()); addProperty(SERVER_VERSION, info.getVersion().getName()); addProperty("supportedApiVersions", info.getSupportedApiVersions() .toString()); } catch (MalformedURLException e) { return false; } catch (final WebApiException e) { final String betterMessage = replaceWebApiMessage(e.getMessage()); if (betterMessage == null) { throw e; } else { throw new WebApiException() { private static final long serialVersionUID = 1L; @Override public ResponseCode getResponseCode() { return e.getResponseCode(); } @Override public String getMessage() { return betterMessage; } }; } } return true; } @Override public boolean connect() throws WebApiException, LicenseExpiredException { return connect(WebApiVersion.UNKNOWN, ServerType.ZEND_SERVER_MANAGER); } @Override public ServerType getServerType() { if (TargetsManager.checkMinVersion(this, ZendServerVersion.v6_0_0)) { return ServerType.ZEND_SERVER; } else { String system = getProperty(OPERATING_SYSTEM); if (system != null) { system = system.toLowerCase(); if ("os400".equals(system) || "aix".equals(system)) { return ServerType.ZEND_SERVER; } } } return ServerType.ZEND_SERVER_MANAGER; } @Override public WebApiVersion getWebApiVersion() { if (TargetsManager.checkMinVersion(this, ZendServerVersion.v6_0_0)) { return WebApiVersion.V1_3; } return WebApiVersion.UNKNOWN; } public boolean equals(Object obj) { if (obj instanceof ZendTarget) { IZendTarget t = (ZendTarget) obj; if (getId().equals(t.getId())) { return true; } } return false; } private String replaceWebApiMessage(String message) { if ("Zend Server Community Edition does not rely on licensing" .equals(message)) { return "Zend Server Community Edition does not support deployment"; } return null; } public String[] getPropertiesKeys() { Set<Object> keyset = properties.keySet(); List<String> result = new ArrayList<String>(); for (Object o : keyset) { String key = (String) o; if (key.startsWith(EXTRA)) { result.add(key.substring(EXTRA.length())); } } return (String[]) result.toArray(new String[result.size()]); } private String decrypt(String secretKey) { return decrypt(convertHexToByte(secretKey)); } private String decrypt(byte[] secretKey) { try { Cipher c = Cipher.getInstance("AES"); SecretKeySpec k = new SecretKeySpec(getSeq(), "AES"); c.init(Cipher.DECRYPT_MODE, k); return new String(c.doFinal(secretKey)); } catch (Exception e) { Log.getInstance().getLogger(this.getClass().getName()).error(e); return null; } } private byte[] encrypt(String secretKey) { try { Cipher cipher = Cipher.getInstance("AES"); SecretKeySpec k = new SecretKeySpec(getSeq(), "AES"); cipher.init(Cipher.ENCRYPT_MODE, k); return cipher.doFinal(secretKey.getBytes()); } catch (Exception e) { Log.getInstance().getLogger(this.getClass().getName()).error(e); return null; } } private byte[] getSeq() { return "[B@10f11b8=$eEew".getBytes(); } private String convertByteToHex(byte[] chars) { String hex = new String(); for (int i = 0; i < chars.length; i++) { String c = Integer.toHexString(0xFF & (int) chars[i]); if (c.length() == 1) { c = "0" + c; } hex += c; } return hex.toString(); } private byte[] convertHexToByte(String hex) { byte[] result = new byte[hex.length() / 2]; int j = 0; for (int i = 0; i < hex.length() - 1; i += 2) { String output = hex.substring(i, (i + 2)); int decimal = Integer.parseInt(output, 16); result[j++] = (byte) decimal; } return result; } private URL generateDefaultUrl() { String system = getProperty(OPERATING_SYSTEM); if (system != null) { system = system.toLowerCase(); try { if ("darwin".equals(system)) { return new URL("http", host.getHost(), 10088, ""); } if ("linux".equals(system)) { return new URL("http", host.getHost(), 80, ""); } if ("os400".equals(system) || "AIX".equals(system)) { String version = getProperty(IZendTarget.SERVER_VERSION); if (version != null && !version.startsWith("6")) { //$NON-NLS-1$ return new URL("http", host.getHost(), 10088, ""); } else { return new URL("http", host.getHost(), 10080, ""); } } } catch (MalformedURLException e) { } } return host; } private Properties removeTempProperites(Properties input) { Properties result = new Properties(); Set<Object> keys = input.keySet(); for (Object key : keys) { if (!((String) key).startsWith(EXTRA + TEMP)) { String value = (String) input.get(key); result.put(key, value); } } return result; } }