Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,22 @@
{% else %}
<ClientTransportCertAsHeaderEnabled>true</ClientTransportCertAsHeaderEnabled>
{% endif %}
{% if open_banking.identity.application_scope_restriction is defined %}
<ApplicationScopeRestriction>
<Enabled>{{ open_banking.identity.application_scope_restriction.enabled | default(false) }}</Enabled>
{% if open_banking.identity.application_scope_restriction.grant_types is defined %}
<RestrictedGrantTypes>
{% for grant_type in open_banking.identity.application_scope_restriction.grant_types %}
<GrantType>{{ grant_type }}</GrantType>
{% endfor %}
</RestrictedGrantTypes>
{% endif %}
</ApplicationScopeRestriction>
{% else %}
<ApplicationScopeRestriction>
<Enabled>false</Enabled>
</ApplicationScopeRestriction>
{% endif %}
{% if open_banking.identity.signing_certificate_kid is defined %}
<SigningCertificateKid>{{open_banking.identity.signing_certificate_kid}}</SigningCertificateKid>
{% endif %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.wso2.openbanking.accelerator.identity.grant.type.handlers;

import com.wso2.openbanking.accelerator.common.exception.OpenBankingException;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonConstants;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonUtil;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO;
Expand All @@ -34,8 +35,14 @@ public class OBAuthorizationCodeGrantHandler extends AuthorizationCodeGrantHandl
public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {

try {
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(tokReqMsgCtx.getOauth2AccessTokenReqDTO()
.getClientId())) {
String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(clientId)) {
// Apply application scope restrictions if enabled
if (IdentityCommonUtil.isAppScopeRestrictionEnabledForGrant(
IdentityCommonConstants.AUTHORIZATION_CODE)) {
tokReqMsgCtx.setScope(IdentityCommonUtil.retainAllowedScopesForApplication(
tokReqMsgCtx.getScope(), clientId));
}
OAuth2AccessTokenRespDTO oAuth2AccessTokenRespDTO = super.issue(tokReqMsgCtx);
executeInitialStep(oAuth2AccessTokenRespDTO, tokReqMsgCtx);
tokReqMsgCtx.setScope(IdentityCommonUtil.removeInternalScopes(tokReqMsgCtx.getScope()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.wso2.openbanking.accelerator.identity.grant.type.handlers;

import com.wso2.openbanking.accelerator.common.exception.OpenBankingException;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonConstants;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonUtil;
import org.wso2.carbon.identity.oauth.common.exception.InvalidOAuthClientException;
import org.wso2.carbon.identity.oauth.dao.OAuthAppDO;
Expand All @@ -39,16 +40,21 @@ public class OBClientCredentialsGrantHandler extends ClientCredentialsGrantHandl
public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {

try {
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(tokReqMsgCtx.getOauth2AccessTokenReqDTO()
.getClientId())) {
String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(clientId)) {
if (IdentityCommonUtil.getDCRModifyResponseConfig() && tokReqMsgCtx.getScope().length > 0 &&
Arrays.asList(tokReqMsgCtx.getScope()).contains(IdentityCommonUtil.getDCRScope())) {
long validityPeriod = 999999999;
OAuthAppDO oAuthAppDO = OAuth2Util
.getAppInformationByClientId(tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId());
OAuthAppDO oAuthAppDO = OAuth2Util.getAppInformationByClientId(clientId);
oAuthAppDO.setApplicationAccessTokenExpiryTime(validityPeriod);
tokReqMsgCtx.setValidityPeriod(validityPeriod);
}
// Apply application scope restrictions if enabled
if (IdentityCommonUtil.isAppScopeRestrictionEnabledForGrant(
IdentityCommonConstants.CLIENT_CREDENTIALS)) {
tokReqMsgCtx.setScope(IdentityCommonUtil.retainAllowedScopesForApplication(
tokReqMsgCtx.getScope(), clientId));
}
OAuth2AccessTokenRespDTO oAuth2AccessTokenRespDTO = super.issue(tokReqMsgCtx);
executeInitialStep(oAuth2AccessTokenRespDTO, tokReqMsgCtx);
tokReqMsgCtx.setScope(IdentityCommonUtil.removeInternalScopes(tokReqMsgCtx.getScope()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.wso2.openbanking.accelerator.identity.grant.type.handlers;

import com.wso2.openbanking.accelerator.common.exception.OpenBankingException;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonConstants;
import com.wso2.openbanking.accelerator.identity.util.IdentityCommonUtil;
import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception;
import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenRespDTO;
Expand All @@ -34,8 +35,13 @@ public class OBPasswordGrantHandler extends PasswordGrantHandler {
public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {

try {
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(tokReqMsgCtx.getOauth2AccessTokenReqDTO()
.getClientId())) {
String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(clientId)) {
// Apply application scope restrictions if enabled
if (IdentityCommonUtil.isAppScopeRestrictionEnabledForGrant(IdentityCommonConstants.PASSWORD)) {
tokReqMsgCtx.setScope(IdentityCommonUtil.retainAllowedScopesForApplication(
tokReqMsgCtx.getScope(), clientId));
}
OAuth2AccessTokenRespDTO oAuth2AccessTokenRespDTO = super.issue(tokReqMsgCtx);
executeInitialStep(oAuth2AccessTokenRespDTO, tokReqMsgCtx);
tokReqMsgCtx.setScope(IdentityCommonUtil.removeInternalScopes(tokReqMsgCtx.getScope()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,13 @@ public class OBRefreshGrantHandler extends RefreshGrantHandler {
public OAuth2AccessTokenRespDTO issue(OAuthTokenReqMessageContext tokReqMsgCtx) throws IdentityOAuth2Exception {

try {
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(tokReqMsgCtx.getOauth2AccessTokenReqDTO()
.getClientId())) {
String clientId = tokReqMsgCtx.getOauth2AccessTokenReqDTO().getClientId();
if (IdentityCommonUtil.getRegulatoryFromSPMetaData(clientId)) {
// Apply application scope restrictions if enabled
if (IdentityCommonUtil.isAppScopeRestrictionEnabledForGrant(IdentityCommonConstants.REFRESH_TOKEN)) {
tokReqMsgCtx.setScope(IdentityCommonUtil.retainAllowedScopesForApplication(
tokReqMsgCtx.getScope(), clientId));
}
OAuth2AccessTokenRespDTO oAuth2AccessTokenRespDTO = super.issue(tokReqMsgCtx);
executeInitialStep(oAuth2AccessTokenRespDTO, tokReqMsgCtx);
tokReqMsgCtx.setScope(IdentityCommonUtil.removeInternalScopes(tokReqMsgCtx.getScope()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -71,6 +72,7 @@ public class IdentityExtensionsDataHolder {
private Map<String, Object> configurationMap;
private Map<String, Map<String, Object>> dcrRegistrationConfigMap;
private List<OBIdentityFilterValidator> tokenValidators = new ArrayList<>();
private List<String> scopeRestrictedGrantTypes = new ArrayList<>();
private DefaultTokenFilter defaultTokenFilter;
private RegistrationValidator registrationValidator;
private ClaimProvider claimProvider;
Expand Down Expand Up @@ -217,6 +219,7 @@ public void setOpenBankingConfigurationService(
.getConfigurations().get("IdentityCache.CacheAccessExpiry"));
setIdentityCacheModifiedExpiry((String) openBankingConfigurationService
.getConfigurations().get("IdentityCache.CacheModifiedExpiry"));
setScopeRestrictedGrantTypes(extractScopeRestrictedGrantTypes());

Map<String, String> authenticationWorkers = openBankingConfigurationService.getAuthenticationWorkers();
authenticationWorkers.forEach((key, value) ->
Expand All @@ -237,6 +240,16 @@ public void setTokenFilterValidators() {
}
}

public List<String> getScopeRestrictedGrantTypes() {

return scopeRestrictedGrantTypes;
}

public void setScopeRestrictedGrantTypes(List<String> scopeRestrictedGrantTypes) {

this.scopeRestrictedGrantTypes = scopeRestrictedGrantTypes;
}

private List extractTokenFilterValidators() {

Object validators = configurationMap.get(IdentityCommonConstants.TOKEN_VALIDATORS);
Expand All @@ -252,6 +265,26 @@ private List extractTokenFilterValidators() {
}
}

/**
* Get grant types which the token scopes should be restricted based on scopes allowed for the application.
*
* @return List of grant types
*/
public List<String> extractScopeRestrictedGrantTypes() {

Object grantTypes = configurationMap.get(IdentityCommonConstants.APPLICATION_SCOPE_RESTRICTED_GRANT_TYPES);

if (grantTypes instanceof List) {
return (List<String>) grantTypes;
}

if (grantTypes instanceof String) {
return Collections.singletonList((String) grantTypes);
}

return Collections.emptyList();
}

public DefaultTokenFilter getDefaultTokenFilterImpl() {

return defaultTokenFilter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public class IdentityCommonConstants {
"Identity.TokenSubject.RemoveUserStoreDomainFromSubject";
public static final String REMOVE_TENANT_DOMAIN_FROM_SUBJECT =
"Identity.TokenSubject.RemoveTenantDomainFromSubject";
public static final String APPLICATION_SCOPE_RESTRICTION_ENABLED = "Identity.ApplicationScopeRestriction.Enabled";
public static final String APPLICATION_SCOPE_RESTRICTED_GRANT_TYPES =
"Identity.ApplicationScopeRestriction.RestrictedGrantTypes.GrantType";


public static final String AUTH_SERVLET_EXTENSION = "Identity.Extensions.AuthenticationWebApp.ServletExtension";
public static final String CONSENT_ID_CLAIM_NAME = "Identity.ConsentIDClaimName";
Expand All @@ -90,6 +94,9 @@ public class IdentityCommonConstants {
public static final String DCR_INTERNAL_SCOPE = "OB_DCR";
public static final String OPENID_SCOPE = "openid";
public static final String CLIENT_CREDENTIALS = "client_credentials";
public static final String AUTHORIZATION_CODE = "authorization_code";
public static final String REFRESH_TOKEN = "refresh_token";
public static final String PASSWORD = "password";
public static final String CARBON_SUPER = "carbon.super";
public static final String REGISTRATION_ACCESS_TOKEN = "registration_access_token";
public static final String REGISTRATION_CLIENT_URI = "registration_client_uri";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -124,7 +126,42 @@ public static String[] removeInternalScopes(String[] scopes) {
}

/**
* Cache regulatory property if exists.
* Filter the requested scopes by removing scopes which are not allowed for the application.
*
* @param scopes Requested scopes
* @param clientId OAuth client ID
* @return filtered scopes by removing the scopes not allowed for the application
*/
public static String[] retainAllowedScopesForApplication(String[] scopes, String clientId)
throws OpenBankingException {

if (scopes == null || scopes.length == 0) {
return scopes;
}
String allowedScopes = getScopeFromSPMetaData(clientId);

if (StringUtils.isBlank(allowedScopes)) {
if (log.isDebugEnabled()) {
log.debug("No allowed scopes configured for application client_id: "
+ clientId.replaceAll("[\r\n]", "") + ". All requested scopes will be removed.");
}
return new String[0];
}

Set<String> allowedScopeSet = new HashSet<>(Arrays.asList(allowedScopes.split(" ")));
String[] filteredScopes = Arrays.stream(scopes).filter(allowedScopeSet::contains).toArray(String[]::new);

if (log.isDebugEnabled()) {
log.debug("Filtered scopes for application client_id: " + clientId.replaceAll("[\r\n]", "")
+ ". Requested scopes: " + Arrays.toString(scopes).replaceAll("[\r\n]", "")
+ " | Filtered scopes: " + Arrays.toString(filteredScopes).replaceAll("[\r\n]", ""));
}

return filteredScopes;
}

/**
* Cache regulatory property if exists
*
* @param clientId ClientId of the application
* @return the regulatory property from cache if exists or from sp metadata
Expand Down Expand Up @@ -163,6 +200,41 @@ public static synchronized boolean getRegulatoryFromSPMetaData(String clientId)
}
}

/**
* Get scopes for the application and add to cache.
*
* @param clientId clientId of the application
* @return the scopes from cache if exists or from sp metadata
* @throws OpenBankingException
*/
@Generated(message = "Excluding from code coverage since it requires a cache initialization/service call")
public static synchronized String getScopeFromSPMetaData(String clientId) throws OpenBankingException {

if (StringUtils.isNotEmpty(clientId)) {

if (identityCache == null) {
log.debug("Creating new Identity cache");
identityCache = new IdentityCache();
}

IdentityCacheKey identityCacheKey = IdentityCacheKey.of(clientId
.concat("_").concat(IdentityCommonConstants.SCOPE));
Object scope = null;

scope = identityCache.getFromCacheOrRetrieve(identityCacheKey,
() -> new IdentityCommonHelper().getAppPropertyFromSPMetaData(clientId,
IdentityCommonConstants.SCOPE));

if (scope != null) {
return scope.toString();
} else {
throw new OpenBankingException("Unable to retrieve scope from sp metadata");
}
} else {
throw new OpenBankingException(IdentityCommonConstants.CLIENT_ID_ERROR);
}
}

public static ServiceProviderProperty getServiceProviderProperty(String spPropertyName, String spPropertyValue) {

ServiceProviderProperty serviceProviderProperty = new ServiceProviderProperty();
Expand Down Expand Up @@ -468,4 +540,31 @@ public static Date parseStringToDate(String dateString) throws ParseException {
return dateFormat.parse(dateString);
}

/**
* Check whether application scope restriction is enabled for the given grant type.
*
* @param grantType OAuth2 grant type
* @return true if scope restriction is enabled for the given grant type, false otherwise
*/
public static boolean isAppScopeRestrictionEnabledForGrant(String grantType) {

boolean isRestrictionEnabled = Boolean.parseBoolean(String.valueOf(
IdentityExtensionsDataHolder.getInstance().getConfigurationMap().getOrDefault(
IdentityCommonConstants.APPLICATION_SCOPE_RESTRICTION_ENABLED, false)
));

if (!isRestrictionEnabled || StringUtils.isBlank(grantType)) {
return false;
}

boolean isEnabledForGrant = IdentityExtensionsDataHolder.getInstance().getScopeRestrictedGrantTypes().stream()
.anyMatch(configuredGrantType -> configuredGrantType.equalsIgnoreCase(grantType));

if (log.isDebugEnabled()) {
log.debug("Application scope restriction evaluation for grant type: "
+ grantType.replaceAll("[\r\n]", "") + ". Enabled for grant: " + isEnabledForGrant);
}
return isEnabledForGrant;
}

}