1 package org
.argeo
.cms
.client
;
3 import java
.io
.BufferedInputStream
;
4 import java
.io
.IOException
;
6 import java
.net
.URISyntaxException
;
8 import java
.net
.http
.HttpClient
;
9 import java
.net
.http
.HttpRequest
;
10 import java
.net
.http
.HttpResponse
;
11 import java
.net
.http
.HttpResponse
.BodyHandler
;
12 import java
.net
.http
.HttpResponse
.BodyHandlers
;
13 import java
.net
.http
.WebSocket
;
14 import java
.nio
.file
.Files
;
15 import java
.nio
.file
.Path
;
16 import java
.nio
.file
.Paths
;
17 import java
.security
.KeyManagementException
;
18 import java
.security
.NoSuchAlgorithmException
;
19 import java
.security
.cert
.CertificateException
;
20 import java
.security
.cert
.CertificateFactory
;
21 import java
.security
.cert
.X509Certificate
;
22 import java
.util
.Collection
;
23 import java
.util
.concurrent
.CompletableFuture
;
25 import javax
.net
.ssl
.SSLContext
;
26 import javax
.net
.ssl
.TrustManager
;
27 import javax
.net
.ssl
.X509TrustManager
;
28 import javax
.security
.auth
.login
.LoginContext
;
29 import javax
.security
.auth
.login
.LoginException
;
31 import org
.argeo
.cms
.auth
.ConsoleCallbackHandler
;
32 import org
.argeo
.cms
.auth
.RemoteAuthUtils
;
33 import org
.argeo
.cms
.http
.HttpHeader
;
35 /** Utility to connect to a remote CMS node. */
36 public class CmsClient
{
37 public final static String CLIENT_LOGIN_CONTEXT
= "CLIENT";
41 private HttpClient httpClient
;
42 private String gssToken
;
44 public CmsClient(URI uri
) {
49 String server
= uri
.getHost();
51 URL jaasUrl
= CmsClient
.class.getResource("jaas-client-ipa.cfg");
52 System
.setProperty("java.security.auth.login.config", jaasUrl
.toExternalForm());
54 LoginContext lc
= new LoginContext(CLIENT_LOGIN_CONTEXT
, new ConsoleCallbackHandler());
56 gssToken
= RemoteAuthUtils
.createGssToken(lc
.getSubject(), "HTTP", server
);
57 } catch (LoginException e
) {
58 // TODO Auto-generated catch block
65 public String
getAsString() {
66 return getAsString(uri
);
69 public String
getAsString(URI uri
) {
70 uri
= normalizeUri(uri
);
72 HttpClient httpClient
= getHttpClient();
74 HttpRequest request
= HttpRequest
.newBuilder().uri(uri
) //
75 .header(HttpHeader
.AUTHORIZATION
.getHeaderName(), HttpHeader
.NEGOTIATE
+ " " + getGssToken()) //
77 BodyHandler
<String
> bodyHandler
= BodyHandlers
.ofString();
78 HttpResponse
<String
> response
= httpClient
.send(request
, bodyHandler
);
79 return response
.body();
80 // int responseCode = response.statusCode();
81 // System.exit(responseCode);
82 } catch (IOException
| InterruptedException e
) {
83 throw new RuntimeException("Cannot read " + uri
+ " as a string", e
);
87 protected URI
normalizeUri(URI uri
) {
88 if (uri
.getHost() != null)
91 String path
= uri
.getPath();
92 if (path
.startsWith("/")) {// absolute
93 return new URI(this.uri
.getScheme(), this.uri
.getUserInfo(), this.uri
.getHost(), this.uri
.getPort(),
94 path
, uri
.getQuery(), uri
.getFragment());
96 String thisUriStr
= this.uri
.toString();
97 if (!thisUriStr
.endsWith("/"))
98 thisUriStr
= thisUriStr
+ "/";
99 return URI
.create(thisUriStr
+ path
);
101 } catch (URISyntaxException e
) {
102 throw new IllegalArgumentException("Cannot interpret " + uri
, e
);
106 public URI
getUri() {
110 String
getGssToken() {
114 public HttpClient
getHttpClient() {
115 if (httpClient
== null) {
117 HttpClient client
= HttpClient
.newBuilder() //
118 .sslContext(ipaSslContext()) //
119 .version(HttpClient
.Version
.HTTP_1_1
) //
126 public CompletableFuture
<WebSocket
> newWebSocket(WebSocket
.Listener listener
) {
127 return newWebSocket(uri
, listener
);
130 public CompletableFuture
<WebSocket
> newWebSocket(URI uri
, WebSocket
.Listener listener
) {
131 CompletableFuture
<WebSocket
> ws
= getHttpClient().newWebSocketBuilder()
132 .header(HttpHeader
.AUTHORIZATION
.getHeaderName(), HttpHeader
.NEGOTIATE
+ " " + getGssToken())
133 .buildAsync(uri
, listener
);
137 @SuppressWarnings("unchecked")
138 protected SSLContext
ipaSslContext() {
140 final Collection
<X509Certificate
> certificates
;
141 Path caCertificatePath
= Paths
.get("/etc/ipa/ca.crt");
142 if (Files
.exists(caCertificatePath
)) {
143 CertificateFactory certificateFactory
= CertificateFactory
.getInstance("X509");
144 try (BufferedInputStream in
= new BufferedInputStream(Files
.newInputStream(caCertificatePath
))) {
145 certificates
= (Collection
<X509Certificate
>) certificateFactory
.generateCertificates(in
);
150 TrustManager
[] noopTrustManager
= new TrustManager
[] { new X509TrustManager() {
151 public void checkClientTrusted(X509Certificate
[] xcs
, String string
) {
154 public void checkServerTrusted(X509Certificate
[] xcs
, String string
) {
157 public X509Certificate
[] getAcceptedIssuers() {
158 if (certificates
== null)
160 return certificates
.toArray(new X509Certificate
[certificates
.size()]);
164 SSLContext sc
= SSLContext
.getInstance("ssl");
165 sc
.init(null, noopTrustManager
, null);
167 } catch (KeyManagementException
| NoSuchAlgorithmException
| CertificateException
| IOException e
) {
168 throw new IllegalStateException("Cannot create SSL context ", e
);