21
21
import com .nimbusds .jose .JWSAlgorithm ;
22
22
import com .nimbusds .jose .jwk .KeyUse ;
23
23
import com .nimbusds .jose .jwk .RSAKey ;
24
+ import com .nimbusds .jose .util .Base64 ;
25
+ import com .nimbusds .jose .util .Base64URL ;
26
+ import net .minidev .json .JSONArray ;
27
+ import net .minidev .json .JSONObject ;
24
28
import org .apache .axis2 .AxisFault ;
25
29
import org .apache .axis2 .Constants ;
26
30
import org .apache .commons .logging .Log ;
29
33
import org .apache .synapse .commons .json .JsonUtil ;
30
34
import org .apache .synapse .core .axis2 .Axis2MessageContext ;
31
35
import org .apache .synapse .rest .AbstractHandler ;
32
- import org .json .JSONArray ;
33
- import org .json .JSONObject ;
34
36
import org .wso2 .carbon .apimgt .api .APIManagementException ;
35
37
import org .wso2 .carbon .apimgt .common .gateway .util .JWTUtil ;
38
+ import org .wso2 .carbon .apimgt .gateway .dto .CertificateInfo ;
39
+ import org .wso2 .carbon .apimgt .gateway .utils .GatewayUtils ;
36
40
import org .wso2 .carbon .apimgt .impl .APIConstants ;
37
41
import org .wso2 .carbon .apimgt .impl .dto .ExtendedJWTConfigurationDto ;
38
42
import org .wso2 .carbon .apimgt .impl .internal .ServiceReferenceHolder ;
44
48
import java .security .KeyStore ;
45
49
import java .security .KeyStoreException ;
46
50
import java .security .cert .Certificate ;
51
+ import java .security .cert .CertificateEncodingException ;
47
52
import java .security .cert .X509Certificate ;
48
53
import java .security .interfaces .RSAPublicKey ;
49
54
import java .text .ParseException ;
@@ -63,7 +68,7 @@ public class JwksHandler extends AbstractHandler {
63
68
private static final Log log = LogFactory .getLog (JwksHandler .class );
64
69
private static final String KEY_USE = "sig" ;
65
70
private static final String KEYS = "keys" ;
66
- private final Map <String , Set <Certificate >> certificateMap = new HashMap <>();
71
+ private final Map <String , Set <CertificateInfo >> certificateMap = new HashMap <>();
67
72
ExtendedJWTConfigurationDto jwtConfigurationDto ;
68
73
69
74
public boolean handleRequest (MessageContext messageContext ) {
@@ -77,7 +82,7 @@ public boolean handleRequest(MessageContext messageContext) {
77
82
axis2MsgContext .setProperty (Constants .Configuration .MESSAGE_TYPE , APIConstants .APPLICATION_JSON_MEDIA_TYPE );
78
83
axis2MsgContext .setProperty (Constants .Configuration .CONTENT_TYPE , APIConstants .APPLICATION_JSON_MEDIA_TYPE );
79
84
axis2MsgContext .removeProperty (APIConstants .NO_ENTITY_BODY );
80
- } catch (ParseException | AxisFault | APIManagementException e ) {
85
+ } catch (ParseException | AxisFault | APIManagementException | CertificateEncodingException e ) {
81
86
log .error ("Error while generating payload " + axis2MsgContext .getLogIDString (), e );
82
87
}
83
88
return true ;
@@ -92,7 +97,7 @@ public boolean handleResponse(MessageContext messageContext) {
92
97
*
93
98
* @return JWKS response
94
99
*/
95
- public String getJwksEndpointResponse () throws ParseException , APIManagementException {
100
+ public String getJwksEndpointResponse () throws ParseException , APIManagementException , CertificateEncodingException {
96
101
this .jwtConfigurationDto = org .wso2 .carbon .apimgt .gateway .internal .ServiceReferenceHolder .getInstance ()
97
102
.getAPIManagerConfiguration ().getJwtConfigurationDto ();
98
103
boolean isTenantBasedSigningEnabled = jwtConfigurationDto .isTenantBasedSigningEnabled ();
@@ -103,7 +108,7 @@ public String getJwksEndpointResponse() throws ParseException, APIManagementExce
103
108
certMapKey = APIConstants .SUPER_TENANT_DOMAIN ;
104
109
}
105
110
106
- Set <Certificate > certificateSet = null ;
111
+ Set <CertificateInfo > certificateSet = null ;
107
112
if (certificateMap .containsKey (certMapKey )) {
108
113
certificateSet = certificateMap .get (certMapKey );
109
114
} else {
@@ -126,24 +131,30 @@ public String getJwksEndpointResponse() throws ParseException, APIManagementExce
126
131
* @param certificates Set of certificates
127
132
* @return JWKS response as a JSON string
128
133
*/
129
- private String buildResponse (Set <Certificate > certificates ) throws ParseException , APIManagementException {
134
+ private String buildResponse (Set <CertificateInfo > certificates ) throws ParseException , APIManagementException ,
135
+ CertificateEncodingException {
130
136
131
137
JSONArray jwksArray = new JSONArray ();
132
138
JSONObject jwksJson = new JSONObject ();
133
139
JWSAlgorithm accessTokenSignAlgorithm = mapSignatureAlgorithmForJWSAlgorithm (
134
140
ServiceReferenceHolder .getInstance ().getOauthServerConfiguration ().getSignatureAlgorithm ());
135
141
List <JWSAlgorithm > diffAlgorithms = findDifferentAlgorithms (accessTokenSignAlgorithm );
136
142
137
- for (Certificate certificate : certificates ) {
143
+ for (CertificateInfo certificateInfo : certificates ) {
138
144
for (JWSAlgorithm algorithm : diffAlgorithms ) {
139
- RSAPublicKey publicKey = (RSAPublicKey ) certificate .getPublicKey ();
145
+ String alias = certificateInfo .getCertificateAlias ();
146
+ X509Certificate x509Certificate = (X509Certificate ) certificateInfo .getCertificate ();
147
+ RSAPublicKey publicKey = (RSAPublicKey ) x509Certificate .getPublicKey ();
140
148
RSAKey .Builder jwk = new RSAKey .Builder (publicKey );
141
149
142
- X509Certificate x509Certificate = (X509Certificate ) certificate ;
150
+ Certificate [] certChain = certificateInfo .getCertificateChain ();
151
+ List <Base64 > encodedCertList = generateEncodedCertList (certChain , alias );
143
152
jwk .keyID (JWTUtil .getKID (x509Certificate ));
144
153
jwk .algorithm (algorithm );
145
154
jwk .keyUse (KeyUse .parse (KEY_USE ));
146
- jwksArray .put (jwk .build ().toJSONObject ());
155
+ jwk .x509CertChain (encodedCertList );
156
+ jwk .x509CertSHA256Thumbprint (new Base64URL (GatewayUtils .getThumbPrint (x509Certificate , alias )));
157
+ jwksArray .add (jwk .build ().toJSONObject ());
147
158
}
148
159
}
149
160
@@ -192,8 +203,8 @@ private String generateKSNameFromDomainName(String tenantDomain) {
192
203
* @param tenantDomain tenant domain which is used to get the relevant key store and extract certificates
193
204
* @return set of certificates
194
205
*/
195
- private Set <Certificate > getCertificates (String tenantDomain ) {
196
- Set <Certificate > certificates = new HashSet <>();
206
+ private Set <CertificateInfo > getCertificates (String tenantDomain ) {
207
+ Set <CertificateInfo > certificates = new HashSet <>();
197
208
KeyStore keyStore ;
198
209
try {
199
210
if (!APIConstants .SUPER_TENANT_DOMAIN .equals (tenantDomain )) {
@@ -232,13 +243,14 @@ private Set<Certificate> getCertificates(String tenantDomain) {
232
243
* @param keyStore Key store
233
244
* @return Set of certificates from the key store
234
245
*/
235
- private Set <Certificate > getCertificatesFromKeyStore (KeyStore keyStore ) throws KeyStoreException {
236
- Set <Certificate > certs = new HashSet <>();
246
+ private Set <CertificateInfo > getCertificatesFromKeyStore (KeyStore keyStore ) throws KeyStoreException {
247
+ Set <CertificateInfo > certs = new HashSet <>();
237
248
Enumeration <String > enumeration = keyStore .aliases ();
238
249
while (enumeration .hasMoreElements ()) {
239
250
String alias = enumeration .nextElement ();
240
251
if (keyStore .isKeyEntry (alias )) {
241
- Certificate publicCert = keyStore .getCertificate (alias );
252
+ CertificateInfo publicCert = new CertificateInfo (keyStore .getCertificate (alias ), alias );
253
+ publicCert .setCertificateChain (keyStore .getCertificateChain (alias ));
242
254
certs .add (publicCert );
243
255
}
244
256
}
@@ -277,4 +289,26 @@ private static JWSAlgorithm mapSignatureAlgorithmForJWSAlgorithm(String signatur
277
289
return JWSAlgorithm .PS256 ;
278
290
}
279
291
}
292
+
293
+ /**
294
+ * This method generates the base64 encoded certificate list from a Certificate array
295
+ *
296
+ * @return base64 encoded certificate list
297
+ */
298
+ private List <Base64 > generateEncodedCertList (Certificate [] certificates , String alias )
299
+ throws CertificateEncodingException {
300
+
301
+ List <Base64 > certList = new ArrayList <>();
302
+ for (Certificate certificate : certificates ) {
303
+ try {
304
+ certList .add (Base64 .encode (certificate .getEncoded ()));
305
+ } catch (CertificateEncodingException exception ) {
306
+ String errorMessage = "Unable to encode the public certificate with alias: " + alias +
307
+ " in the tenant domain: " + PrivilegedCarbonContext .getThreadLocalCarbonContext ().
308
+ getTenantDomain ();
309
+ throw new CertificateEncodingException (errorMessage , exception );
310
+ }
311
+ }
312
+ return certList ;
313
+ }
280
314
}
0 commit comments