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.cms.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 bodyHandler = BodyHandlers.ofString(); HttpResponse 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 newWebSocket(WebSocket.Listener listener) { return newWebSocket(uri, listener); } public CompletableFuture newWebSocket(URI uri, WebSocket.Listener listener) { CompletableFuture ws = getHttpClient().newWebSocketBuilder() .header(HttpHeader.AUTHORIZATION.getHeaderName(), HttpHeader.NEGOTIATE + " " + getGssToken()) .buildAsync(uri, listener); return ws; } @SuppressWarnings("unchecked") protected SSLContext ipaSslContext() { try { final Collection 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) 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); } } }