Skip to content

Commit 91b4c94

Browse files
authored
Merge pull request wso2#12280 from npamudika/4.3.0-kernel-upgrade
Merge 4.3.0-kernel-upgrade to master
2 parents 28ffa8f + 97aaabf commit 91b4c94

File tree

58 files changed

+1768
-283
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1768
-283
lines changed

components/apimgt/org.wso2.carbon.apimgt.cache.invalidation/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
org.wso2.carbon.apimgt.impl.*;version="${carbon.apimgt.imp.pkg.version}",
7070
org.wso2.carbon.context.*;version="${carbon.kernel.package.import.version.range}",
7171
org.wso2.carbon.core.*;version="${carbon.kernel.package.import.version.range}",
72-
org.wso2.carbon.event.output.adapter.core.*,
72+
org.wso2.carbon.event.output.adapter.core.*;version ="${carbon.analytics.common.version}",
7373
org.wso2.carbon.utils.*;version="${carbon.kernel.package.import.version.range}",
7474
*;resolution:=optional
7575
</Import-Package>

components/apimgt/org.wso2.carbon.apimgt.common.gateway/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@
8989
<groupId>com.github.spotbugs</groupId>
9090
<artifactId>spotbugs-annotations</artifactId>
9191
</dependency>
92+
<dependency>
93+
<groupId>org.json.wso2</groupId>
94+
<artifactId>json</artifactId>
95+
</dependency>
9296
</dependencies>
9397

9498
<build>

