/*
* Copyright (C) 2012 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.client.cmd;
import com.intel.mtwilson.ApiClient;
import com.intel.mtwilson.KeystoreUtil;
import com.intel.mtwilson.client.AbstractCommand;
import com.intel.dcsg.cpg.crypto.RsaCredentialX509;
import com.intel.dcsg.cpg.crypto.SimpleKeystore;
import com.intel.dcsg.cpg.x509.X509Util;
import com.intel.mtwilson.datatypes.ApiClientCreateRequest;
import com.intel.dcsg.cpg.io.Filename;
import com.intel.dcsg.cpg.tls.policy.TlsUtil;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
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;
/**
* HostTrustResponse getHostTrust(Hostname hostname) throws IOException, ApiException, SignatureException;
*
* @author jbuhacoff
*/
public class RegisterUser extends AbstractCommand {
private Logger log = LoggerFactory.getLogger(getClass());
@Override
public void execute(String[] args) throws Exception {
// ApiClient api = getClient();
if( args.length < 3 ) {
System.err.println("Usage: RegisterUser /path/to/username.jks ServiceURL Role1[,Role2,...] [password]");
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[0]);
// args[2] should be the url of the server to register with
URL server = new URL(args[1]);
// args[3] should be the roles being requested, comma-separated values (Attestation,Whitelist,Security)
String[] roles = StringUtils.split(args[2], ",");
String username = Filename.decode(keystoreFile.getName().substring(0, keystoreFile.getName().lastIndexOf("."))); // username is everything before ".jks"
String password = null;
String tlsProtocol = "TLS"; // issue #870 allow user to specify tls protocol version, default to TLS
// args[4] is optional password plaintext (not recommended) or environment variable name (recommended) (if not provided we will prompt)
if( args.length > 3 ) { password = args[3]; }
if( args.length > 4 ) { tlsProtocol = args[4]; }
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
if( password == null || password.isEmpty() ) {
System.out.print("Password: ");
password = in.readLine();
}
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);
}
SimpleKeystore keystore = new SimpleKeystore(keystoreFile, password);
// download server's ssl certificates and add them to the keystore and display for user to confirm later
String[] tlsCertAliases0 = keystore.listTrustedSslCertificates();
TlsUtil.addSslCertificatesToKeystore(keystore, server, tlsProtocol);
String[] tlsCertAliases = keystore.listTrustedSslCertificates();
String[] newTlsCertAliases = elementsAdded(tlsCertAliases0, tlsCertAliases);
for(String alias : newTlsCertAliases) {
X509Certificate cert = keystore.getX509Certificate(alias);
System.out.println(String.format("Added TLS Certificate for %s with SHA1 fingerprint %s", cert.getSubjectX500Principal().getName(), X509Util.sha1fingerprint(cert)));
}
// register the user with the server
RsaCredentialX509 rsaCredential = keystore.getRsaCredentialX509(username, password);
Properties p = new Properties();
/*
p.setProperty("mtwilson.api.ssl.policy", "TRUST_CA_VERIFY_HOSTNAME"); // must be secure out of the box!
p.setProperty("mtwilson.api.ssl.requireTrustedCertificate", "true");
p.setProperty("mtwilson.api.ssl.verifyHostname", "true");
*/
p.setProperty("mtwilson.api.ssl.policy", "TRUST_FIRST_CERTIFICATE");
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 {
return;
}
}
else {
throw e;
}
}
// download all ca certs from the server (root ca, privacy ca, saml ca, etc)
try {
Set<X509Certificate> cacerts = c.getRootCaCertificates();
for(X509Certificate cacert : cacerts) {
keystore.addTrustedCaCertificate(cacert, cacert.getSubjectX500Principal().getName());
log.debug("Added CA Certificate with alias {}, subject {}, fingerprint {}, from server {}", cacert.getSubjectX500Principal().getName(), cacert.getSubjectX500Principal().getName(), DigestUtils.shaHex(cacert.getEncoded()), server.getHost());
}
}
catch(Exception e) {
log.error("Cannot download Mt Wilson Root CA certificate from server");
}
// download privacy ca certificates
try {
Set<X509Certificate> cacerts = c.getPrivacyCaCertificates();
for(X509Certificate cacert : cacerts) {
keystore.addTrustedCaCertificate(cacert, cacert.getSubjectX500Principal().getName());
log.debug("Added Privacy CA Certificate with alias {}, subject {}, fingerprint {}, from server {}", cacert.getSubjectX500Principal().getName(), cacert.getSubjectX500Principal().getName(), DigestUtils.shaHex(cacert.getEncoded()), server.getHost());
}
}
catch(Exception e) {
log.error("Cannot download Privacy CA certificate from server");
}
// download server's saml certificate and save in the keystore
try {
Set<X509Certificate> cacerts = c.getSamlCertificates();
for(X509Certificate cert : cacerts) {
if( cert.getBasicConstraints() == -1 ) { // -1 indicates the certificate is not a CA cert; so we add it as the saml cert
keystore.addTrustedSamlCertificate(cert, server.getHost());
log.debug("Added SAML Certificate with alias {}, subject {}, fingerprint {}, from server {}", cert.getSubjectX500Principal().getName(), cert.getSubjectX500Principal().getName(), DigestUtils.shaHex(cert.getEncoded()), server.getHost());
}
else {
keystore.addTrustedCaCertificate(cert, cert.getSubjectX500Principal().getName());
log.debug("Added SAML CA Certificate with alias {}, subject {}, fingerprint {}, from server {}", cert.getSubjectX500Principal().getName(), cert.getSubjectX500Principal().getName(), DigestUtils.shaHex(cert.getEncoded()), server.getHost());
}
}
}
catch(Exception e) {
log.error("Cannot download SAML certificate from server");
}
keystore.save();
System.out.println("OK");
}
private String[] elementsAdded(String[] from, String[] to) {
HashSet<String> added = new HashSet<String>();
added.addAll(Arrays.asList(to));
added.removeAll(Arrays.asList(from));
return added.toArray(new String[added.size()]);
}
}