knox-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lmc...@apache.org
Subject [knox] branch master updated: KNOX-1711 - Provide Endpoint Public Cert for KnoxToken
Date Wed, 26 Dec 2018 22:48:38 GMT
This is an automated email from the ASF dual-hosted git repository.

lmccay pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new eb831f2  KNOX-1711 - Provide Endpoint Public Cert for KnoxToken
eb831f2 is described below

commit eb831f2b1e4174239c804da1c8cdb19caa47c092
Author: Larry McCay <lmccay@apache.org>
AuthorDate: Wed Dec 26 17:44:50 2018 -0500

    KNOX-1711 - Provide Endpoint Public Cert for KnoxToken
---
 gateway-service-knoxtoken/pom.xml                  |   5 +
 .../gateway/service/knoxtoken/TokenResource.java   |  69 ++++++---
 .../service/knoxtoken/TokenServiceMessages.java    |   5 +-
 gateway-shell/pom.xml                              |  10 ++
 .../apache/knox/gateway/shell/ClientContext.java   |  17 ++-
 .../org/apache/knox/gateway/shell/Credentials.java |  14 +-
 .../apache/knox/gateway/shell/ErrorResponse.java   |   4 +-
 .../org/apache/knox/gateway/shell/KnoxSession.java | 154 +++++++++++++++------
 .../{ErrorResponse.java => KnoxShellMessages.java} |  22 ++-
 .../shell/KnoxTokenCredentialCollector.java        |  64 ++++++---
 .../apache/knox/gateway/shell/KnoxSessionTest.java |  75 ++++++++++
 .../shell/KnoxTokenCredentialCollectorTest.java    |  74 +++++++++-
 .../security/impl/X509CertificateUtil.java         |  17 ++-
 13 files changed, 416 insertions(+), 114 deletions(-)

diff --git a/gateway-service-knoxtoken/pom.xml b/gateway-service-knoxtoken/pom.xml
index c080327..dbc3cf9 100644
--- a/gateway-service-knoxtoken/pom.xml
+++ b/gateway-service-knoxtoken/pom.xml
@@ -69,6 +69,11 @@
         </dependency>
 
         <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <scope>test</scope>
diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
index 526f7d9..0da2def 100644
--- a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
+++ b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenResource.java
@@ -17,7 +17,10 @@
  */
 package org.apache.knox.gateway.service.knoxtoken;
 
+import java.security.KeyStoreException;
 import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Map;
@@ -33,8 +36,12 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
+
+import org.apache.commons.codec.binary.Base64;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.security.KeystoreService;
+import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.services.security.token.JWTokenAuthority;
 import org.apache.knox.gateway.services.security.token.TokenServiceException;
 import org.apache.knox.gateway.services.security.token.impl.JWT;
@@ -43,12 +50,13 @@ import org.apache.knox.gateway.util.JsonUtils;
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static javax.ws.rs.core.MediaType.APPLICATION_XML;
 