components/apimgt/org.wso2.carbon.apimgt.gateway/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@
204204
<artifactId>slf4j-api</artifactId>
205205
<scope>test</scope>
206206
</dependency>
207+
<dependency>
208+
<groupId>org.wso2.orbit.com.nimbusds</groupId>
209+
<artifactId>nimbus-jose-jwt</artifactId>
210+
</dependency>
207211
<dependency>
208212
<groupId>org.powermock</groupId>
209213
<artifactId>powermock-module-junit4</artifactId>

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/APIMgtGatewayConstants.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* You may obtain a copy of the License at
88
*
99
* http://www.apache.org/licenses/LICENSE-2.0
10-
*
10+
1111
* Unless required by applicable law or agreed to in writing,
1212
* software distributed under the License is distributed on an
1313
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -191,6 +191,10 @@ public class APIMgtGatewayConstants {
191191

192192
//This will be a reserved name for the synapse message context properties.
193193
public static final String ADDITIONAL_ANALYTICS_PROPS = "ADDITIONAL_ANALYTICS_PROPS_TO_PUBLISH";
194+
195+
public static final String AZP_JWT_CLAIM = "azp";
196+
public static final String ENTITY_ID_JWT_CLAIM = "entity_id";
197+
194198
public static final String ACCESS_GRANT_CLAIM_NAME = "grantVerificationClaim";
195199
public static final String ACCESS_GRANT_CLAIM_VALUE = "grantVerificationClaimValue";
196200
public static final String SHOULD_ALLOW_ACCESS_VALIDATION = "shouldAllowValidation";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
package org.wso2.carbon.apimgt.gateway.dto;
20+
21+
import com.google.gson.annotations.SerializedName;
22+
23+
import java.util.List;
24+
25+
public class RevokedEventsDTO {
26+
27+
@SerializedName("revokedJWTList")
28+
private List<RevokedJWTTokenDTO> revokedJWTList;
29+
30+
@SerializedName("revokedJWTConsumerKeyList")
31+
private List<RevokedJWTConsumerKeyDTO> revokedConsumerKeyList;
32+
33+
@SerializedName("revokedJWTSubjectEntityList")
34+
private List<RevokedJWTSubjectEntityDTO> revokedJWTSubjectEntityList;
35+
36+
public List<RevokedJWTTokenDTO> getRevokedJWTList() {
37+
return revokedJWTList;
38+
}
39+
40+
public void setRevokedJWTList(List<RevokedJWTTokenDTO> revokedJWTList) {
41+
this.revokedJWTList = revokedJWTList;
42+
}
43+
44+
public List<RevokedJWTConsumerKeyDTO> getRevokedConsumerKeyList() {
45+
return revokedConsumerKeyList;
46+
}
47+
48+
public void setRevokedConsumerKeyList(List<RevokedJWTConsumerKeyDTO> revokedConsumerKeyList) {
49+
this.revokedConsumerKeyList = revokedConsumerKeyList;
50+
}
51+
52+
public List<RevokedJWTSubjectEntityDTO> getRevokedSubjectEntityList() {
53+
return revokedJWTSubjectEntityList;
54+
}
55+
56+
public void setRevokedSubjectEntityList(List<RevokedJWTSubjectEntityDTO> subjectEntityDTOList) {
57+
this.revokedJWTSubjectEntityList = subjectEntityDTOList;
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
package org.wso2.carbon.apimgt.gateway.dto;
20+
21+
import com.google.gson.annotations.SerializedName;
22+
23+
/**
24+
* DTO of revoked JWT Consumer key.
25+
*/
26+
public class RevokedJWTConsumerKeyDTO {
27+
28+
@SerializedName("consumer_key")
29+
private String consumerKey;
30+
@SerializedName("revocation_time")
31+
private Long revocationTime;
32+
@SerializedName("organization")
33+
private String organization;
34+
35+
public void setRevocationTime(Long revocationTime) {
36+
this.revocationTime = revocationTime;
37+
}
38+
39+
public Long getRevocationTime() {
40+
return revocationTime;
41+
}
42+
43+
public String getConsumerKey() {
44+
return consumerKey;
45+
}
46+
47+
public void setConsumerKey(String consumerKey) {
48+
this.consumerKey = consumerKey;
49+
}
50+
51+
public String getOrganization() {
52+
return organization;
53+
}
54+
55+
public void setOrganization(String organization) {
56+
this.organization = organization;
57+
}
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
3+
*
4+
* WSO2 LLC. licenses this file to you under the Apache License,
5+
* Version 2.0 (the "License"); you may not use this file except
6+
* in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing,
12+
* software distributed under the License is distributed on an
13+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
* KIND, either express or implied. See the License for the
15+
* specific language governing permissions and limitations
16+
* under the License.
17+
*/
18+
19+
package org.wso2.carbon.apimgt.gateway.dto;
20+
21+
import com.google.gson.annotations.SerializedName;
22+
23+
/**
24+
* DTO of revoked JWT Subject Entity.
25+
*/
26+
public class RevokedJWTSubjectEntityDTO {
27+
28+
@SerializedName("entity_id")
29+
private String entityId;
30+
@SerializedName("entity_type")
31+
private String entityType;
32+
@SerializedName("revocation_time")
33+
private Long revocationTime;
34+
@SerializedName("organization")
35+
private String organization;
36+
37+
public String getEntityId() {
38+
return entityId;
39+
}
40+
41+
public void setEntityId(String entityId) {
42+
this.entityId = entityId;
43+
}
44+
45+
public String getEntityType() {
46+
return entityType;
47+
}
48+
49+
public void setEntityType(String entityType) {
50+
this.entityType = entityType;
51+
}
52+
53+
public Long getRevocationTime() {
54+
return revocationTime;
55+
}
56+
57+
public void setRevocationTime(Long revocationTime) {
58+
this.revocationTime = revocationTime;
59+
}
60+
61+
public String getOrganization() {
62+
return organization;
63+
}
64+
65+
public void setOrganization(String organization) {
66+
this.organization = organization;
67+
}
68+
}

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/jwt/JWTValidator.java

+43-1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration;
6363

6464
import java.security.cert.Certificate;
65+
import java.text.ParseException;
6566
import java.util.Base64;
6667
import java.util.Date;
6768
import java.util.HashMap;
@@ -177,7 +178,48 @@ public AuthenticationContext authenticate(SignedJWTInfo signedJWTInfo, MessageCo
177178
"Invalid JWT token");
178179
}
179180
}
180-
181+
Object authorizedPartyClaim = signedJWTInfo.getJwtClaimsSet().getClaim(APIMgtGatewayConstants.AZP_JWT_CLAIM);
182+
Object entityIdClaim = signedJWTInfo.getJwtClaimsSet().getClaim(APIMgtGatewayConstants.ENTITY_ID_JWT_CLAIM);
183+
long jwtGeneratedTime = 0;
184+
try {
185+
jwtGeneratedTime = signedJWTInfo.getSignedJWT().getJWTClaimsSet().getIssueTime().getTime();
186+
} catch (ParseException e) {
187+
log.error("Error while obtaining JWT token generated time " + GatewayUtils.getMaskedToken(jwtHeader));
188+
}
189+
if (jwtGeneratedTime != 0 && authorizedPartyClaim != null && entityIdClaim != null) {
190+
String authorizedParty = (String) authorizedPartyClaim;
191+
String entityId = (String) entityIdClaim;
192+
if (RevokedJWTDataHolder.getInstance().isRevokedConsumerKeyExists(authorizedParty, jwtGeneratedTime)) {
193+
if (log.isDebugEnabled()) {
194+
log.debug("Consumer key retrieved from the jwt token map is in revoked consumer key map."
195+
+ " Token: " + GatewayUtils.getMaskedToken(jwtHeader));
196+
}
197+
log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(jwtHeader));
198+
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS,
199+
"Invalid JWT token");
200+
}
201+
if (StringUtils.equals(entityId, authorizedParty)
202+
&& RevokedJWTDataHolder.getInstance().isRevokedSubjectEntityConsumerAppExists(
203+
entityId, jwtGeneratedTime)) {
204+
// handle user event revocations of app tokens since the 'sub' claim is client id
205+
if (log.isDebugEnabled()) {
206+
log.debug("Consumer key retrieved from the jwt token map is in revoked consumer key map."
207+
+ " Token: " + GatewayUtils.getMaskedToken(jwtHeader));
208+
}
209+
log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(jwtHeader));
210+
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS, "Invalid JWT token");
211+
}
212+
if (!StringUtils.equals(entityId, authorizedParty) && RevokedJWTDataHolder.getInstance()
213+
.isRevokedSubjectEntityUserExists(entityId, jwtGeneratedTime)) {
214+
if (log.isDebugEnabled()) {
215+
log.debug("User id retrieved from the jwt token map is in revoked user id map."
216+
+ " Token: " + GatewayUtils.getMaskedToken(jwtHeader));
217+
}
218+
log.error("Invalid JWT token. " + GatewayUtils.getMaskedToken(jwtHeader));
219+
throw new APISecurityException(APISecurityConstants.API_AUTH_INVALID_CREDENTIALS,
220+
"Invalid JWT token");
221+
}
222+
}
181223
JWTValidationInfo jwtValidationInfo = getJwtValidationInfo(signedJWTInfo, jwtTokenIdentifier);
182224

