|
73 | 73 | import java.util.Base64; |
74 | 74 | import java.util.Date; |
75 | 75 | import java.util.HashMap; |
| 76 | +import java.util.HashSet; |
76 | 77 | import java.util.LinkedList; |
77 | 78 | import java.util.List; |
78 | 79 | import java.util.Map; |
79 | 80 | import java.util.Optional; |
| 81 | +import java.util.Set; |
80 | 82 | import java.util.stream.Collectors; |
81 | 83 |
|
82 | 84 | import javax.servlet.http.HttpServletRequest; |
@@ -124,7 +126,42 @@ public static String[] removeInternalScopes(String[] scopes) { |
124 | 126 | } |
125 | 127 |
|
126 | 128 | /** |
127 | | - * Cache regulatory property if exists. |
| 129 | + * Filter the requested scopes by removing scopes which are not allowed for the application. |
| 130 | + * |
| 131 | + * @param scopes Requested scopes |
| 132 | + * @param clientId OAuth client ID |
| 133 | + * @return filtered scopes by removing the scopes not allowed for the application |
| 134 | + */ |
| 135 | + public static String[] retainAllowedScopesForApplication(String[] scopes, String clientId) |
| 136 | + throws OpenBankingException { |
| 137 | + |
| 138 | + if (scopes == null || scopes.length == 0) { |
| 139 | + return scopes; |
| 140 | + } |
| 141 | + String allowedScopes = getScopeFromSPMetaData(clientId); |
| 142 | + |
| 143 | + if (StringUtils.isBlank(allowedScopes)) { |
| 144 | + if (log.isDebugEnabled()) { |
| 145 | + log.debug("No allowed scopes configured for application client_id: " |
| 146 | + + clientId.replaceAll("[\r\n]", "") + ". All requested scopes will be removed."); |
| 147 | + } |
| 148 | + return new String[0]; |
| 149 | + } |
| 150 | + |
| 151 | + Set<String> allowedScopeSet = new HashSet<>(Arrays.asList(allowedScopes.split(" "))); |
| 152 | + String[] filteredScopes = Arrays.stream(scopes).filter(allowedScopeSet::contains).toArray(String[]::new); |
| 153 | + |
| 154 | + if (log.isDebugEnabled()) { |
| 155 | + log.debug("Filtered scopes for application client_id: " + clientId.replaceAll("[\r\n]", "") |
| 156 | + + ". Requested scopes: " + Arrays.toString(scopes).replaceAll("[\r\n]", "") |
| 157 | + + " | Filtered scopes: " + Arrays.toString(filteredScopes).replaceAll("[\r\n]", "")); |
| 158 | + } |
| 159 | + |
| 160 | + return filteredScopes; |
| 161 | + } |
| 162 | + |
| 163 | + /** |
| 164 | + * Cache regulatory property if exists |
128 | 165 | * |
129 | 166 | * @param clientId ClientId of the application |
130 | 167 | * @return the regulatory property from cache if exists or from sp metadata |
@@ -163,6 +200,41 @@ public static synchronized boolean getRegulatoryFromSPMetaData(String clientId) |
163 | 200 | } |
164 | 201 | } |
165 | 202 |
|
| 203 | + /** |
| 204 | + * Get scopes for the application and add to cache. |
| 205 | + * |
| 206 | + * @param clientId clientId of the application |
| 207 | + * @return the scopes from cache if exists or from sp metadata |
| 208 | + * @throws OpenBankingException |
| 209 | + */ |
| 210 | + @Generated(message = "Excluding from code coverage since it requires a cache initialization/service call") |
| 211 | + public static synchronized String getScopeFromSPMetaData(String clientId) throws OpenBankingException { |
| 212 | + |
| 213 | + if (StringUtils.isNotEmpty(clientId)) { |
| 214 | + |
| 215 | + if (identityCache == null) { |
| 216 | + log.debug("Creating new Identity cache"); |
| 217 | + identityCache = new IdentityCache(); |
| 218 | + } |
| 219 | + |
| 220 | + IdentityCacheKey identityCacheKey = IdentityCacheKey.of(clientId |
| 221 | + .concat("_").concat(IdentityCommonConstants.SCOPE)); |
| 222 | + Object scope = null; |
| 223 | + |
| 224 | + scope = identityCache.getFromCacheOrRetrieve(identityCacheKey, |
| 225 | + () -> new IdentityCommonHelper().getAppPropertyFromSPMetaData(clientId, |
| 226 | + IdentityCommonConstants.SCOPE)); |
| 227 | + |
| 228 | + if (scope != null) { |
| 229 | + return scope.toString(); |
| 230 | + } else { |
| 231 | + throw new OpenBankingException("Unable to retrieve scope from sp metadata"); |
| 232 | + } |
| 233 | + } else { |
| 234 | + throw new OpenBankingException(IdentityCommonConstants.CLIENT_ID_ERROR); |
| 235 | + } |
| 236 | + } |
| 237 | + |
166 | 238 | public static ServiceProviderProperty getServiceProviderProperty(String spPropertyName, String spPropertyValue) { |
167 | 239 |
|
168 | 240 | ServiceProviderProperty serviceProviderProperty = new ServiceProviderProperty(); |
@@ -468,4 +540,31 @@ public static Date parseStringToDate(String dateString) throws ParseException { |
468 | 540 | return dateFormat.parse(dateString); |
469 | 541 | } |
470 | 542 |
|
| 543 | + /** |
| 544 | + * Check whether application scope restriction is enabled for the given grant type. |
| 545 | + * |
| 546 | + * @param grantType OAuth2 grant type |
| 547 | + * @return true if scope restriction is enabled for the given grant type, false otherwise |
| 548 | + */ |
| 549 | + public static boolean isAppScopeRestrictionEnabledForGrant(String grantType) { |
| 550 | + |
| 551 | + boolean isRestrictionEnabled = Boolean.parseBoolean(String.valueOf( |
| 552 | + IdentityExtensionsDataHolder.getInstance().getConfigurationMap().getOrDefault( |
| 553 | + IdentityCommonConstants.APPLICATION_SCOPE_RESTRICTION_ENABLED, false) |
| 554 | + )); |
| 555 | + |
| 556 | + if (!isRestrictionEnabled || StringUtils.isBlank(grantType)) { |
| 557 | + return false; |
| 558 | + } |
| 559 | + |
| 560 | + boolean isEnabledForGrant = IdentityExtensionsDataHolder.getInstance().getScopeRestrictedGrantTypes().stream() |
| 561 | + .anyMatch(configuredGrantType -> configuredGrantType.equalsIgnoreCase(grantType)); |
| 562 | + |
| 563 | + if (log.isDebugEnabled()) { |
| 564 | + log.debug("Application scope restriction evaluation for grant type: " |
| 565 | + + grantType.replaceAll("[\r\n]", "") + ". Enabled for grant: " + isEnabledForGrant); |
| 566 | + } |
| 567 | + return isEnabledForGrant; |
| 568 | + } |
| 569 | + |
471 | 570 | } |
0 commit comments