/**
* Copyright (c) 2014 EMC Corporation
* All Rights Reserved
*
* This software contains the intellectual property of EMC Corporation
* or is licensed to EMC Corporation from third parties. Use of this
* software and the intellectual property contained therein is expressly
* limited to the terms and conditions of the License Agreement under which
* it is provided by or on behalf of EMC.
*/
package com.emc.storageos.remoterepotool;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.json.simple.parser.JSONParser;
import javax.net.ssl.*;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.*;
import java.net.*;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
public class Main {
private static SSLSocketFactory _sslSocketFactory;
private static Proxy _proxy = Proxy.NO_PROXY;
private static int _timeout = 30000;
private static final int MAXIMUM_REDIRECT_ALLOWED = 10;
private static final String EMC_SSO_AUTH_SERVICE_HOST= "sso.emc.com";
private static final String EMC_SSO_AUTH_SERVICE_TESTHOST= "sso-tst.emc.com";
private static final String EMC_SSO_AUTH_SERVICE_URLPATH = "/authRest/service/auth.json";
private static final String EMC_SSO_DOWNLOAD_SERVICE_HOST= "download.emc.com";
private static final String EMC_SSO_DOWNLOAD_SERVICE_TESTHOST= "download-tst.emc.com";
private static final String EMC_SSO_AUTH_SERVICE_LOGIN_POST_CONTENT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><user><password>{0}</password><username>{1}</username></user>";
private static String _ssohost;
private static String _username;
private static String _password;
private static String _ctsession;
private static Map<String, String> _cookieMap = new HashMap<>();
private static void usage() {
System.out.println("Usage: ");
System.out.println("remoterepotool --hostname <hostname> --imgpath <image path> --user <username> --pass <password>");
}
private static String hostname;
private static String imgUrlPath;
public static void main(String[] args) {
if (args.length != 8) {
usage();
return;
}
int port=443;
for (int i=0; i< args.length; i++){
if(args[i].equals("--hostname")) {
i++;
hostname=args[i];
continue;
}
if(args[i].equals("--imgpath")) {
i++;
imgUrlPath=args[i];
continue;
}
if(args[i].equals("--user")) {
i++;
_username=args[i];
continue;
}
if(args[i].equals("--pass")) {
i++;
_password=args[i];
continue;
}
}
try {
initializeSslContext();
} catch (Exception e) {
System.out.println("error:" + e.getMessage());
e.printStackTrace();
}
try {
if ( hostname.equalsIgnoreCase(EMC_SSO_DOWNLOAD_SERVICE_TESTHOST) ) {
_ssohost = EMC_SSO_AUTH_SERVICE_TESTHOST;
} else if ( hostname.equalsIgnoreCase(EMC_SSO_DOWNLOAD_SERVICE_HOST) ) {
_ssohost = EMC_SSO_AUTH_SERVICE_HOST;
} else {
_ssohost = null;
}
if (_ssohost != null) {
URL loginUrl = new URL("https", _ssohost, EMC_SSO_AUTH_SERVICE_URLPATH);
login(loginUrl, _username, _password);
}
URL imgUrl = new URL("https", hostname, imgUrlPath);
connectImage(imgUrl);
} catch (Exception e) {
System.out.println("error:" + e.getMessage());
e.printStackTrace();
}
}
/**
* Before downloading images from download.emc.com, user needs to login
* EMC SSO service (sso.emc.com) to get authorized session cookie.
* The request:
* URI: http://sso.emc.com/authRest/service/auth.json
* Format: XML
* HTTP Method: POST
* Request Body for customer, partner or lite users:
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?><user><password>##########</password><username>johndoe@acme.com</username></user>
* Request Body for employee
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?><user><password>pin+fob/softtoken</password><username>emp nt</username></user>
*
* Response body:
* 1. Example for successful response:
* {
* "object": {
* "authResult": {
* "status":"SUCCESS",
* "operation":"VALID_USER",
* "token":"AAAAAgABAFBLtr+WcJAh+DJ1Q2GXYiH0PC5+Txuscy1+pU7TRpAcUoyfhNwB55DZwPCZlQwgVpyY+vaOYNblApcSOZ+hEWFzIxj1JtII/ozshY+33ddafg==",
* "userProps":[{"propName":"LAST_NAME","propValue":"[TestFour]"},{"propName":"GIVEN_NAME","propValue":"[AlphaFour]"},{"propName":"UID","propValue":"[1110000003]"},{"propName":"EMC_IDENTITY","propValue":"[C]"}]
* }
* },
* "serviceFault":null
* }
* 2. Example for failure response:
* {
* "object": {
* "authResult": {
* "status": "FAILED",
* "operation": "INVALID_USERNAME_PASSWORD",
* "token": null,
* "userProps": null
* }
* },
* "serviceFault":null
* }
*
* @param username
* @param password
*/
private static void login(URL url, String username, String password) {
System.out.println(username + " is trying to logining at " + url.toString());
try {
HttpURLConnection httpCon = prepareConnection(url);
httpCon.setInstanceFollowRedirects(false);
String loginContent = MessageFormat.format(EMC_SSO_AUTH_SERVICE_LOGIN_POST_CONTENT, password, username);
writePostContent(httpCon, loginContent);
System.out.println("Response code:" + String.valueOf(httpCon.getResponseCode()));
System.out.println("Response size:" + httpCon.getContentLength());
InputStream in = httpCon.getInputStream();
if(in == null) {
throw new IllegalArgumentException("in is null");
}
BufferedReader rd = new BufferedReader(new InputStreamReader(in));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
String s = response.toString();
System.out.println("Response body: " + s);
JSONParser parser = new JSONParser();
JSONObject obj = (JSONObject)parser.parse(s);
JSONObject authObj = (JSONObject)obj.get("object");
JSONObject authResultObj = (JSONObject)authObj.get("authResult");
if (authResultObj.get("status").toString().equalsIgnoreCase("SUCCESS")) {
System.out.println("Succeed to login EMC SSO service");
if (authResultObj.get("token") != null) {
_ctsession = authResultObj.get("token").toString();
System.out.println(_ctsession);
} else {
throw new IllegalArgumentException("Failed to parse ctsession token as expected");
}
} else if (authResultObj.get("status").toString().equalsIgnoreCase("FAILED")) {
JSONObject serviceFaultObj = (JSONObject)obj.get("serviceFault");
String errstr = "";
if (serviceFaultObj != null) {
errstr = "Please contact with EMC customer support. EMC SSO service failed:" + serviceFaultObj.toString();
System.out.println(errstr);
} else {
String operation = authResultObj.get("operation").toString();
errstr= "EMC SSO authentication result is " + operation;
}
System.out.println(errstr);
throw new IllegalArgumentException(errstr);
}
} catch ( Exception e){
throw new IllegalArgumentException(
MessageFormat.format("User {0} failed to login {1}: {2}", username, EMC_SSO_AUTH_SERVICE_URLPATH, e));
}
}
/**
* Initialize the SSL context for connecting to a remote repository
* @throws java.security.NoSuchAlgorithmException
* @throws java.security.KeyManagementException
*/
private static void initializeSslContext() throws NoSuchAlgorithmException, KeyManagementException {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
@Override
public void checkClientTrusted( final X509Certificate[] chain, final String authType ) {
}
@Override
public void checkServerTrusted( final X509Certificate[] chain, final String authType ) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
} };
// Install the all-trusting trust manager
SSLContext sslContext;
sslContext = SSLContext.getInstance( "SSL" );
sslContext.init( null, trustAllCerts, new java.security.SecureRandom() );
// Create an ssl socket factory with our all-trusting manager
_sslSocketFactory = sslContext.getSocketFactory();
}
/**
* Open a URL connection and set the SSL context factory if necessary
* @param url
* @return a connection to the URL
* @throws java.io.IOException
*/
private static HttpURLConnection prepareConnection( URL url ) throws IOException {
HttpURLConnection connection;
connection = (HttpURLConnection) url.openConnection(_proxy);
connection.setConnectTimeout(_timeout);
connection.setReadTimeout(_timeout);
if( url.getProtocol().equalsIgnoreCase("https")) {
((HttpsURLConnection)connection).setSSLSocketFactory(_sslSocketFactory);
}
return connection;
}
/**
* Connect with remote target url for download
* Client needs to read the token from returned JSON object for login request.
* Token aka CTSESSION is one of the important attribute to access any application or rest services that is protected behind RSA.
* For Example: if support zone rest needs to be accessed then use the auth rest service read the token and set the cookie header with the token as shown
* For download request:
* URI: image url
* Format: XML
* HTTP Method: GET
* HTTP Header: CTSESSION="token"
*
* @param url
* @return HttpURLConnection
* @throws RemoteRepositoryException
*/
private static void connectImage(URL url) throws Exception {
HttpURLConnection httpCon = prepareConnection(url);
try {
System.out.println("Connecting to URL " + url.toString());
httpCon.setInstanceFollowRedirects(false);
String cookie = "CTSESSION=" + _ctsession;
httpCon.setRequestProperty("Cookie", cookie);
httpCon.setRequestMethod("GET");
httpCon.connect();
System.out.println("Cookies for current connection:" + cookie);
if(httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IllegalArgumentException("Http error code:" + httpCon.getResponseCode());
}
System.out.println("Image is located successfully and its size is " + httpCon.getContentLength());
final InputStream in = httpCon.getInputStream();
if(in == null) {
throw new IllegalArgumentException("in is null");
}
byte[] buffer = new byte[0x100000];
int len = in.read(buffer);
if(len <= 0) {
throw new IllegalArgumentException("getImageInputStream failed for ");
} else {
System.out.println("Succeed to read some data from image.");
}
in.close();
} catch ( Exception e){
throw new IllegalArgumentException(
MessageFormat.format("User {0} failed to connect with remote image {1}: {2}", _username, url.toString(), e));
}
}
/**
* Send a post request with content to the specified connection
* @param connection connection to URL
* @param postContent content to post
* @throws Exception
*/
private static void writePostContent(HttpURLConnection connection, String postContent) throws Exception {
connection.setRequestMethod("POST");
// set the output and input to true
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setAllowUserInteraction(false);
// set the content length
DataOutputStream dstream = null;
try {
connection.connect();
dstream = new DataOutputStream(connection.getOutputStream());
// write the post content
dstream.writeBytes(postContent);
dstream.flush();
} finally {
// flush the stream
if (dstream != null) {
try {
dstream.close();
}
catch (Exception ex) {
System.out.println("Exception while closing the stream.");
}
}
}
}
}