|
32 | 32 | import org.forgerock.util.Reject; |
33 | 33 |
|
34 | 34 | import java.util.List; |
| 35 | +import java.util.regex.Matcher; |
| 36 | +import java.util.regex.Pattern; |
35 | 37 | import java.util.Set; |
36 | 38 |
|
37 | 39 | import static org.forgerock.openam.authentication.modules.oidc.OpenIdConnectConfig.*; |
@@ -68,7 +70,7 @@ public JwtClaimsSet validateJwt(String jwtValue) throws AuthLoginException { |
68 | 70 | final SignedJwt signedJwt = getSignedJwt(jwtValue); |
69 | 71 | JwtClaimsSet jwtClaimSet = signedJwt.getClaimsSet(); |
70 | 72 | final String jwtClaimSetIssuer = jwtClaimSet.getIssuer(); |
71 | | - if (!config.getConfiguredIssuer().equals(jwtClaimSetIssuer)) { |
| 73 | + if (!config.getConfiguredIssuer().equals(jwtClaimSetIssuer) && !isJwtFromIssuerFormat(jwtClaimSet)) { |
72 | 74 | logger.error("The issuer configured for the module, " + config.getConfiguredIssuer() + ", and the " + |
73 | 75 | "issuer found in the token, " + jwtClaimSetIssuer + ", do not match. This means that the token " + |
74 | 76 | "authentication was directed at the wrong module, or the targeted module is mis-configured."); |
@@ -136,6 +138,30 @@ public JwtClaimsSet validateJwt(String jwtValue) throws AuthLoginException { |
136 | 138 | return jwtClaimSet; |
137 | 139 | } |
138 | 140 |
|
| 141 | + /** |
| 142 | + * Indicates whether the JWT token is issued by configured issuer, with parameterized substitution from the claims set. |
| 143 | + * Example: <tt>https://login.microsoftonline.com/{tid}/v2.0</tt> shall have <tt>{tid}</tt> replaced with the iss claim's value. |
| 144 | + * |
| 145 | + * @param jwtClaimSet The JWT claims. |
| 146 | + * @return Whether the JWT token is issued by the configured issuer. |
| 147 | + */ |
| 148 | + private boolean isJwtFromIssuerFormat(JwtClaimsSet jwtClaimSet) { |
| 149 | + /* Since the OpenID Connect Core says "The Issuer Identifier [...] MUST exactly match the value of the iss (issuer) Claim.", |
| 150 | + allow only parameterized matching. */ |
| 151 | + final Matcher m = Pattern.compile("\\{[^\\}]+\\}").matcher(config.getConfiguredIssuer()); |
| 152 | + final StringBuffer issuer = new StringBuffer(); |
| 153 | + while (m.find()) { |
| 154 | + final String group = m.group(); |
| 155 | + final String key = group.substring(1, group.length() - 1); |
| 156 | + final Object value = jwtClaimSet.getClaim(key); |
| 157 | + if (value != null) |
| 158 | + m.appendReplacement(issuer, value.toString()); |
| 159 | + } |
| 160 | + m.appendTail(issuer); |
| 161 | + |
| 162 | + return issuer.toString().equals(jwtClaimSet.getIssuer()); |
| 163 | + } |
| 164 | + |
139 | 165 | /** |
140 | 166 | * Retrieve the actual JWT token from the encoded JWT token. |
141 | 167 | * |
|
0 commit comments