183225
if (jwtValidationInfo != null) {

components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/jwt/RevokedJWTDataHolder.java

+66
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.commons.logging.Log;
2121
import org.apache.commons.logging.LogFactory;
2222

23+
import java.sql.Timestamp;
2324
import java.util.Map;
2425
import java.util.concurrent.ConcurrentHashMap;
2526

@@ -30,6 +31,10 @@ public class RevokedJWTDataHolder {
3031

3132
private static final Log log = LogFactory.getLog(RevokedJWTDataHolder.class);
3233
private static Map<String, Long> revokedJWTMap = new ConcurrentHashMap<>();
34+
private static final Map<String, Long> revokedConsumerKeyMap = new ConcurrentHashMap<>();
35+
private static final Map<String, Long> revokedSubjectEntityAppMap = new ConcurrentHashMap<>();
36+
// User UUID (jwt claim) -> revoked timestamp
37+
private static final Map<String, Long> revokedSubjectEntityUserMap = new ConcurrentHashMap<>();
3338
private static RevokedJWTDataHolder instance = new RevokedJWTDataHolder();
3439

3540
/**
@@ -72,4 +77,65 @@ Map<String, Long> getRevokedJWTMap() {
7277
public static RevokedJWTDataHolder getInstance() {
7378
return instance;
7479
}
80+
81+
public void addRevokedConsumerKeyToMap(String consumerKey, Long revocationTime) {
82+
83+
if (log.isDebugEnabled()) {
84+
log.debug("Adding internal revoked JWT client Id, revocation time pair to the " + "revoked map :"
85+
+ consumerKey + " , revocationTime:" + revocationTime);
86+
}
87+
revokedConsumerKeyMap.put(consumerKey, revocationTime);
88+
}
89+
90+
public boolean isRevokedConsumerKeyExists(String consumerKey, Long jwtGeneratedTimestamp) {
91+
92+
Long jwtRevokedTime = revokedConsumerKeyMap.get(consumerKey);
93+
94+
if (jwtRevokedTime != null) {
95+
Timestamp jwtRevokedTimestamp = new Timestamp(jwtRevokedTime);
96+
jwtRevokedTimestamp.toLocalDateTime();
97+
return jwtRevokedTimestamp.after(new Timestamp(jwtGeneratedTimestamp));
98+
}
99+
return false;
100+
}
101+
102+
public void addRevokedSubjectEntityConsumerAppToMap(String consumerKey, Long revocationTime) {
103+
104+
if (log.isDebugEnabled()) {
105+
log.debug("Adding internal revoked JWT client Id, revocation time pair to the revoked app only map :"
106+
+ consumerKey + " , revocationTime:" + revocationTime);
107+
}
108+
revokedSubjectEntityAppMap.put(consumerKey, revocationTime);
109+
}
110+
111+
public boolean isRevokedSubjectEntityConsumerAppExists(String consumerKey, Long jwtGeneratedTimestamp) {
112+
113+
Long jwtRevokedTime = revokedSubjectEntityAppMap.get(consumerKey);
114+
115+
if (jwtRevokedTime != null) {
116+
Timestamp jwtRevokedTimestamp = new Timestamp(jwtRevokedTime);
117+
return jwtRevokedTimestamp.after(new Timestamp(jwtGeneratedTimestamp));
118+
}
119+
120+
return false;
121+
}
122+
123+
public void addRevokedSubjectEntityUserToMap(String userUUID, Long revocationTime) {
124+
125+
if (log.isDebugEnabled()) {
126+
log.debug("Adding internal revoked JWT user id, revocation time value pair to the revoked map :"
127+
+ userUUID + " , revocationTime: " + revocationTime);
128+
}
129+
revokedSubjectEntityUserMap.put(userUUID, revocationTime);
130+
}
131+
132+
public boolean isRevokedSubjectEntityUserExists(String user, Long jwtGeneratedTimestamp) {
133+
134+
Long jwtRevokedTime = revokedSubjectEntityUserMap.get(user);
135+
if (jwtRevokedTime != null) {
136+
Timestamp jwtRevokedTimestamp = new Timestamp(jwtRevokedTime);
137+
return jwtRevokedTimestamp.after(new Timestamp(jwtGeneratedTimestamp));
138+
}
139+
return false;
140+
}
75141
}

0 commit comments

Comments
 (0)