]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.cms/src/org/argeo/cms/client/CmsClient.java
Introduce CMS client
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / client / CmsClient.java
diff --git a/org.argeo.cms/src/org/argeo/cms/client/CmsClient.java b/org.argeo.cms/src/org/argeo/cms/client/CmsClient.java
new file mode 100644 (file)
index 0000000..af06560
--- /dev/null
@@ -0,0 +1,172 @@
+package org.argeo.cms.client;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.net.http.HttpResponse.BodyHandler;
+import java.net.http.HttpResponse.BodyHandlers;
+import java.net.http.WebSocket;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.concurrent.CompletableFuture;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.cms.auth.ConsoleCallbackHandler;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.util.http.HttpHeader;
+
+/** Utility to connect to a remote CMS node. */
+public class CmsClient {
+       public final static String CLIENT_LOGIN_CONTEXT = "CLIENT";
+
+       private URI uri;
+
+       private HttpClient httpClient;
+       private String gssToken;
+
+       public CmsClient(URI uri) {
+               this.uri = uri;
+       }
+
+       public void login() {
+               String server = uri.getHost();
+
+               URL jaasUrl = CmsClient.class.getResource("jaas-client-ipa.cfg");
+               System.setProperty("java.security.auth.login.config", jaasUrl.toExternalForm());
+               try {
+                       LoginContext lc = new LoginContext(CLIENT_LOGIN_CONTEXT, new ConsoleCallbackHandler());
+                       lc.login();
+                       gssToken = RemoteAuthUtils.createGssToken(lc.getSubject(), "HTTP", server);
+               } catch (LoginException e) {
+                       // TODO Auto-generated catch block
+                       e.printStackTrace();
+               } finally {
+
+               }
+       }
+
+       public String getAsString() {
+               return getAsString(uri);
+       }
+
+       public String getAsString(URI uri) {
+               uri = normalizeUri(uri);
+               try {
+                       HttpClient httpClient = getHttpClient();
+
+                       HttpRequest request = HttpRequest.newBuilder().uri(uri) //
+                                       .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + getGssToken()) //
+                                       .build();
+                       BodyHandler<String> bodyHandler = BodyHandlers.ofString();
+                       HttpResponse<String> response = httpClient.send(request, bodyHandler);
+                       return response.body();
+//                     int responseCode = response.statusCode();
+//                     System.exit(responseCode);
+               } catch (IOException | InterruptedException e) {
+                       throw new RuntimeException("Cannot read " + uri + " as a string", e);
+               }
+       }
+
+       protected URI normalizeUri(URI uri) {
+               if (uri.getHost() != null)
+                       return uri;
+               try {
+                       String path = uri.getPath();
+                       if (path.startsWith("/")) {// absolute
+                               return new URI(this.uri.getScheme(), this.uri.getUserInfo(), this.uri.getHost(), this.uri.getPort(),
+                                               path, uri.getQuery(), uri.getFragment());
+                       } else {
+                               String thisUriStr = this.uri.toString();
+                               if (!thisUriStr.endsWith("/"))
+                                       thisUriStr = thisUriStr + "/";
+                               return URI.create(thisUriStr + path);
+                       }
+               } catch (URISyntaxException e) {
+                       throw new IllegalArgumentException("Cannot interpret " + uri, e);
+               }
+       }
+
+       public URI getUri() {
+               return uri;
+       }
+
+       String getGssToken() {
+               return gssToken;
+       }
+
+       public HttpClient getHttpClient() {
+               if (httpClient == null) {
+                       login();
+                       HttpClient client = HttpClient.newBuilder() //
+                                       .sslContext(ipaSslContext()) //
+                                       .version(HttpClient.Version.HTTP_1_1) //
+                                       .build();
+                       httpClient = client;
+               }
+               return httpClient;
+       }
+
+       public CompletableFuture<WebSocket> newWebSocket(WebSocket.Listener listener) {
+               return newWebSocket(uri, listener);
+       }
+
+       public CompletableFuture<WebSocket> newWebSocket(URI uri, WebSocket.Listener listener) {
+               CompletableFuture<WebSocket> ws = getHttpClient().newWebSocketBuilder()
+                               .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + getGssToken())
+                               .buildAsync(uri, listener);
+               return ws;
+       }
+
+       @SuppressWarnings("unchecked")
+       protected SSLContext ipaSslContext() {
+               try {
+                       final Collection<X509Certificate> certificates;
+                       Path caCertificatePath = Paths.get("/etc/ipa/ca.crt");
+                       if (Files.exists(caCertificatePath)) {
+                               CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
+                               try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(caCertificatePath))) {
+                                       certificates = (Collection<X509Certificate>) certificateFactory.generateCertificates(in);
+                               }
+                       } else {
+                               certificates = null;
+                       }
+                       TrustManager[] noopTrustManager = new TrustManager[] { new X509TrustManager() {
+                               public void checkClientTrusted(X509Certificate[] xcs, String string) {
+                               }
+
+                               public void checkServerTrusted(X509Certificate[] xcs, String string) {
+                               }
+
+                               public X509Certificate[] getAcceptedIssuers() {
+                                       if (certificates == null)
+                                               return null;
+                                       return certificates.toArray(new X509Certificate[certificates.size()]);
+                               }
+                       } };
+
+                       SSLContext sc = SSLContext.getInstance("ssl");
+                       sc.init(null, noopTrustManager, null);
+                       return sc;
+               } catch (KeyManagementException | NoSuchAlgorithmException | CertificateException | IOException e) {
+                       throw new IllegalStateException("Cannot create SSL context ", e);
+               }
+       }
+
+}