1 package com.guinetik.rr.auth;
2
3 import com.guinetik.rr.RocketRestConfig;
4 import com.guinetik.rr.http.RocketClient;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import javax.net.ssl.KeyManagerFactory;
9 import javax.net.ssl.SSLContext;
10 import javax.net.ssl.TrustManager;
11 import javax.net.ssl.X509TrustManager;
12 import java.io.InputStream;
13 import java.nio.file.Files;
14 import java.nio.file.Paths;
15 import java.security.KeyStore;
16 import java.security.NoSuchAlgorithmException;
17 import java.security.cert.X509Certificate;
18 import java.util.HashMap;
19 import java.util.Map;
20
21
22
23
24
25 public class RocketSSL {
26
27 private static final Logger logger = LoggerFactory.getLogger(RocketSSL.class);
28
29
30
31
32 public interface SSLConfig {
33 String getCustomCertificateFilename();
34
35 String getCustomCertificatePassword();
36
37 boolean isCustomCertificateEnabled();
38 }
39
40
41
42
43
44
45 public interface SSLAware {
46
47
48
49
50
51
52 void configureSsl(SSLContext sslContext);
53 }
54
55
56
57
58 public static class SSLCertificate {
59 private String certificateFilename;
60 private String certificatePassword;
61
62 public SSLCertificate(String certificateFilename, String certificatePassword) {
63 this.certificateFilename = certificateFilename;
64 this.certificatePassword = certificatePassword;
65 }
66
67 public SSLCertificate() {
68 }
69
70 public String getCertificateFilename() {
71 return certificateFilename;
72 }
73
74 public void setCertificateFilename(String certificateFilename) {
75 this.certificateFilename = certificateFilename;
76 }
77
78 public String getCertificatePassword() {
79 return certificatePassword;
80 }
81
82 public void setCertificatePassword(String certificatePassword) {
83 this.certificatePassword = certificatePassword;
84 }
85 }
86
87 private Map<String, SSLContext> sslContexts = new HashMap<>();
88
89
90
91
92
93
94
95 public synchronized SSLContext getSSLContext(SSLCertificate SSLCertificate) {
96 return getSSLContext(SSLCertificate.getCertificateFilename(), SSLCertificate.getCertificatePassword());
97 }
98
99
100
101
102
103
104
105
106 public synchronized SSLContext getSSLContext(String fileName, String certPass) {
107 SSLContext sc;
108 if (sslContexts.get(fileName) != null)
109 return sslContexts.get(fileName);
110 try {
111 TrustManager tm = new X509TrustManager() {
112 public void checkClientTrusted(X509Certificate[] chain, String authType) {
113 }
114
115 public void checkServerTrusted(X509Certificate[] chain, String authType) {
116 }
117
118 public X509Certificate[] getAcceptedIssuers() {
119 return null;
120 }
121 };
122
123 if (fileName == null || certPass == null) {
124 throw new IllegalArgumentException("Security certificate file name or password not found.");
125 }
126 KeyManagerFactory kmf;
127
128 kmf = KeyManagerFactory.getInstance("SunX509");
129
130 InputStream fis = null;
131 try {
132 KeyStore ks = KeyStore.getInstance("PKCS12");
133 fis = Files.newInputStream(Paths.get(fileName));
134 ks.load(fis, certPass.toCharArray());
135 kmf.init(ks, certPass.toCharArray());
136 } finally {
137 if (fis != null) {
138 fis.close();
139 }
140 }
141 try {
142
143 sc = SSLContext.getInstance("TLSv1.3");
144 } catch (NoSuchAlgorithmException e) {
145
146 logger.info("TLS 1.3 not available, falling back to TLS 1.2");
147 sc = SSLContext.getInstance("TLSv1.2");
148 }
149 sc.init(kmf.getKeyManagers(), new TrustManager[]{tm}, null);
150 sslContexts.put(fileName, sc);
151 } catch (Exception e) {
152 logger.error("Exception occurred getting SSL context: {}", e.getMessage());
153 return null;
154 }
155
156 return sc;
157 }
158
159
160
161
162
163
164
165
166
167 public static boolean configureSsl(RocketClient client, RocketRestConfig config) {
168 if (!(config instanceof SSLConfig)) {
169 return false;
170 }
171
172 SSLConfig certConfig = (SSLConfig) config;
173
174 if (!certConfig.isCustomCertificateEnabled()) {
175 return false;
176 }
177
178 String certFile = certConfig.getCustomCertificateFilename();
179 String certPass = certConfig.getCustomCertificatePassword();
180
181 if (certFile == null || certPass == null) {
182 logger.warn("Certificate file or password is null");
183 return false;
184 }
185
186 logger.info("Configuring SSL with custom certificate: {}", certFile);
187
188 SSLCertificate cert = new SSLCertificate(certFile, certPass);
189 RocketSSL ssl = new RocketSSL();
190 SSLContext sslContext = ssl.getSSLContext(cert);
191
192 if (sslContext == null) {
193 logger.error("Failed to configure SSL context with certificate: {}", certFile);
194 return false;
195 }
196
197
198 client.configureSsl(sslContext);
199
200
201 if (config.getAuthStrategy() instanceof SSLAware) {
202 ((SSLAware) config.getAuthStrategy()).configureSsl(sslContext);
203 logger.info("SSL context configured for authentication strategy");
204 }
205
206 logger.info("SSL context configured successfully");
207 return true;
208 }
209 }