/*
* Copyright (C) 2011-2012 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson;
import com.intel.dcsg.cpg.crypto.RsaCredentialX509;
import com.intel.dcsg.cpg.crypto.RsaUtil;
import com.intel.dcsg.cpg.crypto.SimpleKeystore;
import com.intel.mtwilson.datatypes.*;
import com.intel.dcsg.cpg.io.Filename;
import com.intel.mtwilson.api.*;
import com.intel.dcsg.cpg.crypto.CryptographyException;
import com.intel.dcsg.cpg.rfc822.Rfc822Date;
import com.intel.dcsg.cpg.tls.policy.TlsUtil;
import java.io.*;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Properties;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @deprecated use com.intel.mtwilson.client.TextConsole
* @since 0.5.2
* @author jbuhacoff
*/
public class ApiCommand {
private static Logger log = LoggerFactory.getLogger(ApiCommand.class);
private static String getLocalhost() {
try {
InetAddress addr = InetAddress.getLocalHost();
return String.format("%s (%s)", addr.getHostName(), addr.getHostAddress());
} catch (UnknownHostException ex) {
return String.format("Unknown (%s)", ex.getMessage());
}
}
/**
* Syntax:
* java -cp path/to/apiclient.jar com.intel.mtwilson.ApiCommand [configuration options] [command name] [command parameters]
* Configuration options:
* --conf=filename
*
* @param args
*/
public static void main(String[] args) throws IOException, KeyManagementException, NoSuchAlgorithmException, GeneralSecurityException, ApiException, CryptographyException, ClientException, com.intel.dcsg.cpg.crypto.CryptographyException {
for(int i=0; i<args.length ;i++) {
System.out.println("ApiCommand ARG "+i+" = "+args[i]);
}
if( args.length == 0 ) {
printUsage();
System.exit(1);
}
/*
try {
Command cmd = (Command)Class.forName("com.intel.mtwilson.ApiCommand."+args[0]).newInstance();
cmd.run(args);
}
catch(ClassNotFoundException e) {
System.err.println("Unrecognized command: "+args[0]+": "+e.getMessage());
System.exit(1);
}
catch(InstantiationException e) {
System.err.println("Cannot load command: "+args[0]+": "+e.getMessage());
System.exit(1);
}
catch(IllegalAccessException e) {
System.err.println("Cannot load command: "+args[0]+": "+e.getMessage());
System.exit(1);
}
*
*/
if( args[0].equals("BootstrapUser") ) {
// args[1] should be path to folder
File directory = new File(args[1]);
// args[2] should be the url of the server to register with
URL server = new URL(args[2]);
// we assume the user needs only the Security role; everything else can be done via the management console (including adding more roles to him/herself)
String roles[] = new String[] { Role.Security.toString() };
String username = null, password = null, tlsProtocol = "TLS";
// args[2] is optional username (if not provided we will prompt)
if( args.length > 3 ) { username = args[3]; }
// args[3] is optional password plaintext (not recommended) or environment variable name (recommended) (if not provided we will prompt)
if( args.length > 4 ) { password = args[4]; }
if( args.length > 5 ) { tlsProtocol = args[5]; } // issue #870 allow user to specify tls protocol version, default to TLS
// prompt for username and password
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
if( username == null || username.isEmpty() ) {
System.out.print("Username: ");
username = in.readLine();
}
if( password == null || password.isEmpty() ) {
System.out.print("Password: ");
password = in.readLine();
System.out.print("Password again: ");
String passwordAgain = in.readLine();
if(password != null && passwordAgain != null) {
if( !password.equals(passwordAgain) ) {
System.err.println("The two passwords don't match");
System.exit(1);
}
}else{
System.err.println("Error reading passwords. Please run command again");
System.exit(1);
}
}
else if( password.startsWith("env:") && password.length() > 4 ) {
String varName = password.substring(4);
password = System.getenv(varName);
}
if( password == null || password.isEmpty() || password.length() < 6 ) {
System.err.println("The password must be at least six characters");
System.exit(1);
}
// create the keystore
String subject = username; //(see changes in RsaUtil ).format("CN=%s", username);
File keystoreFile = new File(directory.getAbsoluteFile() + File.separator + Filename.encode(username) + ".jks");
SimpleKeystore keystore = new SimpleKeystore(keystoreFile, password);
KeyPair keypair = RsaUtil.generateRsaKeyPair(RsaUtil.MINIMUM_RSA_KEY_SIZE);
X509Certificate certificate = RsaUtil.generateX509Certificate(subject, keypair, RsaUtil.DEFAULT_RSA_KEY_EXPIRES_DAYS);
keystore.addKeyPairX509(keypair.getPrivate(), certificate, username, password);
keystore.save();
System.out.println("Created new user keystore: "+keystoreFile.getAbsolutePath());
// register with the web service
// download server's ssl certificates and add them to the keystore
TlsUtil.addSslCertificatesToKeystore(keystore, server, tlsProtocol);
// register the user with the server
RsaCredentialX509 rsaCredential = keystore.getRsaCredentialX509(username, password);
Properties p = new Properties();
p.setProperty("mtwilson.api.ssl.requireTrustedCertificate", "true");
p.setProperty("mtwilson.api.ssl.verifyHostname", "true");
ApiClient c = new ApiClient(server, rsaCredential, keystore, new MapConfiguration(p)); //ConfigurationFactory.fromSystemEnvironment());
ApiClientCreateRequest user = new ApiClientCreateRequest();
user.setCertificate(rsaCredential.getCertificate().getEncoded());
user.setRoles(roles);
try {
c.register(user);
}
catch(javax.net.ssl.SSLException e) {
if( e.getMessage().contains("hostname in certificate didn't match") && !"false".equals(System.getenv("MTWILSON_API_SSL_VERIFY_HOSTNAME")) ) {
System.err.println(e.getMessage());
System.out.print("Do you want to continue anyway? [Y/N] ");
String ignoreHostname = in.readLine();
if( ignoreHostname != null && ignoreHostname.length() > 0 && ignoreHostname.toUpperCase().charAt(0) == 'Y' ) {
System.err.println("To avoid this prompt in the future, address the server by the hostname in its SSL certificate or set the environment variable MTWILSON_API_SSL_VERIFY_HOSTNAME=false");
Properties p2 = new Properties();
p2.setProperty("mtwilson.api.ssl.verifyHostname", "false");
c = new ApiClient(server, rsaCredential, keystore, new MapConfiguration(p2));
c.register(user);
}
else {
System.exit(2);
}
}
else {
throw e;
}
}
// download server's saml certificate and save in the keystore
X509Certificate samlCertificate = c.getSamlCertificate();
keystore.addTrustedSamlCertificate(samlCertificate, server.getHost());
log.debug("Added SAML Certificate with alias {}, subject {}, fingerprint {}, from server {}", server.getHost(), samlCertificate.getSubjectX500Principal().getName(), DigestUtils.shaHex(samlCertificate.getEncoded()), server.getHost());
keystore.save();
/*
// assume the management service is on the localhost, add 127.0.0.1 to mtwilson.api.trust in management-service.properties
// fixed 2012-07-31: instead of adding 127.0.0.1, add the external IP of local host (same as server's external IP) since we're accessing it as , for example, https://1.2.3.4 then our IP will appear as 1.2.3.4 not 127.0.0.1 , so we want to whitelist the IP that the serve rwill see.
Properties p = new Properties();
p.load(new FileInputStream("/etc/intel/cloudsecurity/management-service.properties"));
String previousWhitelistCSV = p.getProperty("mtwilson.api.trust","");
String[] previousWhitelist = StringUtils.split(previousWhitelistCSV, ", ");
String[] updatedWhitelist = (String[]) ArrayUtils.add(previousWhitelist, server.getHost()); // was: "127.0.0.1" now: same as server's IP, ex. 1.2.3.4
String updatedWhitelistCSV = StringUtils.join(updatedWhitelist, ",");
Runtime.getRuntime().exec("msctl edit mtwilson.api.trust \""+updatedWhitelistCSV+"\"");
Runtime.getRuntime().exec("msctl restart");
// self-approve
ApiClientUpdateRequest update = new ApiClientUpdateRequest();
update.fingerprint = rsaCredential.identity();
update.enabled = true;
update.roles = roles;
update.status = ApiClientStatus.APPROVED.toString();
update.comment = "via command line from "+getLocalhost()+" at "+Rfc822Date.format(new Date());
c.updateApiClient(update); // ApiException, SignatureException
// restore previous mtwilson.api.trust setting
Runtime.getRuntime().exec("msctl edit mtwilson.api.trust "+previousWhitelistCSV);
Runtime.getRuntime().exec("msctl restart");
*/
/*
Runtime.getRuntime().exec("msctl approve-user "+directory.getAbsoluteFile()+" "+Filename.encode(username)+" "+password);
*
System.out.println("Bootstrap complete");
*/
return; //System.exit(0);
}
//if( args[0].equals("CreateUser") ) {
//
//}
if( args[0].equals("RegisterUser") ) {
return; //System.exit(0);
}
if( args[0].equals("ApproveUser") ) {
if( args.length < 4 ) {
System.err.println("Usage: ApproveUser /path/to/username.jks ServiceURL Role1[,Role2,...]");
System.err.println("ServiceURL is the URL to the management service");
System.err.println("Try these roles: Attestation,Whitelist,Security");
System.exit(1);
}
// args[1] should be path to keystore (/path/to/directory/username.jks)
File keystoreFile = new File(args[1]);
// args[2] should be the url of the server to register with
URL server = new URL(args[2]);
// args[3] should be the roles being requested, comma-separated values (Attestation,Whitelist,Security)
String[] roles = StringUtils.split(args[3], ",");
String username = Filename.decode(keystoreFile.getName().substring(0, keystoreFile.getName().lastIndexOf("."))); // username is everything before ".jks"
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Password: ");
String password = in.readLine();
SimpleKeystore keystore = new SimpleKeystore(keystoreFile, password);
// approve the user with the server (requires server to trust our IP address)
RsaCredentialX509 rsaCredential = keystore.getRsaCredentialX509(username, password);
Properties p = new Properties();
p.setProperty("mtwilson.api.ssl.requireTrustedCertificate", "true");
p.setProperty("mtwilson.api.ssl.verifyHostname", "true");
ApiClient c = new ApiClient(server, rsaCredential, keystore, new MapConfiguration(p)); //ConfigurationFactory.fromSystemEnvironment());
ApiClientUpdateRequest update = new ApiClientUpdateRequest();
update.fingerprint = rsaCredential.identity();
update.enabled = true;
update.roles = roles;
update.status = ApiClientStatus.APPROVED.toString();
update.comment = "via command line from "+getLocalhost()+" at "+Rfc822Date.format(new Date());
try {
c.updateApiClient(update); // ApiException, SignatureException
}
catch(javax.net.ssl.SSLException e) {
if( e.getMessage().contains("hostname in certificate didn't match") && !"false".equals(System.getenv("MTWILSON_API_SSL_VERIFY_HOSTNAME")) ) {
System.err.println(e.getMessage());
System.out.print("Do you want to continue anyway? [Y/N] ");
String ignoreHostname = in.readLine();
if( ignoreHostname != null && ignoreHostname.length() > 0 && ignoreHostname.toUpperCase().charAt(0) == 'Y' ) {
System.err.println("To avoid this prompt in the future, address the server by the hostname in its SSL certificate or set the environment variable MTWILSON_API_SSL_VERIFY_HOSTNAME=false");
Properties p2 = new Properties();
p2.setProperty("mtwilson.api.ssl.verifyHostname", "false");
c = new ApiClient(server, rsaCredential, keystore, new MapConfiguration(p2));
c.updateApiClient(update); // ApiException, SignatureException
}
else {
System.exit(2);
}
}
else {
throw e;
}
}
System.out.println("OK");
return; //System.exit(0);
}
/*
int i = 0;
try {
ApiClient api = null;
// look for configuration options
while(args.length > i && args[i].startsWith("--")) {
if( args[i].startsWith("--conf=") ) {
String configurationFilename = args[i].substring("--conf=".length());
System.out.println("Configuration filename: "+configurationFilename);
api = new ApiClient(new File(configurationFilename));
}
++i;
}
if( api == null ) {
CompositeConfiguration config = new CompositeConfiguration();
config.addConfiguration(new SystemConfiguration());
config.addConfiguration(ConfigurationFactory.fromSystemEnvironment()); // lower priority than system properties set on java vm
api = new ApiClient(config);
}
// look for the command name
String command = null;
if( args.length > i ) {
command = args[i];
++i;
}
if( command == null ) {
printUsage();
return;
}
// execute the selected command
if( "GetHostLocation".equals(command) ) {
if( args.length > i ) {
api.getHostLocation(new Hostname(args[i]));
++i;
}
else {
printUsage("GetHostLocation", "<hostname>");
}
}
} catch (SignatureException ex) {
log.error("Error signing request: "+ex.getMessage(), ex);
} catch (KeyStoreException ex) {
log.error("Error loading credentials: "+ex.getMessage(), ex);
} catch (CertificateException ex) {
log.error("Invalid certificate for key: "+ex.getMessage(), ex);
} catch (UnrecoverableEntryException ex) {
log.error("Error loading key: "+ex.getMessage(), ex);
} catch (NoSuchAlgorithmException ex) {
log.error("Algorithm not available: "+ex.getMessage(), ex);
} catch (KeyManagementException ex) {
log.error("Error in key management: "+ex.getMessage(), ex);
} catch (MalformedURLException ex) {
log.error("Cannot understand URL: "+ex.getMessage(), ex);
} catch (IOException ex) {
log.error("IO Error: "+ex.getMessage(), ex);
} catch (ApiException ex) {
log.error("API Error "+ex.getErrorCode()+": "+ex.getMessage(), ex);
}
*
*/
}
private static void printUsage() {
System.err.println("Usage:");
System.err.println("CreateUser /path/to/directory");
System.err.println(" Will prompt for username and password.");
System.err.println(" Will create username.jks in directory.");
}
/*
private static void printUsage(String command, String parameters) {
System.err.println("Usage: mtwilson [configuration options] "+command+" "+parameters);
}
*/
}