-@Path( TokenResource.RESOURCE_PATH )
+@Path(TokenResource.RESOURCE_PATH)
 public class TokenResource {
   private static final String EXPIRES_IN = "expires_in";
   private static final String TOKEN_TYPE = "token_type";
   private static final String ACCESS_TOKEN = "access_token";
   private static final String TARGET_URL = "target_url";
+  private static final String ENDPOINT_PUBLIC_CERT = "endpoint_public_cert";
   private static final String BEARER = "Bearer";
   private static final String TOKEN_TTL_PARAM = "knox.token.ttl";
   private static final String TOKEN_AUDIENCES_PARAM = "knox.token.audiences";
@@ -59,14 +67,16 @@ public class TokenResource {
   private static final String TOKEN_SIG_ALG = "knox.token.sigalg";
   private static final long TOKEN_TTL_DEFAULT = 30000L;
   static final String RESOURCE_PATH = "knoxtoken/api/v1/token";
-  private static TokenServiceMessages log = MessagesFactory.get( TokenServiceMessages.class
);
+  private static final String TARGET_ENDPOINT_PULIC_CERT_PEM = "knox.token.target.endpoint.cert.pem";
+  private static TokenServiceMessages log = MessagesFactory.get(TokenServiceMessages.class);
   private long tokenTTL = TOKEN_TTL_DEFAULT;
   private List<String> targetAudiences = new ArrayList<>();
   private String tokenTargetUrl;
-  private Map<String,Object> tokenClientDataMap;
+  private Map<String, Object> tokenClientDataMap;
   private List<String> allowedDNs = new ArrayList<>();
   private boolean clientCertRequired;
   private String signatureAlgorithm = "RS256";
+  private String endpointPublicCert;
 
   @Context
   HttpServletRequest request;
@@ -86,7 +96,7 @@ public class TokenResource {
     }
 
     String clientCert = context.getInitParameter(TOKEN_CLIENT_CERT_REQUIRED);
-    clientCertRequired = Boolean.parseBoolean(clientCert);
+    clientCertRequired = "true".equals(clientCert);
 
     String principals = context.getInitParameter(TOKEN_ALLOWED_PRINCIPALS);
     if (principals != null) {
@@ -104,8 +114,7 @@ public class TokenResource {
           log.invalidTokenTTLEncountered(ttl);
           tokenTTL = TOKEN_TTL_DEFAULT;
         }
-      }
-      catch (NumberFormatException nfe) {
+      } catch (NumberFormatException nfe) {
         log.invalidTokenTTLEncountered(ttl);
       }
     }
@@ -123,6 +132,11 @@ public class TokenResource {
     if (sigAlg != null) {
       signatureAlgorithm = sigAlg;
     }
+
+    String targetEndpointPublicCert = context.getInitParameter(TARGET_ENDPOINT_PULIC_CERT_PEM);
+    if (targetEndpointPublicCert != null) {
+      endpointPublicCert = targetEndpointPublicCert;
+    }
   }
 
   @GET
@@ -140,7 +154,7 @@ public class TokenResource {
   private X509Certificate extractCertificate(HttpServletRequest req) {
     X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
     if (null != certs && certs.length > 0) {
-        return certs[0];
+      return certs[0];
     }
     return null;
   }
@@ -149,23 +163,38 @@ public class TokenResource {
     if (clientCertRequired) {
       X509Certificate cert = extractCertificate(request);
       if (cert != null) {
-        if (!allowedDNs.contains(cert.getSubjectDN().getName().replaceAll("\\s+",""))) {
+        if (!allowedDNs.contains(cert.getSubjectDN().getName().replaceAll("\\s+", ""))) {
           return Response.status(403).entity("{ \"Unable to get token - untrusted client
cert.\" }").build();
         }
-      }
-      else {
+      } else {
         return Response.status(403).entity("{ \"Unable to get token - client cert required.\"
}").build();
       }
     }
     GatewayServices services = (GatewayServices) request.getServletContext()
-            .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
+        .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
 
     JWTokenAuthority ts = services.getService(GatewayServices.TOKEN_SERVICE);
-    Principal p = request.getUserPrincipal();
+    Principal p = ((HttpServletRequest) request).getUserPrincipal();
     long expires = getExpiry();
 
+    if (endpointPublicCert == null) {
+      // acquire PEM for gateway-identity of this gateway instance
+      KeystoreService ks = services.getService(GatewayServices.KEYSTORE_SERVICE);
+      if (ks != null) {
+        try {
+          Certificate cert = ks.getKeystoreForGateway().getCertificate("gateway-identity");
+          byte[] bytes = cert.getEncoded();
+          //Base64 encoder = new Base64(76, "\n".getBytes("ASCII"));
+          endpointPublicCert = Base64.encodeBase64String(bytes);
+        } catch (KeyStoreException | KeystoreServiceException | CertificateEncodingException
e) {
+          // assuming that certs will be properly provisioned across all clients
+          log.unableToAcquireCertForEndpointClients(e);
+        }
+      }
+    }
+
     try {
-      JWT token;
+      JWT token = null;
       if (targetAudiences.isEmpty()) {
         token = ts.issueToken(p, signatureAlgorithm, expires);
       } else {
@@ -185,16 +214,17 @@ public class TokenResource {
         if (tokenClientDataMap != null) {
           map.putAll(tokenClientDataMap);
         }
+        if (endpointPublicCert != null) {
+          map.put(ENDPOINT_PUBLIC_CERT, endpointPublicCert);
+        }
 
         String jsonResponse = JsonUtils.renderAsJsonString(map);
 
         return Response.ok().entity(jsonResponse).build();
-      }
-      else {
+      } else {
         return Response.serverError().build();
       }
-    }
-    catch (TokenServiceException e) {
+    } catch (TokenServiceException e) {
       log.unableToIssueToken(e);
     }
     return Response.ok().entity("{ \"Unable to acquire token.\" }").build();
@@ -212,11 +242,10 @@ public class TokenResource {
   }
 
   private long getExpiry() {
-    long expiry;
+    long expiry = 0L;
     if (tokenTTL == -1) {
       expiry = -1;
-    }
-    else {
+    } else {
       expiry = System.currentTimeMillis() + tokenTTL;
     }
     return expiry;
diff --git a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceMessages.java
b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceMessages.java
index 4219d66..f9d97ad 100644
--- a/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceMessages.java
+++ b/gateway-service-knoxtoken/src/main/java/org/apache/knox/gateway/service/knoxtoken/TokenServiceMessages.java
@@ -63,4 +63,7 @@ public interface TokenServiceMessages {
   @Message( level = MessageLevel.ERROR, text = "The original URL: {0} for redirecting back
after authentication is " +
       "not valid according to the configured whitelist: {1}. See documentation for KnoxSSO
Whitelisting.")
   void whiteListMatchFail(String original, String whitelist);
-}
\ No newline at end of file
+
+  @Message( level = MessageLevel.WARN, text = "Unable to acquire cert for endpoint clients
- assume trust will be provisioned separately: {0}.")
+  void unableToAcquireCertForEndpointClients(@StackTrace( level = MessageLevel.DEBUG ) Exception
e);
+}
diff --git a/gateway-shell/pom.xml b/gateway-shell/pom.xml
index e7c0c2a..35382cf 100644
--- a/gateway-shell/pom.xml
+++ b/gateway-shell/pom.xml
@@ -35,6 +35,16 @@
             <groupId>org.apache.knox</groupId>
             <artifactId>gateway-util-common</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-i18n</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.knox</groupId>
+            <artifactId>gateway-test-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.codehaus.groovy</groupId>
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java
b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java
index 0434e5a..3bb1339 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ClientContext.java
@@ -31,7 +31,7 @@ public class ClientContext {
   private final ConnectionContext connectionContext;
   private final KerberosContext kerberos;
 
-  private ClientContext() {
+  public ClientContext() {
     configuration = new MapConfiguration(new HashMap<>());
     poolContext = new PoolContext(this);
     socketContext = new SocketContext(this);
@@ -43,7 +43,7 @@ public class ClientContext {
     private final ClientContext clientContext;
     protected final Configuration configuration;
 
-    Context(ClientContext clientContext, String prefix) {
+    private Context(ClientContext clientContext, String prefix) {
       this.clientContext = clientContext;
       this.configuration = new SubsetConfiguration(clientContext.configuration, prefix);
     }
@@ -54,6 +54,7 @@ public class ClientContext {
   }
 
   public static class PoolContext extends Context {
+
     PoolContext(ClientContext clientContext) {
       super(clientContext, "pool");
     }
@@ -78,6 +79,7 @@ public class ClientContext {
   }
 
   public static class SocketContext extends Context {
+
     SocketContext(ClientContext clientContext) {
       super(clientContext, "socket");
     }
@@ -129,6 +131,7 @@ public class ClientContext {
   }
 
   public static class ConnectionContext extends Context {
+
     ConnectionContext(ClientContext clientContext) {
       super(clientContext, "connection");
     }
@@ -176,6 +179,11 @@ public class ClientContext {
       return this;
     }
 
+    public ConnectionContext withPublicCertPem(final String endpointPublicCertPem) {
+          configuration.addProperty("endpointPublicCertPem", endpointPublicCertPem);
+          return this;
+    }
+
     public String truststoreLocation() {
       return configuration.getString("truststoreLocation");
     }
@@ -183,6 +191,10 @@ public class ClientContext {
     public String truststorePass() {
       return configuration.getString("truststorePass");
     }
+
+    public String endpointPublicCertPem() {
+      return configuration.getString("endpointPublicCertPem");
+    }
   }
 
   /**
@@ -190,6 +202,7 @@ public class ClientContext {
    * @since 1.3.0
    */
   public static class KerberosContext extends Context {
+
     KerberosContext(ClientContext clientContext) {
       super(clientContext, "kerberos");
     }
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Credentials.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Credentials.java
index 610bd16..13ac9bf 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Credentials.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/Credentials.java
@@ -22,7 +22,7 @@ import java.util.List;
 import java.util.ServiceLoader;
 
 public class Credentials {
-  List<CredentialCollector> collectors = new ArrayList<>();
+  List<CredentialCollector> collectors = new ArrayList<CredentialCollector>();
 
   public Credentials add(String collectorType, String prompt, String name)
     throws CredentialCollectionException {
@@ -37,6 +37,18 @@ public class Credentials {
     return this;
   }
 
+  public Credentials add(CredentialCollector collector, String prompt, String name)
+      throws CredentialCollectionException {
+    if (collector == null) {
+      throw new CredentialCollectionException("Null CredentialCollector cannot be added.");
+    }
+    collector.setPrompt(prompt);
+    collector.setName(name);
+    collectors.add(collector);
+
+    return this;
+  }
+
   public void collect() throws CredentialCollectionException {
     for (CredentialCollector collector : collectors) {
       collector.collect();
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
index 92661e9..58a5ed6 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
@@ -23,8 +23,8 @@ class ErrorResponse extends RuntimeException {
 
   HttpResponse response;
 
-  ErrorResponse( HttpResponse response ) {
-    super(String.valueOf(response.getStatusLine()));
+  ErrorResponse(String text, HttpResponse response) {
+    super(text + response.getStatusLine());
     this.response = response;
   }
 
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java
index d7d962e..da7036a 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxSession.java
@@ -18,6 +18,9 @@
 package org.apache.knox.gateway.shell;
 
 import com.sun.security.auth.callback.TextCallbackHandler;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpRequest;
@@ -48,12 +51,15 @@ import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.http.protocol.BasicHttpContext;
 import org.apache.http.ssl.SSLContexts;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.SSLContext;
 import javax.security.auth.Subject;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
+
+import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -70,6 +76,8 @@ import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.PrivilegedAction;
 import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Callable;
@@ -90,7 +98,10 @@ public class KnoxSession implements Closeable {
   private static final String KNOX_CLIENT_TRUSTSTORE_DIR = "KNOX_CLIENT_TRUSTSTORE_DIR";
   private static final String DEFAULT_JAAS_FILE = "/jaas.conf";
   public static final String JGSS_LOGIN_MOUDLE = "com.sun.security.jgss.initiate";
+  public static final String END_CERTIFICATE = "-----END CERTIFICATE-----\n";
+  public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n";
 
+  private static final KnoxShellMessages LOG = MessagesFactory.get(KnoxShellMessages.class);
   private boolean isKerberos;
 
   String base;
@@ -114,6 +125,18 @@ public class KnoxSession implements Closeable {
     return instance;
   }
 
+  public static KnoxSession login( String             url,
+                                   Map<String,String> headers,
+                                   String             truststoreLocation,
+                                   String             truststorePass  ) throws URISyntaxException
{
+    KnoxSession instance = new KnoxSession(ClientContext.with(url)
+                                                        .connection()
+                                                        .withTruststore(truststoreLocation,
truststorePass)
+                                                        .end());
+    instance.setHeaders(headers);
+    return instance;
+  }
+
   public static KnoxSession login( String url, String username, String password ) throws
URISyntaxException {
     return new KnoxSession(ClientContext.with(username, password, url));
   }
@@ -122,12 +145,11 @@ public class KnoxSession implements Closeable {
       String truststoreLocation, String truststorePass ) throws URISyntaxException {
 
     return new KnoxSession(ClientContext.with(username, password, url)
-            .connection().withTruststore(truststoreLocation, truststorePass).end());
+        .connection().withTruststore(truststoreLocation, truststorePass).end());
   }
 
-  public static KnoxSession loginInsecure(String url, String username, String password) throws
URISyntaxException {
-    return new KnoxSession(ClientContext.with(username, password, url)
-            .connection().secure(false).end());
+  public static KnoxSession login(ClientContext context) throws URISyntaxException {
+    return new KnoxSession(context);
   }
 
   /**
@@ -170,10 +192,15 @@ public class KnoxSession implements Closeable {
     return kerberosLogin(url, "", "", false);
   }
 
+  public static KnoxSession loginInsecure(String url, String username, String password) throws
URISyntaxException {
+    return new KnoxSession(ClientContext.with(username, password, url)
+        .connection().secure(false).end());
+  }
+
   protected KnoxSession() throws KnoxShellException, URISyntaxException {
   }
 
-  public KnoxSession( ClientContext clientContext) throws KnoxShellException, URISyntaxException
{
+  public KnoxSession( final ClientContext clientContext) throws KnoxShellException, URISyntaxException
{
     this.executor = Executors.newCachedThreadPool();
     this.base = clientContext.url();
 
@@ -194,19 +221,19 @@ public class KnoxSession implements Closeable {
     } else {
       trustStrategy = TrustSelfSignedStrategy.INSTANCE;
       System.out.println("**************** WARNING ******************\n"
-              + "This is an insecure client instance and may\n"
-              + "leave the interactions subject to a man in\n"
-              + "the middle attack. Please use the login()\n"
-              + "method instead of loginInsecure() for any\n"
-              + "sensitive or production usecases.\n"
-              + "*******************************************");
+          + "This is an insecure client instance and may\n"
+          + "leave the interactions subject to a man in\n"
+          + "the middle attack. Please use the login()\n"
+          + "method instead of loginInsecure() for any\n"
+          + "sensitive or production usecases.\n"
+          + "*******************************************");
     }
 
     KeyStore trustStore = getTrustStore(clientContext);
     SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(trustStore, trustStrategy).build();
     Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
-            .register("http", PlainConnectionSocketFactory.getSocketFactory())
-            .register("https", new SSLConnectionSocketFactory(sslContext, hostnameVerifier)).build();
+        .register("http", PlainConnectionSocketFactory.getSocketFactory())
+        .register("https", new SSLConnectionSocketFactory(sslContext, hostnameVerifier)).build();
 
     // Pool
     PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
@@ -214,17 +241,17 @@ public class KnoxSession implements Closeable {
     connectionManager.setDefaultMaxPerRoute(clientContext.pool().defaultMaxPerRoute());
 
     ConnectionConfig connectionConfig = ConnectionConfig.custom()
-            .setBufferSize(clientContext.connection().bufferSize())
-            .build();
+        .setBufferSize(clientContext.connection().bufferSize())
+        .build();
     connectionManager.setDefaultConnectionConfig(connectionConfig);
 
     SocketConfig socketConfig = SocketConfig.custom()
-            .setSoKeepAlive(clientContext.socket().keepalive())
-            .setSoLinger(clientContext.socket().linger())
-            .setSoReuseAddress(clientContext.socket().reuseAddress())
-            .setSoTimeout(clientContext.socket().timeout())
-            .setTcpNoDelay(clientContext.socket().tcpNoDelay())
-            .build();
+        .setSoKeepAlive(clientContext.socket().keepalive())
+        .setSoLinger(clientContext.socket().linger())
+        .setSoReuseAddress(clientContext.socket().reuseAddress())
+        .setSoTimeout(clientContext.socket().timeout())
+        .setTcpNoDelay(clientContext.socket().tcpNoDelay())
+        .build();
     connectionManager.setDefaultSocketConfig(socketConfig);
 
     // Auth
@@ -273,25 +300,24 @@ public class KnoxSession implements Closeable {
       final Registry<AuthSchemeProvider> authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create()
           .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory(true)).build();
 
-      return HttpClients.custom()
-          .setConnectionManager(connectionManager)
+      return HttpClients.custom().setConnectionManager(connectionManager)
           .setDefaultAuthSchemeRegistry(authSchemeRegistry)
-          .setDefaultCredentialsProvider(credentialsProvider)
-          .build();
-
+          .setDefaultCredentialsProvider(credentialsProvider).build();
     } else {
+      AuthCache authCache = new BasicAuthCache();
+      BasicScheme authScheme = new BasicScheme();
+      authCache.put(host, authScheme);
+      context = new BasicHttpContext();
+      context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE,
+          authCache);
+
       CredentialsProvider credentialsProvider = null;
       if (clientContext.username() != null && clientContext.password() != null) {
         credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(
-            new AuthScope(host.getHostName(), host.getPort()),
-            new UsernamePasswordCredentials(clientContext.username(), clientContext.password()));
-
-        AuthCache authCache = new BasicAuthCache();
-        BasicScheme authScheme = new BasicScheme();
-        authCache.put(host, authScheme);
-        context = new BasicHttpContext();
-        context.setAttribute(org.apache.http.client.protocol.HttpClientContext.AUTH_CACHE,
authCache);
+        credentialsProvider
+            .setCredentials(new AuthScope(host.getHostName(), host.getPort()),
+                new UsernamePasswordCredentials(clientContext.username(),
+                    clientContext.password()));
       }
       return HttpClients.custom()
           .setConnectionManager(connectionManager)
@@ -301,12 +327,39 @@ public class KnoxSession implements Closeable {
 
   }
 
+  protected X509Certificate generateCertificateFromBytes(byte[] certBytes) throws CertificateException
{
+    CertificateFactory factory = CertificateFactory.getInstance("X.509");
+    return (X509Certificate)factory.generateCertificate(new ByteArrayInputStream(certBytes));
+  }
+
   private KeyStore getTrustStore(ClientContext clientContext) throws GeneralSecurityException
{
     KeyStore ks;
     String truststorePass = null;
 
+    // if a PEM file was provided create a keystore from that and use
+    // it as the truststore
+    String pem = clientContext.connection().endpointPublicCertPem();
+    if (pem != null) {
+      // strip delimiters
+      if (pem.contains("BEGIN")) {
+        pem = pem.substring(BEGIN_CERTIFICATE.length()-1,
+            pem.indexOf(END_CERTIFICATE.substring(0, END_CERTIFICATE.length()-1)));
+      }
+      try {
+        byte[] bytes = Base64.decodeBase64(pem);
+        KeyStore keystore = KeyStore.getInstance("JKS");
+        keystore.load(null);
+        keystore.setCertificateEntry("knox-gateway", generateCertificateFromBytes(bytes));
+
+        return keystore;
+      } catch (IOException e) {
+        LOG.unableToLoadProvidedPEMEncodedTrustedCert(e);
+      }
+    }
+
     discoverTruststoreDetails(clientContext);
 
+    InputStream is = null;
     try {
       ks = KeyStore.getInstance("JKS");
       File file = new File(clientContext.connection().truststoreLocation());
@@ -324,14 +377,13 @@ public class KnoxSession implements Closeable {
       }
 
       if (file.exists()) {
-        try (InputStream is = Files.newInputStream(file.toPath())) {
-          ks.load(is, truststorePass.toCharArray());
-        }
+        is = Files.newInputStream(file.toPath());
+        ks.load(is, truststorePass.toCharArray());
       }
       else {
         throw new KnoxShellException("Unable to find a truststore for secure login."
             + "Please import the gateway-identity certificate into the JVM"
-          + " truststore or set the truststore location ENV variables.");
+            + " truststore or set the truststore location ENV variables.");
       }
     } catch (KeyStoreException e) {
       throw new KnoxShellException("Unable to create keystore of expected type.", e);
@@ -350,14 +402,16 @@ public class KnoxSession implements Closeable {
     } catch (IOException e) {
       throw new KnoxShellException("Unable to load truststore."
           + " May be related to password setting or truststore format.", e);
+    } finally {
+      IOUtils.closeQuietly(is);
     }
 
     return ks;
   }
 
   protected void discoverTruststoreDetails(ClientContext clientContext) {
-    String truststoreDir;
-    String truststoreFileName;
+    String truststoreDir = null;
+    String truststoreFileName = null;
     if (clientContext.connection().truststoreLocation() != null &&
         clientContext.connection().truststorePass() != null) {
       return;
@@ -399,7 +453,8 @@ public class KnoxSession implements Closeable {
                 if (response.getStatusLine().getStatusCode() < 400) {
                   return response;
                 } else {
-                  throw new ErrorResponse(response);
+                  throw new ErrorResponse(
+                      request.getRequestLine().getUri() + ": ", response);
                 }
               } catch (final IOException e) {
                 throw new KnoxShellException(e.toString(), e);
@@ -411,11 +466,13 @@ public class KnoxSession implements Closeable {
       }
 
     } else {
-      CloseableHttpResponse response = client.execute( host, request, context );
-      if( response.getStatusLine().getStatusCode() < 400 ) {
+
+      CloseableHttpResponse response = client.execute(host, request, context);
+      if (response.getStatusLine().getStatusCode() < 400) {
         return response;
       } else {
-        throw new ErrorResponse( response );
+        throw new ErrorResponse(request.getRequestLine().getUri() + ": ",
+            response);
       }
     }
 
@@ -476,4 +533,11 @@ public class KnoxSession implements Closeable {
       throw new KnoxShellException("Can not shutdown underlying resources", e);
     }
   }
+
+  @Override
+  public String toString() {
+    final StringBuilder sb = new StringBuilder(
+        "KnoxSession{base='").append(base).append("\'}");
+    return sb.toString();
+  }
 }
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxShellMessages.java
similarity index 58%
copy from gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
copy to gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxShellMessages.java
index 92661e9..f3671b2 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/ErrorResponse.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxShellMessages.java
@@ -17,19 +17,15 @@
  */
 package org.apache.knox.gateway.shell;
 
-import org.apache.http.HttpResponse;
+import java.io.IOException;
 
-class ErrorResponse extends RuntimeException {
-
-  HttpResponse response;
-
-  ErrorResponse( HttpResponse response ) {
-    super(String.valueOf(response.getStatusLine()));
-    this.response = response;
-  }
-
-  public HttpResponse getReponse() {
-    return response;
-  }
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+import org.apache.knox.gateway.i18n.messages.StackTrace;
 
+@Messages(logger="org.apache.knox.gateway.shell")
+public interface KnoxShellMessages {
+  @Message( level = MessageLevel.WARN, text = "Unable to load provided PEM encoded trusted
cert - falling through for other truststores: {0}" )
+  void unableToLoadProvidedPEMEncodedTrustedCert(@StackTrace( level = MessageLevel.DEBUG
) IOException e);
 }
diff --git a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollector.java
b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollector.java
index 412764b..31ae149 100644
--- a/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollector.java
+++ b/gateway-shell/src/main/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollector.java
@@ -39,31 +39,52 @@ public class KnoxTokenCredentialCollector extends AbstractCredentialCollector
{
 
   private String tokenType;
 
+  private String endpointPublicCertPem;
+
+  private long expiresIn;
+
+  /* (non-Javadoc)
+   * @see CredentialCollector#collect()
+   */
   @Override
   public void collect() throws CredentialCollectionException {
+    try {
+      String knoxtoken = getCachedKnoxToken();
+      if (knoxtoken != null) {
+        Map<String, String> attrs = JsonUtils.getMapFromJsonString(knoxtoken);
+        value = attrs.get("access_token");
+        targetUrl = attrs.get("target_url");
+        tokenType = attrs.get("token_type");
+        endpointPublicCertPem = attrs.get("endpoint_public_cert");
+        expiresIn = Long.parseLong(attrs.get("expires_in"));
+        if (expiresIn > 0) {
+          Date expires = new Date(expiresIn);
+          if (expires.before(new Date())) {
+            throw new CredentialCollectionException("Cached knox token has expired. Please
relogin through knoxinit.");
+          }
+        }
+      } else {
+        throw new CredentialCollectionException("Cached knox token cannot be found. Please
login through knoxinit.");
+      }
+    } catch (IOException e) {
+      throw new CredentialCollectionException("Cached knox token cannot be read. Please login
through knoxinit.", e);
+    }
+  }
+
+  protected String getCachedKnoxToken() throws IOException {
+    String line = null;
     String userDir = System.getProperty("user.home");
     File knoxtoken = new File(userDir, KNOXTOKENCACHE);
     if (knoxtoken.exists()) {
       Path path = Paths.get(knoxtoken.toURI());
       List<String> lines;
-      try {
-        lines = Files.readAllLines(path, StandardCharsets.UTF_8);
-        if (!lines.isEmpty()) {
-          Map<String, String> attrs = JsonUtils.getMapFromJsonString(lines.get(0));
-          value = attrs.get("access_token");
-          targetUrl = attrs.get("target_url");
-          tokenType = attrs.get("token_type");
-          Date expires = new Date(Long.parseLong(attrs.get("expires_in")));
-          if (expires.before(new Date())) {
-            throw new CredentialCollectionException("Cached knox token has expired. Please
relogin through knoxinit.");
-          }
-        }
-      } catch (IOException e) {
-        throw new CredentialCollectionException("Cached knox token cannot be read. Please
login through knoxinit.", e);
+      lines = Files.readAllLines(path, StandardCharsets.UTF_8);
+      if (!lines.isEmpty()) {
+        line = lines.get(0);
       }
-    } else {
-      throw new CredentialCollectionException("Cached knox token cannot be found. Please
login through knoxinit.");
     }
+
+    return line;
   }
 
   public String getTargetUrl() {
@@ -74,6 +95,17 @@ public class KnoxTokenCredentialCollector extends AbstractCredentialCollector
{
     return tokenType;
   }
 
+  public String getEndpointClientCertPEM() {
+    return endpointPublicCertPem;
+  }
+
+  public long getExpiresIn() {
+    return expiresIn;
+  }
+
+  /* (non-Javadoc)
+   * @see CredentialCollector#name()
+   */
   @Override
   public String type() {
     return COLLECTOR_TYPE;
diff --git a/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxSessionTest.java
b/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxSessionTest.java
new file mode 100644
index 0000000..56e5712
--- /dev/null
+++ b/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxSessionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.shell;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+public class KnoxSessionTest {
+  public static final String PEM = "MIICOjCCAaOgAwIBAgIJAN5kp1oW3Up8MA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNVBAYTAlVTMQ0w\n"
+      + "CwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ8wDQYDVQQKEwZIYWRvb3AxDTALBgNVBAsTBFRl\n"
+      + "c3QxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xODEyMTMwMzE2MTFaFw0xOTEyMTMwMzE2MTFaMF8x\n"
+      + "CzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ8wDQYDVQQKEwZIYWRv\n"
+      + "b3AxDTALBgNVBAsTBFRlc3QxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOB\n"
+      + "jQAwgYkCgYEAqxnzKNhNgPEeOWsTabaxR9N3QjKohvDOrAwwVvzVhHIb1GKRo+TfSkDozS3BmzuO\n"
+      + "+xQN6LvIsE6pzl+TFvTJvM9Ir5vMyybww8ZVkeD7vaHvBT9+w+1R79wYEhC7kqj68bGJJpl+1fGa\n"
+      + "c6yTKBYcAs3hO54Zg56rgreQKwXeBysCAwEAATANBgkqhkiG9w0BAQUFAAOBgQACFpBmy7KgSiBG\n"
+      + "0flF1+l8KXCU7t3LL8F3RlJSF4fyexfojilkHW7u6TdJbrAsz5nhe85AchFl6/jtmvCMGMFPobMI\n"
+      + "f/44w9sYdC3u604wJy8CF5xKqDb/en4xmiLnEc0LzOeEvtFv0ociu82SuRara7ua1J6UR9JsNu5p\n"
+      + "dWEFEA==\n";
+
+  @Test
+  public void testParsingPublicCertPem() throws Exception {
+
+    final ClientContext context = ClientContext.with("https://localhost:8443/gateway/dt");
+    context.connection().withPublicCertPem(PEM);
+    KnoxSession session = KnoxSession.login(context);
+    session.close();
+  }
+
+  @Test
+  public void testParsingInvalidPublicCertPem() throws Exception {
+
+    final ClientContext context = ClientContext.with("https://localhost:8443/gateway/dt");
+    try {
+      context.connection().withPublicCertPem("INVLID-" + PEM);
+      KnoxSession session = KnoxSession.login(context);
+      fail("Invalid Public Cert should have resulted in CertificateException wrapped by KnoxShellException");
+      session.close();
+    }
+    catch (KnoxShellException e) {
+      assertTrue(e.getCause().toString().contains("CertificateException"));
+    }
+  }
+
+  @Test
+  public void testParsingPublicCertPemWithCertDelimiters() throws Exception {
+
+    final ClientContext context = ClientContext.with("https://localhost:8443/gateway/dt");
+    try {
+      context.connection().withPublicCertPem(KnoxSession.BEGIN_CERTIFICATE + PEM + KnoxSession.END_CERTIFICATE);
+      KnoxSession session = KnoxSession.login(context);
+      session.close();
+    }
+    catch (KnoxShellException e) {
+      fail("Should have been able to parse cert with BEGIN and END Certificate delimiters.");
+    }
+  }
+}
diff --git a/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollectorTest.java
b/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollectorTest.java
index 5ca06bc..65e5cd8 100644
--- a/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollectorTest.java
+++ b/gateway-shell/src/test/java/org/apache/knox/gateway/shell/KnoxTokenCredentialCollectorTest.java
@@ -16,18 +16,40 @@
  */
 package org.apache.knox.gateway.shell;
 
-import org.apache.commons.io.FileUtils;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
 
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import org.apache.commons.io.FileUtils;
+import org.apache.knox.gateway.util.JsonUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
 public class KnoxTokenCredentialCollectorTest {
+  public static final String PEM = "MIICOjCCAaOgAwIBAgIJAN5kp1oW3Up8MA0GCSqGSIb3DQEBBQUAMF8xCzAJBgNVBAYTAlVTMQ0w\n"
+      + "CwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ8wDQYDVQQKEwZIYWRvb3AxDTALBgNVBAsTBFRl\n"
+      + "c3QxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xODEyMTMwMzE2MTFaFw0xOTEyMTMwMzE2MTFaMF8x\n"
+      + "CzAJBgNVBAYTAlVTMQ0wCwYDVQQIEwRUZXN0MQ0wCwYDVQQHEwRUZXN0MQ8wDQYDVQQKEwZIYWRv\n"
+      + "b3AxDTALBgNVBAsTBFRlc3QxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOB\n"
+      + "jQAwgYkCgYEAqxnzKNhNgPEeOWsTabaxR9N3QjKohvDOrAwwVvzVhHIb1GKRo+TfSkDozS3BmzuO\n"
+      + "+xQN6LvIsE6pzl+TFvTJvM9Ir5vMyybww8ZVkeD7vaHvBT9+w+1R79wYEhC7kqj68bGJJpl+1fGa\n"
+      + "c6yTKBYcAs3hO54Zg56rgreQKwXeBysCAwEAATANBgkqhkiG9w0BAQUFAAOBgQACFpBmy7KgSiBG\n"
+      + "0flF1+l8KXCU7t3LL8F3RlJSF4fyexfojilkHW7u6TdJbrAsz5nhe85AchFl6/jtmvCMGMFPobMI\n"
+      + "f/44w9sYdC3u604wJy8CF5xKqDb/en4xmiLnEc0LzOeEvtFv0ociu82SuRara7ua1J6UR9JsNu5p\n"
+      + "dWEFEA==\n";
+
+  public static final String JWT = "eyJhbGciOiJSUzI1NiJ9."
+      + "eyJzdWIiOiJndWVzdCIsImF1ZCI6InRva2VuYmFzZWQiLCJpc3MiOiJLTk9YU1NPIiwiZXhwIjoxNT"
+      + "Q0ODMxNTI3fQ.gcIuNQN1_6dF6guk_7-QZo13xQMtlhtrc53H0lBzhj4Ft8OjUw-QNNMz6-bohz5Al"
+      + "XBF6r_whfqFBm8MZUHIh8-hmqt91458acqR3jtJNDrjs5cv2ExaycK40KgyX58cnh6wfph5RLgiAo4"
+      + "j3zRSOaykZBq8W1DhYliXkRBFm1w";
 
   private static final File tokenCacheBackup = new File("tokenCacheBackup.bin");
 
@@ -78,12 +100,17 @@ public class KnoxTokenCredentialCollectorTest {
       fail("Could not create empty Knox token cache file: " + e.getMessage());
     }
 
+    boolean caughtCredentialCollectionException = false;
+
     // Attempt to collect the Knox token
     KnoxTokenCredentialCollector collector = new KnoxTokenCredentialCollector();
     try {
       collector.collect();
+    } catch (CredentialCollectionException e) {
+      // Expected
+      caughtCredentialCollectionException = true;
     } catch (Exception e) {
-      fail(e.getMessage());
+      fail("Unexpected exception: " + e.getMessage());
     } finally {
       try {
         getTokenCacheFile().delete();
@@ -91,6 +118,39 @@ public class KnoxTokenCredentialCollectorTest {
         // Ignore
       }
     }
+
+    assertTrue("Expected exception not thrown.", caughtCredentialCollectionException);
+  }
+
+  @Test
+  public void testParsingPublicCertPem() throws Exception {
+    Map<String, Object> map = new HashMap<>();
+    map.put("access_token", JWT);
+    map.put("target_url", "https://localhost:8443/gateway/sandbox" );
+    map.put("token_type", "Bearer");
+    map.put("endpoint_public_cert", PEM);
+
+    // NOTE: we are setting the expiry to -1 however this is not the actual expiration inside
+    // the JWT. Any tests that are added to test that the token is not meant to expire will
fail.
+    map.put("expires_in", -1L);
+    Credentials credentials = new org.apache.knox.gateway.shell.Credentials();
+    KnoxTokenCredentialCollector knoxTokenCollector = new KnoxTokenCredentialCollector()
{
+      @Override
+      protected String getCachedKnoxToken() throws IOException {
+        return JsonUtils.renderAsJsonString(map);
+      }
+    };
+
+    credentials.add(knoxTokenCollector, "none: ", "token");
+    credentials.collect();
+
+    KnoxTokenCredentialCollector token = (KnoxTokenCredentialCollector) credentials.get("token");
+
+    assertEquals(token.string(), map.get("access_token"));
+    assertEquals(token.getTargetUrl(), map.get("target_url"));
+    assertEquals(token.getTokenType(), map.get("token_type"));
+    assertEquals(token.getEndpointClientCertPEM(), map.get("endpoint_public_cert"));
+    assertEquals(token.getExpiresIn(), map.get("expires_in"));
   }
 
 }
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
index 8e0a370..7e051ee 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/impl/X509CertificateUtil.java
@@ -25,8 +25,8 @@ import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
+import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
@@ -40,12 +40,14 @@ import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.Date;
 
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.knox.gateway.i18n.GatewaySpiMessages;
-import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 
 public class X509CertificateUtil {
 
+  public static final String END_CERTIFICATE = "-----END CERTIFICATE-----\n";
+  public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----\n";
   private static GatewaySpiMessages LOG = MessagesFactory.get(GatewaySpiMessages.class);
 
   /**
@@ -56,7 +58,8 @@ public class X509CertificateUtil {
    * @param algorithm the signing algorithm, eg "SHA1withRSA"
    * @return self-signed X.509 certificate
    */
-  public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String
algorithm) {
+  public static X509Certificate generateCertificate(String dn, KeyPair pair,
+      int days, String algorithm) throws GeneralSecurityException, IOException {
 
   PrivateKey privkey = pair.getPrivate();
   Object x509CertImplObject = null;
@@ -276,11 +279,11 @@ public class X509CertificateUtil {
   public static void writeCertificateToFile(Certificate cert, final File file)
        throws CertificateEncodingException, IOException {
     byte[] bytes = cert.getEncoded();
-    Base64 encoder = new Base64( 76, "\n".getBytes( StandardCharsets.US_ASCII ) );
+    Base64 encoder = new Base64( 76, "\n".getBytes( "ASCII" ) );
     try(OutputStream out = Files.newOutputStream(file.toPath()) ) {
-      out.write( "-----BEGIN CERTIFICATE-----\n".getBytes( StandardCharsets.US_ASCII ) );
-      out.write( encoder.encodeToString( bytes ).getBytes( StandardCharsets.US_ASCII ) );
-      out.write( "-----END CERTIFICATE-----\n".getBytes( StandardCharsets.US_ASCII ) );
+      out.write( BEGIN_CERTIFICATE.getBytes( "ASCII" ) );
+      out.write( encoder.encodeToString( bytes ).getBytes( "ASCII" ) );
+      out.write( END_CERTIFICATE.getBytes( "ASCII" ) );
     }
   }
 


Mime
View raw message