From 4d78cb786643f91559f8bb41098712119c3e0b9b Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 24 Apr 2026 17:28:39 +0530 Subject: [PATCH 1/6] feat(fapi2): add tenant-level FAPI config models and connector utility Add FapiConfig and FapiProfile model classes to the configs API for tenant-level FAPI compliance configuration (enabled flag + supported profiles) Add FapiProfile enum to the application management API module Introduce FAPIConnectorUtil for bi-directional conversion between API-layer FAPI models and OAuth bundle FAPI models Default FAPI profile to FAPI1_ADVANCED when an application is FAPI-enabled but no profile is explicitly specified Remove unused imports (FapiConfig, FapiProfile, FapiConfigMgtServerException) Fix import ordering in ServerApplicationMetadataService --- .../management/v1/FapiMetadata.java | 37 +++-- .../management/v1/FapiProfile.java | 64 +++++++++ .../ServerApplicationManagementService.java | 66 ++++++++- .../ServerApplicationMetadataService.java | 1 + .../oauth2/ApiModelToOAuthConsumerApp.java | 8 +- .../server/configs/v1/model/FapiConfig.java | 136 ++++++++++++++++++ .../server/configs/v1/model/FapiProfile.java | 75 ++++++++++ .../core/ServerConfigManagementService.java | 85 ++++++++++- .../v1/function/FAPIConnectorUtil.java | 97 +++++++++++++ 9 files changed, 548 insertions(+), 21 deletions(-) create mode 100644 components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java create mode 100644 components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java create mode 100644 components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java create mode 100644 components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/FAPIConnectorUtil.java diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java index 0548c852d9..c2e5121769 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024-2026, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -33,11 +33,30 @@ import javax.xml.bind.annotation.*; public class FapiMetadata { - + + private MetadataProperty allowedFapiProfiles; private MetadataProperty allowedSignatureAlgorithms; private MetadataProperty allowedEncryptionAlgorithms; private ClientAuthenticationMethodMetadata tokenEndpointAuthMethod; + /** + **/ + public FapiMetadata allowedFapiProfiles(MetadataProperty allowedFapiProfiles) { + + this.allowedFapiProfiles = allowedFapiProfiles; + return this; + } + + @ApiModelProperty(value = "") + @JsonProperty("allowedFapiProfiles") + @Valid + public MetadataProperty getAllowedFapiProfiles() { + return allowedFapiProfiles; + } + public void setAllowedFapiProfiles(MetadataProperty allowedFapiProfiles) { + this.allowedFapiProfiles = allowedFapiProfiles; + } + /** **/ public FapiMetadata allowedSignatureAlgorithms(MetadataProperty allowedSignatureAlgorithms) { @@ -45,7 +64,7 @@ public FapiMetadata allowedSignatureAlgorithms(MetadataProperty allowedSignature this.allowedSignatureAlgorithms = allowedSignatureAlgorithms; return this; } - + @ApiModelProperty(value = "") @JsonProperty("allowedSignatureAlgorithms") @Valid @@ -63,7 +82,7 @@ public FapiMetadata allowedEncryptionAlgorithms(MetadataProperty allowedEncrypti this.allowedEncryptionAlgorithms = allowedEncryptionAlgorithms; return this; } - + @ApiModelProperty(value = "") @JsonProperty("allowedEncryptionAlgorithms") @Valid @@ -81,7 +100,7 @@ public FapiMetadata tokenEndpointAuthMethod(ClientAuthenticationMethodMetadata t this.tokenEndpointAuthMethod = tokenEndpointAuthMethod; return this; } - + @ApiModelProperty(value = "") @JsonProperty("tokenEndpointAuthMethod") @Valid @@ -104,14 +123,15 @@ public boolean equals(java.lang.Object o) { return false; } FapiMetadata fapiMetadata = (FapiMetadata) o; - return Objects.equals(this.allowedSignatureAlgorithms, fapiMetadata.allowedSignatureAlgorithms) && + return Objects.equals(this.allowedFapiProfiles, fapiMetadata.allowedFapiProfiles) && + Objects.equals(this.allowedSignatureAlgorithms, fapiMetadata.allowedSignatureAlgorithms) && Objects.equals(this.allowedEncryptionAlgorithms, fapiMetadata.allowedEncryptionAlgorithms) && Objects.equals(this.tokenEndpointAuthMethod, fapiMetadata.tokenEndpointAuthMethod); } @Override public int hashCode() { - return Objects.hash(allowedSignatureAlgorithms, allowedEncryptionAlgorithms, tokenEndpointAuthMethod); + return Objects.hash(allowedFapiProfiles, allowedSignatureAlgorithms, allowedEncryptionAlgorithms, tokenEndpointAuthMethod); } @Override @@ -119,7 +139,8 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class FapiMetadata {\n"); - + + sb.append(" allowedFapiProfiles: ").append(toIndentedString(allowedFapiProfiles)).append("\n"); sb.append(" allowedSignatureAlgorithms: ").append(toIndentedString(allowedSignatureAlgorithms)).append("\n"); sb.append(" allowedEncryptionAlgorithms: ").append(toIndentedString(allowedEncryptionAlgorithms)).append("\n"); sb.append(" tokenEndpointAuthMethod: ").append(toIndentedString(tokenEndpointAuthMethod)).append("\n"); diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java new file mode 100644 index 0000000000..ebc57b06af --- /dev/null +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024-2026, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.api.server.application.management.v1; + +import io.swagger.annotations.ApiModel; +import javax.validation.constraints.*; + +/** + * FAPI security profile. - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile. - `FAPI2_SECURITY`: FAPI 2.0 Security Profile. + **/ +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; + +@XmlType(name="") +@XmlEnum(String.class) +public enum FapiProfile { + + @XmlEnumValue("FAPI1_ADVANCED") FAPI1_ADVANCED(String.valueOf("FAPI1_ADVANCED")), @XmlEnumValue("FAPI2_SECURITY") FAPI2_SECURITY(String.valueOf("FAPI2_SECURITY")); + + + private String value; + + FapiProfile(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static FapiProfile fromValue(String value) { + for (FapiProfile b : FapiProfile.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + + diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java index eeb539e063..c86232b47c 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java @@ -66,6 +66,7 @@ import org.wso2.carbon.identity.api.server.application.management.v1.SAML2Configuration; import org.wso2.carbon.identity.api.server.application.management.v1.SAML2ServiceProvider; import org.wso2.carbon.identity.api.server.application.management.v1.ScriptUpdateModel; +import org.wso2.carbon.identity.api.server.application.management.v1.FapiProfile; import org.wso2.carbon.identity.api.server.application.management.v1.WSTrustConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.ApiModelToServiceProvider; @@ -142,6 +143,9 @@ import org.wso2.carbon.identity.cors.mgt.core.exception.CORSManagementServiceException; import org.wso2.carbon.identity.cors.mgt.core.model.CORSOrigin; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; +import org.wso2.carbon.identity.oauth2.fapi.exceptions.FapiConfigMgtException; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.role.v2.mgt.core.RoleConstants; import org.wso2.carbon.identity.sso.saml.dto.SAMLSSOServiceProviderDTO; import org.wso2.carbon.identity.template.mgt.TemplateManager; @@ -190,6 +194,7 @@ import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ErrorMessage.FORBIDDEN_OPERATION; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ErrorMessage.INBOUND_NOT_CONFIGURED; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ErrorMessage.UNSUPPORTED_ENHANCED_ORGANIZATION_AUTHENTICATION_ENABLED_CONFIGURATION; +import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ErrorMessage.UNSUPPORTED_FAPI_PROFILE; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ErrorMessage.USE_EXTERNAL_CONSENT_PAGE_NOT_SUPPORTED; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.ISSUER; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.NAME; @@ -815,7 +820,10 @@ public String createApplication(ApplicationModel applicationModel, String templa */ if (applicationModel.getInboundProtocolConfiguration() != null && applicationModel.getInboundProtocolConfiguration().getOidc() != null) { - validateCORSOrigins(applicationModel.getInboundProtocolConfiguration().getOidc().getAllowedOrigins()); + OpenIDConnectConfiguration oidcConfig = + applicationModel.getInboundProtocolConfiguration().getOidc(); + validateCORSOrigins(oidcConfig.getAllowedOrigins()); + validateFapiProfile(oidcConfig); } /* @@ -838,11 +846,6 @@ public String createApplication(ApplicationModel applicationModel, String templa UNSUPPORTED_ENHANCED_ORGANIZATION_AUTHENTICATION_ENABLED_CONFIGURATION.getDescription()); } - if (applicationModel.getEnhancedOrgAuthenticationEnabled() == null - && isEnhancedOrganizationAuthenticationFeatureEnabled()) { - applicationModel.setEnhancedOrgAuthenticationEnabled(isEnhancedOrgAuthEnabledByDefaultForNewApps()); - } - // Block application creation with name Console or MyAccount. if (FrameworkConstants.Application.CONSOLE_APP.equals(applicationModel.getName()) || FrameworkConstants.Application.MY_ACCOUNT_APP.equals(applicationModel.getName())) { @@ -1235,6 +1238,7 @@ public void putInboundOAuthConfiguration(String applicationId, OpenIDConnectConf * But for now we are handling the validation here. */ validateCORSOrigins(oidcConfigModel.getAllowedOrigins()); + validateFapiProfile(oidcConfigModel); putApplicationInbound(applicationId, oidcConfigModel, OAuthInboundFunctions::getInboundProtocolConfig); } @@ -2219,6 +2223,56 @@ private String buildFormattedDescription(String description, String... formatDat } } + /** + * Validates the FAPI profile in the given OIDC configuration. + * + *

Validation: checks the resolved profile against the organisation's allowed list from + * {@link FapiConfigMgtService}. Throws a 400 error if the profile is not supported. + * No-ops when {@code oidcConfig} is null, FAPI is disabled, or {@link FapiConfigMgtService} + * is unavailable (treated as optional OSGi service). + * + * @param oidcConfig the OIDC configuration from the incoming request; may be null. + */ + private void validateFapiProfile(OpenIDConnectConfiguration oidcConfig) { + + // Validate — only needed when a profile is present. + if (oidcConfig.getFapiProfile() == null) { + return; + } + + FapiConfigMgtService fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); + if (fapiConfigMgtService == null) { + // FapiConfigMgtService is optional. Skip validation rather than blocking all OIDC updates. + log.debug("FapiConfigMgtService is unavailable. Skipping fapiProfile validation."); + return; + } + + String tenantDomain = ContextLoader.getTenantDomainFromContext(); + try { + List supportedProfiles = + fapiConfigMgtService.getFapiConfig(tenantDomain).getSupportedProfiles(); + String requestedProfileValue = oidcConfig.getFapiProfile().toString(); + + boolean isSupported = supportedProfiles.stream() + .anyMatch(p -> p.value().equals(requestedProfileValue)); + + if (!isSupported) { + String supportedProfilesStr = supportedProfiles.stream() + .map(FapiProfileEnum::value) + .collect(Collectors.joining(", ")); + if (log.isDebugEnabled()) { + log.debug(String.format("Rejected fapiProfile '%s' for tenant '%s'. Supported: [%s]", + requestedProfileValue, tenantDomain, supportedProfilesStr)); + } + throw buildClientError(UNSUPPORTED_FAPI_PROFILE, requestedProfileValue, supportedProfilesStr); + } + } catch (FapiConfigMgtException e) { + throw Utils.buildServerError( + String.format("Error while retrieving FAPI configuration for tenant '%s' during fapiProfile " + + "validation.", tenantDomain), e); + } + } + /** * Validate the CORS Origins. This should be moved to the service layer with the CORS adding step on creating * OIDC applications. diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java index b2c5afc637..f1c6552d60 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.api.server.application.management.v1.core; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java index f3b7745bc8..584990ec15 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java @@ -41,6 +41,7 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO; import org.wso2.carbon.identity.oauth2.config.models.IssuerDetails; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum; import java.util.ArrayList; import java.util.Arrays; @@ -90,6 +91,11 @@ public OAuthConsumerAppDTO apply(String appName, OpenIDConnectConfiguration oidc updatePARConfigurations(consumerAppDTO, oidcModel.getPushAuthorizationRequest()); updateSubjectConfigurations(consumerAppDTO, oidcModel.getSubject()); consumerAppDTO.setFapiConformanceEnabled(oidcModel.getIsFAPIApplication()); + // Convert FAPI profile enum to String for storage. If no profile specified; default is set to FAPI1_ADVANCED. + if (oidcModel.getIsFAPIApplication()) { + consumerAppDTO.setFapiProfile(oidcModel.getFapiProfile() != null + ? oidcModel.getFapiProfile().toString() : FapiProfileEnum.FAPI1_ADVANCED.value()); + } updateSubjectTokenConfigurations(consumerAppDTO, oidcModel.getSubjectToken()); updateCIBAAuthenticationRequestConfigurations(consumerAppDTO, oidcModel.getCibaAuthenticationRequest()); updateIssuerDetails(consumerAppDTO, oidcModel.getIssuer()); @@ -167,7 +173,7 @@ private void updateRefreshTokenConfiguration(OAuthConsumerAppDTO consumerAppDTO, } private void updateAllowedOrigins(OAuthConsumerAppDTO consumerAppDTO, List allowedOrigins) { - + // Setting the allowed origins since now the cors origin services will be called and handle by the Oauth2 // Inbound config handler consumerAppDTO.setAllowedOrigins(allowedOrigins); diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java new file mode 100644 index 0000000000..002b913ed4 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.api.server.configs.v1.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.List; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiProfile; +import javax.validation.constraints.*; + +/** + * Financial-grade API (FAPI) configuration for the tenant. + **/ + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; +@ApiModel(description = "Financial-grade API (FAPI) configuration for the tenant.") +public class FapiConfig { + + private Boolean enabled = false; + private List supportedProfiles = null; + + + /** + * Indicates whether FAPI compliance enforcement is enabled for the tenant. + **/ + public FapiConfig enabled(Boolean enabled) { + + this.enabled = enabled; + return this; + } + + @ApiModelProperty(example = "false", value = "Indicates whether FAPI compliance enforcement is enabled for the tenant.") + @JsonProperty("enabled") + @Valid + public Boolean getEnabled() { + return enabled; + } + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + /** + * List of FAPI security profiles supported by the tenant. - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile (Read and Write API Security Profile). - `FAPI2_SECURITY`: FAPI 2.0 Security Profile (baseline profile for high-security OAuth 2.0 APIs). + **/ + public FapiConfig supportedProfiles(List supportedProfiles) { + + this.supportedProfiles = supportedProfiles; + return this; + } + + @ApiModelProperty(example = "[\"FAPI1_ADVANCED\",\"FAPI2_SECURITY\"]", value = "List of FAPI security profiles supported by the tenant. - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile (Read and Write API Security Profile). - `FAPI2_SECURITY`: FAPI 2.0 Security Profile (baseline profile for high-security OAuth 2.0 APIs). ") + @JsonProperty("supportedProfiles") + @Valid + public List getSupportedProfiles() { + return supportedProfiles; + } + public void setSupportedProfiles(List supportedProfiles) { + this.supportedProfiles = supportedProfiles; + } + + public FapiConfig addSupportedProfilesItem(FapiProfile supportedProfilesItem) { + if (this.supportedProfiles == null) { + this.supportedProfiles = new ArrayList<>(); + } + this.supportedProfiles.add(supportedProfilesItem); + return this; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FapiConfig fapiConfig = (FapiConfig) o; + return Objects.equals(this.enabled, fapiConfig.enabled) && + Objects.equals(this.supportedProfiles, fapiConfig.supportedProfiles); + } + + @Override + public int hashCode() { + return Objects.hash(enabled, supportedProfiles); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class FapiConfig {\n"); + + sb.append(" enabled: ").append(toIndentedString(enabled)).append("\n"); + sb.append(" supportedProfiles: ").append(toIndentedString(supportedProfiles)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(java.lang.Object o) { + + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n"); + } +} + diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java new file mode 100644 index 0000000000..5c8c8a4115 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.api.server.configs.v1.model; + +import io.swagger.annotations.ApiModel; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum; + +import javax.validation.constraints.*; + +/** + * FAPI security profile. - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile. - `FAPI2_SECURITY`: FAPI 2.0 Security Profile. + **/ +import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.XmlEnum; +import javax.xml.bind.annotation.XmlEnumValue; + +@XmlType(name="") +@XmlEnum(String.class) +public enum FapiProfile { + + @XmlEnumValue("FAPI1_ADVANCED") FAPI1_ADVANCED(String.valueOf("FAPI1_ADVANCED")), @XmlEnumValue("FAPI2_SECURITY") FAPI2_SECURITY(String.valueOf("FAPI2_SECURITY")); + + + private String value; + + FapiProfile(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static FapiProfile fromValue(String value) { + + for (FapiProfile b : FapiProfile.values()) { + if (b.value.equals(value)) { + return b; + } + } + return null; + } + + public static FapiProfile fromValue(FapiProfileEnum fapiProfileEnum) { + + if (fapiProfileEnum == null) { + return null; + } + return fromValue(fapiProfileEnum.value()); + } +} + + + diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java index dc0b6540d2..4d6f7c221b 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java @@ -39,6 +39,7 @@ import org.wso2.carbon.identity.api.server.configs.v1.function.CORSConfigurationToCORSConfig; import org.wso2.carbon.identity.api.server.configs.v1.function.CompatibilitySettingUtil; import org.wso2.carbon.identity.api.server.configs.v1.function.DCRConnectorUtil; +import org.wso2.carbon.identity.api.server.configs.v1.function.FAPIConnectorUtil; import org.wso2.carbon.identity.api.server.configs.v1.function.JWTConnectorUtil; import org.wso2.carbon.identity.api.server.configs.v1.model.AuthenticationType; import org.wso2.carbon.identity.api.server.configs.v1.model.Authenticator; @@ -53,6 +54,8 @@ import org.wso2.carbon.identity.api.server.configs.v1.model.Endpoint; import org.wso2.carbon.identity.api.server.configs.v1.model.EventConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.EventProperty; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiConfig; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiProfile; import org.wso2.carbon.identity.api.server.configs.v1.model.FraudDetectionConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.ImpersonationConfiguration; import org.wso2.carbon.identity.api.server.configs.v1.model.ImpersonationPatch; @@ -109,11 +112,13 @@ import org.wso2.carbon.identity.fraud.detection.core.service.FraudDetectionConfigsService; import org.wso2.carbon.identity.oauth.dcr.DCRConfigurationMgtService; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMException; -import org.wso2.carbon.identity.oauth2.config.exceptions.OAuth2OIDCConfigOrgUsageScopeMgtClientException; import org.wso2.carbon.identity.oauth2.config.exceptions.OAuth2OIDCConfigOrgUsageScopeMgtException; import org.wso2.carbon.identity.oauth2.config.models.IssuerUsageScopeConfig; import org.wso2.carbon.identity.oauth2.config.models.UsageScope; import org.wso2.carbon.identity.oauth2.config.services.OAuth2OIDCConfigOrgUsageScopeMgtService; +import org.wso2.carbon.identity.oauth2.fapi.exceptions.FapiConfigMgtClientException; +import org.wso2.carbon.identity.oauth2.fapi.exceptions.FapiConfigMgtException; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.oauth2.impersonation.exceptions.ImpersonationConfigMgtClientException; import org.wso2.carbon.identity.oauth2.impersonation.exceptions.ImpersonationConfigMgtException; import org.wso2.carbon.identity.oauth2.impersonation.exceptions.ImpersonationConfigMgtServerException; @@ -173,6 +178,7 @@ public class ServerConfigManagementService { private final DCRConfigurationMgtService dcrConfigurationMgtService; private final OAuth2OIDCConfigOrgUsageScopeMgtService oauth2OIDCConfigOrgUsageScopeMgtService; private final CompatibilitySettingsService compatibilitySettingsService; + private final FapiConfigMgtService fapiConfigMgtService; private static final Log log = LogFactory.getLog(ServerConfigManagementService.class); @@ -186,7 +192,8 @@ public ServerConfigManagementService(ApplicationManagementService applicationMan FraudDetectionConfigsService fraudDetectionConfigsService, OAuth2OIDCConfigOrgUsageScopeMgtService oauth2OIDCConfigOrgUsageScopeMgtService, - CompatibilitySettingsService identityCompatibilitySettingsService) { + CompatibilitySettingsService identityCompatibilitySettingsService, + FapiConfigMgtService fapiConfigMgtService) { this.applicationManagementService = applicationManagementService; this.idpManager = idpManager; @@ -198,6 +205,7 @@ public ServerConfigManagementService(ApplicationManagementService applicationMan this.fraudDetectionConfigsService = fraudDetectionConfigsService; this.oauth2OIDCConfigOrgUsageScopeMgtService = oauth2OIDCConfigOrgUsageScopeMgtService; this.compatibilitySettingsService = identityCompatibilitySettingsService; + this.fapiConfigMgtService = fapiConfigMgtService; } /** @@ -517,6 +525,52 @@ public void deleteImpersonationConfiguration() { } } + /** + * Get the FAPI configuration for the current tenant. + * + * @return FapiConfig API model. + */ + public FapiConfig getFAPIConfiguration() { + + String tenantDomain = ContextLoader.getTenantDomainFromContext(); + try { + org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig fapiConfig = + fapiConfigMgtService.getFapiConfig(tenantDomain); + return FAPIConnectorUtil.toApiModel(fapiConfig); + } catch (FapiConfigMgtClientException e) { + log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE.message(), e); + throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, + Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE, tenantDomain)); + } catch (FapiConfigMgtException e) { + log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE.message(), e); + throw new APIError(Response.Status.INTERNAL_SERVER_ERROR, this.getFapiConfigErrorResponse(e, + Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE, tenantDomain)); + } + } + + /** + * Update the FAPI configuration for the current tenant. + * + * @param fapiConfig the API model to persist. + * @return the updated FapiConfig API model. + */ + public FapiConfig updateFAPIConfiguration(FapiConfig fapiConfig) { + + String tenantDomain = ContextLoader.getTenantDomainFromContext(); + try { + fapiConfigMgtService.setFapiConfig(FAPIConnectorUtil.toOAuthModel(fapiConfig), tenantDomain); + return fapiConfig; + } catch (FapiConfigMgtClientException e) { + log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE.message(), e); + throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, + Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE, tenantDomain)); + } catch (FapiConfigMgtException e) { + log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE.message(), e); + throw new APIError(Response.Status.INTERNAL_SERVER_ERROR, this.getFapiConfigErrorResponse(e, + Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE, tenantDomain)); + } + } + /** * Get the CORS config for a tenant. */ @@ -1454,6 +1508,22 @@ private APIError handleImpersonationConfigException(ImpersonationConfigMgtExcept return new APIError(status, errorResponse); } + + private ErrorResponse getFapiConfigErrorResponse(FapiConfigMgtException e, + Constants.ErrorMessage errorEnum, String data) { + + final ErrorResponse errorResponse = getErrorBuilder(errorEnum, data).build(log, e.getMessage()); + errorResponse.setDescription(e.getMessage()); + if (e.getErrorCode() != null) { + String errorCode = e.getErrorCode(); + errorCode = errorCode.contains( + org.wso2.carbon.identity.api.server.common.Constants.ERROR_CODE_DELIMITER) + ? errorCode : Constants.CONFIG_ERROR_PREFIX + errorCode; + errorResponse.setCode(errorCode); + } + return errorResponse; + } + /** * Handle exceptions generated in API. * @@ -1668,6 +1738,13 @@ public void patchDCRConfig(List dcrPatchList) { } else if (path.matches(Constants.DCR_CONFIG_SSA_JWKS)) { String value = dcrPatch.getValue(); dcrConfig.setSsaJwks(value); + } else if (path.matches(Constants.DCR_CONFIG_FAPI_PROFILE)) { + FapiProfile fapiProfile = FapiProfile.fromValue(dcrPatch.getValue()); + if (fapiProfile == null) { + throw handleException(Response.Status.BAD_REQUEST, Constants.ErrorMessage + .ERROR_CODE_INVALID_INPUT, "Unsupported patch value for the given path"); + } + dcrConfig.setFapiProfile(fapiProfile); } else { // Throw an error if any other patch operations are sent in the request. throw handleException(Response.Status.BAD_REQUEST, Constants.ErrorMessage @@ -2390,10 +2467,6 @@ public UsageScopePayload updateIssuerUsageScopeConfig(UsageScopePatch usageScope updateIssuerUsageScopeConfig(tenantDomain, issuerUsageScopeConfig); return buildIssuerUsageScopeConfig(updateIssuerUsageScopeConfig, tenantDomain); } catch (OAuth2OIDCConfigOrgUsageScopeMgtException | OrganizationManagementException e) { - if (e instanceof OAuth2OIDCConfigOrgUsageScopeMgtClientException) { - throw handleException(Response.Status.BAD_REQUEST, - Constants.ErrorMessage.ERROR_CODE_CLIENT_ERROR_ISSUER_USAGE_SCOPE_UPDATE, e.getMessage()); - } throw handleException(Response.Status.INTERNAL_SERVER_ERROR, Constants.ErrorMessage.ERROR_CODE_ERROR_ISSUER_USAGE_SCOPE_UPDATE, e.getMessage()); } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/FAPIConnectorUtil.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/FAPIConnectorUtil.java new file mode 100644 index 0000000000..1cae2e2f50 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/FAPIConnectorUtil.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.api.server.configs.v1.function; + +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiConfig; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiProfile; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Utility class for converting between the API-layer FAPI model and the OAuth-bundle FAPI model. + */ +public class FAPIConnectorUtil { + + private FAPIConnectorUtil() { + // Utility class — no instantiation. + } + + /** + * Convert an OAuth-bundle {@link org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig} + * to the API-layer {@link FapiConfig}. + * + * @param oauthModel the OAuth bundle model; may be null. + * @return the API model; never null. + */ + public static FapiConfig toApiModel( + org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig oauthModel) { + + FapiConfig apiModel = new FapiConfig(); + if (oauthModel == null) { + apiModel.setEnabled(false); + apiModel.setSupportedProfiles(Collections.emptyList()); + return apiModel; + } + apiModel.setEnabled(oauthModel.isEnabled()); + List oauthProfiles = + oauthModel.getSupportedProfiles(); + if (oauthProfiles == null || oauthProfiles.isEmpty()) { + apiModel.setSupportedProfiles(Collections.emptyList()); + } else { + apiModel.setSupportedProfiles( + oauthProfiles.stream() + .map(p -> FapiProfile.fromValue(p.value())) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + } + return apiModel; + } + + /** + * Convert an API-layer {@link FapiConfig} to the OAuth-bundle + * {@link org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig}. + * + * @param apiModel the API layer model; may be null. + * @return the OAuth model; never null. + */ + public static org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig toOAuthModel(FapiConfig apiModel) { + + org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig oauthModel = + new org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig(); + if (apiModel == null) { + return oauthModel; + } + oauthModel.setEnabled(Boolean.TRUE.equals(apiModel.getEnabled())); + List apiProfiles = apiModel.getSupportedProfiles(); + if (apiProfiles == null || apiProfiles.isEmpty()) { + oauthModel.setSupportedProfiles(Collections.emptyList()); + } else { + oauthModel.setSupportedProfiles( + apiProfiles.stream() + .map(p -> org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum.fromValue( + p.value())) + .filter(Objects::nonNull) + .collect(Collectors.toList())); + } + return oauthModel; + } +} From b51ffcd5256c01b29b7335fc85e2955803c52a6b Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Tue, 19 May 2026 11:56:00 +0530 Subject: [PATCH 2/6] feat(fapi2): Merge master --- .../ApplicationManagementConstants.java | 12 +- .../ApplicationManagementServiceHolder.java | 17 +++ .../management/v1/FapiMetadata.java | 6 +- .../v1/OpenIDConnectConfiguration.java | 22 +++ .../ServerApplicationMetadataService.java | 56 +++++++ .../oauth2/ApiModelToOAuthConsumerApp.java | 2 +- .../oauth2/OAuthConsumerAppToApiModel.java | 30 ++++ ...rverApplicationMetadataServiceFactory.java | 4 +- .../src/main/resources/applications.yaml | 19 +++ .../configs/common/ConfigsServiceHolder.java | 18 +++ .../api/server/configs/common/Constants.java | 14 +- .../pom.xml | 66 ++++---- .../api/server/configs/v1/ConfigsApi.java | 49 ++++++ .../server/configs/v1/ConfigsApiService.java | 5 + .../server/configs/v1/model/DCRConfig.java | 27 +++- .../core/ServerConfigManagementService.java | 3 +- .../ServerConfigManagementServiceFactory.java | 9 +- .../configs/v1/function/DCRConnectorUtil.java | 7 +- .../v1/impl/ConfigsApiServiceImpl.java | 13 ++ .../src/main/resources/configs.yaml | 144 ++++++++++++++++-- 20 files changed, 464 insertions(+), 59 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementConstants.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementConstants.java index bd6a8f5489..579904570c 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementConstants.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementConstants.java @@ -250,7 +250,17 @@ public enum ErrorMessage { // Organization application based issuer configuration related error messages. ERROR_RETRIEVING_ALLOWED_ISSUERS("65603", "Error occurred while retrieving allowed issuers for the tenant.", - "Unexpected error occurred while retrieving allowed issuers for the tenant."); + "Unexpected error occurred while retrieving allowed issuers for the tenant."), + + // FAPI metadata related error messages. + ERROR_RETRIEVING_FAPI_METADATA("65604", + "Error occurred while retrieving FAPI metadata.", + "Unexpected error occurred while retrieving FAPI metadata for tenant: %s."), + + // FAPI profile validation related error messages. + UNSUPPORTED_FAPI_PROFILE("65605", + "Unsupported FAPI profile.", + "The provided FAPI profile '%s' is not supported by the organization. Supported profiles: %s."); private final String code; private final String message; diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementServiceHolder.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementServiceHolder.java index 124acd7814..bb876390bb 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementServiceHolder.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.common/src/main/java/org/wso2/carbon/identity/api/server/application/management/common/ApplicationManagementServiceHolder.java @@ -31,6 +31,7 @@ import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthServiceImpl; import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth2.config.services.OAuth2OIDCConfigOrgUsageScopeMgtService; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.organization.management.application.OrgApplicationManager; import org.wso2.carbon.identity.sso.saml.SAMLSSOConfigServiceImpl; import org.wso2.carbon.identity.template.mgt.TemplateManager; @@ -151,6 +152,12 @@ private static class OAuthOIDCConfigOrgUsageScopeMgtServiceHolder { .getOSGiService(OAuth2OIDCConfigOrgUsageScopeMgtService.class, null); } + private static class FapiConfigMgtServiceHolder { + + static final FapiConfigMgtService SERVICE = (FapiConfigMgtService) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(FapiConfigMgtService.class, null); + } + /** * Get ApplicationManagementService. * @@ -289,4 +296,14 @@ public static OAuth2OIDCConfigOrgUsageScopeMgtService getOAuth2OIDCConfigOrgUsag return OAuthOIDCConfigOrgUsageScopeMgtServiceHolder.SERVICE; } + + /** + * Get FapiConfigMgtService. + * + * @return FapiConfigMgtService. + */ + public static FapiConfigMgtService getFapiConfigMgtService() { + + return FapiConfigMgtServiceHolder.SERVICE; + } } diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java index c2e5121769..0985b770a0 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java @@ -64,7 +64,7 @@ public FapiMetadata allowedSignatureAlgorithms(MetadataProperty allowedSignature this.allowedSignatureAlgorithms = allowedSignatureAlgorithms; return this; } - + @ApiModelProperty(value = "") @JsonProperty("allowedSignatureAlgorithms") @Valid @@ -82,7 +82,7 @@ public FapiMetadata allowedEncryptionAlgorithms(MetadataProperty allowedEncrypti this.allowedEncryptionAlgorithms = allowedEncryptionAlgorithms; return this; } - + @ApiModelProperty(value = "") @JsonProperty("allowedEncryptionAlgorithms") @Valid @@ -100,7 +100,7 @@ public FapiMetadata tokenEndpointAuthMethod(ClientAuthenticationMethodMetadata t this.tokenEndpointAuthMethod = tokenEndpointAuthMethod; return this; } - + @ApiModelProperty(value = "") @JsonProperty("tokenEndpointAuthMethod") @Valid diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/OpenIDConnectConfiguration.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/OpenIDConnectConfiguration.java index aa0a924bc2..5439a4132c 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/OpenIDConnectConfiguration.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/OpenIDConnectConfiguration.java @@ -104,6 +104,7 @@ public static StateEnum fromValue(String value) { private SubjectConfiguration subject; private Boolean isFAPIApplication = false; private FapiMetadata fapiMetadata; + private FapiProfile fapiProfile = null; private CIBAAuthenticationRequestConfiguration cibaAuthenticationRequest; private AllowedIssuer issuer; @@ -538,6 +539,25 @@ public void setFapiMetadata(FapiMetadata fapiMetadata) { this.fapiMetadata = fapiMetadata; } + /** + * The FAPI security profile applied to the application. Applicable only when isFAPIApplication is true. If isFAPIApplication is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. + **/ + public OpenIDConnectConfiguration fapiProfile(FapiProfile fapiProfile) { + + this.fapiProfile = fapiProfile; + return this; + } + + @ApiModelProperty(example = "FAPI1_ADVANCED", value = "The FAPI security profile applied to the application. Applicable only when isFAPIApplication is true. If isFAPIApplication is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. ") + @JsonProperty("fapiProfile") + @Valid + public FapiProfile getFapiProfile() { + return fapiProfile; + } + public void setFapiProfile(FapiProfile fapiProfile) { + this.fapiProfile = fapiProfile; + } + /** **/ public OpenIDConnectConfiguration cibaAuthenticationRequest(CIBAAuthenticationRequestConfiguration cibaAuthenticationRequest) { @@ -608,6 +628,7 @@ public boolean equals(java.lang.Object o) { Objects.equals(this.subject, openIDConnectConfiguration.subject) && Objects.equals(this.isFAPIApplication, openIDConnectConfiguration.isFAPIApplication) && Objects.equals(this.fapiMetadata, openIDConnectConfiguration.fapiMetadata) && + Objects.equals(this.fapiProfile, openIDConnectConfiguration.fapiProfile) && Objects.equals(this.cibaAuthenticationRequest, openIDConnectConfiguration.cibaAuthenticationRequest) && Objects.equals(this.issuer, openIDConnectConfiguration.issuer); } @@ -646,6 +667,7 @@ public String toString() { sb.append(" subject: ").append(toIndentedString(subject)).append("\n"); sb.append(" isFAPIApplication: ").append(toIndentedString(isFAPIApplication)).append("\n"); sb.append(" fapiMetadata: ").append(toIndentedString(fapiMetadata)).append("\n"); + sb.append(" fapiProfile: ").append(toIndentedString(fapiProfile)).append("\n"); sb.append(" cibaAuthenticationRequest: ").append(toIndentedString(cibaAuthenticationRequest)).append("\n"); sb.append(" issuer: ").append(toIndentedString(issuer)).append("\n"); sb.append("}"); diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java index f1c6552d60..d599433489 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java @@ -42,6 +42,7 @@ import org.wso2.carbon.identity.api.server.application.management.v1.SAMLMetaData; import org.wso2.carbon.identity.api.server.application.management.v1.WSTrustMetaData; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils; +import org.wso2.carbon.identity.api.server.common.ContextLoader; import org.wso2.carbon.identity.api.server.common.error.APIError; import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.application.mgt.AbstractInboundAuthenticatorConfig; @@ -56,6 +57,10 @@ import org.wso2.carbon.identity.oauth2.config.exceptions.OAuth2OIDCConfigOrgUsageScopeMgtException; import org.wso2.carbon.identity.oauth2.config.models.IssuerDetails; import org.wso2.carbon.identity.oauth2.config.services.OAuth2OIDCConfigOrgUsageScopeMgtService; +import org.wso2.carbon.identity.oauth2.fapi.exceptions.FapiConfigMgtException; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.oauth2.model.ClientAuthenticationMethodModel; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; import org.wso2.carbon.identity.sso.saml.SAMLSSOConfigServiceImpl; @@ -65,12 +70,14 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; +import org.apache.commons.collections.CollectionUtils; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.DEFAULT_CERTIFICATE_ALIAS; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.DEFAULT_NAME_ID_FORMAT; @@ -90,6 +97,7 @@ public class ServerApplicationMetadataService { private final OAuthAdminServiceImpl oAuthAdminService; private final STSAdminServiceInterface sTSAdminServiceInterface; private final CibaAuthServiceImpl cibaAuthService; + private final FapiConfigMgtService fapiConfigMgtService; @Deprecated public ServerApplicationMetadataService(ApplicationManagementService applicationManagementService, @@ -102,8 +110,10 @@ public ServerApplicationMetadataService(ApplicationManagementService application this.oAuthAdminService = oAuthAdminService; this.sTSAdminServiceInterface = sTSAdminServiceInterface; this.cibaAuthService = ApplicationManagementServiceHolder.getCibaAuthService(); + this.fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); } + @Deprecated public ServerApplicationMetadataService(ApplicationManagementService applicationManagementService, SAMLSSOConfigServiceImpl samlSSOConfigService, OAuthAdminServiceImpl oAuthAdminService, @@ -115,6 +125,22 @@ public ServerApplicationMetadataService(ApplicationManagementService application this.oAuthAdminService = oAuthAdminService; this.sTSAdminServiceInterface = sTSAdminServiceInterface; this.cibaAuthService = cibaAuthService; + this.fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); + } + + public ServerApplicationMetadataService(ApplicationManagementService applicationManagementService, + SAMLSSOConfigServiceImpl samlSSOConfigService, + OAuthAdminServiceImpl oAuthAdminService, + STSAdminServiceInterface sTSAdminServiceInterface, + CibaAuthServiceImpl cibaAuthService, + FapiConfigMgtService fapiConfigMgtService) { + + this.applicationManagementService = applicationManagementService; + this.samlSSOConfigService = samlSSOConfigService; + this.oAuthAdminService = oAuthAdminService; + this.sTSAdminServiceInterface = sTSAdminServiceInterface; + this.cibaAuthService = cibaAuthService; + this.fapiConfigMgtService = fapiConfigMgtService; } private static final Log LOG = LogFactory.getLog(ServerApplicationMetadataService.class); @@ -262,6 +288,7 @@ public OIDCMetaData getOIDCMetadata() { supportedClientAuthMethods.stream().filter(clientAuthenticationMethod -> fapiAllowedAuthMethods.contains(clientAuthenticationMethod.getName())).collect(Collectors.toList()); FapiMetadata fapiMetadata = new FapiMetadata(); + fapiMetadata.allowedFapiProfiles(new MetadataProperty().options(getAllowedFapiProfiles())); fapiMetadata.allowedSignatureAlgorithms(new MetadataProperty().options(fapiAllowedSignatureAlgorithms)); fapiMetadata.allowedEncryptionAlgorithms(new MetadataProperty().options(fapiAllowedEncryptionAlgorithms)); fapiMetadata.setTokenEndpointAuthMethod(new ClientAuthenticationMethodMetadata() @@ -528,6 +555,35 @@ private List getAllowedIssuersForOrganization() { } } + /** + * Retrieves the list of allowed FAPI profiles for the current tenant from FapiConfigMgtService. + * Returns an empty list if the service is unavailable or no profiles are configured. + * + * @return List of allowed FAPI profile string values. + */ + private List getAllowedFapiProfiles() { + + if (fapiConfigMgtService == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("FapiConfigMgtService is not available. Returning empty FAPI profiles list."); + } + return Collections.emptyList(); + } + String tenantDomain = ContextLoader.getTenantDomainFromContext(); + try { + FapiConfig fapiConfig = fapiConfigMgtService.getFapiConfig(tenantDomain); + List supportedProfiles = fapiConfig.getSupportedProfiles(); + if (CollectionUtils.isEmpty(supportedProfiles)) { + return Collections.emptyList(); + } + return supportedProfiles.stream() + .map(FapiProfileEnum::value) + .collect(Collectors.toList()); + } catch (FapiConfigMgtException e) { + throw handleServerError(ErrorMessage.ERROR_RETRIEVING_FAPI_METADATA, e); + } + } + /** * Handles the server errors and build APIError response with the given error message and exception. * diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java index 584990ec15..ff67ead58c 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/ApiModelToOAuthConsumerApp.java @@ -173,7 +173,7 @@ private void updateRefreshTokenConfiguration(OAuthConsumerAppDTO consumerAppDTO, } private void updateAllowedOrigins(OAuthConsumerAppDTO consumerAppDTO, List allowedOrigins) { - + // Setting the allowed origins since now the cors origin services will be called and handle by the Oauth2 // Inbound config handler consumerAppDTO.setAllowedOrigins(allowedOrigins); diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java index 78d7f139ac..25390db743 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java @@ -18,10 +18,13 @@ package org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.oauth2; import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.api.server.application.management.v1.AccessTokenConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.AllowedIssuer; import org.wso2.carbon.identity.api.server.application.management.v1.CIBAAuthenticationRequestConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.ClientAuthenticationConfiguration; +import org.wso2.carbon.identity.api.server.application.management.v1.FapiProfile; import org.wso2.carbon.identity.api.server.application.management.v1.HybridFlowConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.IdTokenConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.IdTokenEncryptionConfiguration; @@ -48,6 +51,8 @@ */ public class OAuthConsumerAppToApiModel implements Function { + private static final Log log = LogFactory.getLog(OAuthConsumerAppToApiModel.class); + @Override public OpenIDConnectConfiguration apply(OAuthConsumerAppDTO oauthAppDTO) { @@ -72,6 +77,7 @@ public OpenIDConnectConfiguration apply(OAuthConsumerAppDTO oauthAppDTO) { .pushAuthorizationRequest(buildPARAuthenticationConfiguration(oauthAppDTO)) .subject(buildSubjectConfiguration(oauthAppDTO)) .isFAPIApplication(oauthAppDTO.isFapiConformanceEnabled()) + .fapiProfile(buildFapiProfileConfiguration(oauthAppDTO)) .subjectToken(buildSubjectTokenConfiguration(oauthAppDTO)) .cibaAuthenticationRequest(buildCIBAAuthenticationRequestConfiguration(oauthAppDTO)) .issuer(buildIssuerOrganizationConfiguration(oauthAppDTO)); @@ -272,4 +278,28 @@ private AllowedIssuer buildIssuerOrganizationConfiguration(OAuthConsumerAppDTO o } return null; } + + /** + * Converts the stored FAPI profile string from the DTO into the API model enum. + * Returns null if no profile is stored, which will omit the field from the response. + * Logs a warning if an unrecognised value is found (data integrity issue, not an API error). + * + * @param oauthAppDTO the DTO containing the stored FAPI profile string. + * @return the {@link FapiProfile} enum constant, or null if not set. + */ + private FapiProfile buildFapiProfileConfiguration(OAuthConsumerAppDTO oauthAppDTO) { + + String fapiProfileValue = oauthAppDTO.getFapiProfile(); + if (fapiProfileValue == null) { + return null; + } + try { + return FapiProfile.fromValue(fapiProfileValue); + } catch (IllegalArgumentException e) { + log.warn("Unrecognised fapiProfile value stored for application '" + + oauthAppDTO.getApplicationName() + "': " + fapiProfileValue + + ". Omitting from response."); + return null; + } + } } diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/factories/ServerApplicationMetadataServiceFactory.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/factories/ServerApplicationMetadataServiceFactory.java index 6028f95876..536b511c4f 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/factories/ServerApplicationMetadataServiceFactory.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/factories/ServerApplicationMetadataServiceFactory.java @@ -23,6 +23,7 @@ import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.oauth.OAuthAdminServiceImpl; import org.wso2.carbon.identity.oauth.ciba.api.CibaAuthServiceImpl; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.sso.saml.SAMLSSOConfigServiceImpl; import org.wso2.carbon.security.sts.service.STSAdminServiceInterface; @@ -40,6 +41,7 @@ public class ServerApplicationMetadataServiceFactory { OAuthAdminServiceImpl oAuthAdminService = ApplicationManagementServiceHolder.getOAuthAdminService(); STSAdminServiceInterface sTSAdminServiceInterface = ApplicationManagementServiceHolder.getStsAdminService(); CibaAuthServiceImpl cibaAuthService = ApplicationManagementServiceHolder.getCibaAuthService(); + FapiConfigMgtService fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); if (applicationManagementService == null) { throw new IllegalStateException("ApplicationManagementService is not available from OSGi context."); @@ -56,7 +58,7 @@ public class ServerApplicationMetadataServiceFactory { // Null check for STSAdminServiceInterface is not mandatory as per the previous implementation. SERVICE = new ServerApplicationMetadataService(applicationManagementService, samlSSOConfigService, - oAuthAdminService, sTSAdminServiceInterface, cibaAuthService); + oAuthAdminService, sTSAdminServiceInterface, cibaAuthService, fapiConfigMgtService); } /** diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml index f64d1751ad..ef0d19b73c 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml @@ -3977,6 +3977,14 @@ components: default: false description: Enabling this option will make the application FAPI conformant. example: false + fapiProfile: + description: | + The FAPI security profile applied to the application. Applicable only when isFAPIApplication is true. + If isFAPIApplication is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. + allOf: + - $ref: '#/components/schemas/FapiProfile' + default: FAPI1_ADVANCED + example: FAPI1_ADVANCED cibaAuthenticationRequest: $ref: '#/components/schemas/CIBAAuthenticationRequestConfiguration' issuer: @@ -4308,12 +4316,23 @@ components: FapiMetadata: type: object properties: + allowedFapiProfiles: + $ref: '#/components/schemas/MetadataProperty' allowedSignatureAlgorithms: $ref: '#/components/schemas/MetadataProperty' allowedEncryptionAlgorithms: $ref: '#/components/schemas/MetadataProperty' tokenEndpointAuthMethod: $ref: '#/components/schemas/ClientAuthenticationMethodMetadata' + FapiProfile: + type: string + description: | + FAPI security profile. + - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile. + - `FAPI2_SECURITY`: FAPI 2.0 Security Profile. + enum: + - FAPI1_ADVANCED + - FAPI2_SECURITY CIBAMetadata: type: object properties: diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/ConfigsServiceHolder.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/ConfigsServiceHolder.java index c28cdd1b2f..95d8e1111e 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/ConfigsServiceHolder.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/ConfigsServiceHolder.java @@ -27,6 +27,7 @@ import org.wso2.carbon.identity.fraud.detection.core.service.FraudDetectionConfigsService; import org.wso2.carbon.identity.oauth.dcr.DCRConfigurationMgtService; import org.wso2.carbon.identity.oauth2.config.services.OAuth2OIDCConfigOrgUsageScopeMgtService; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.oauth2.impersonation.services.ImpersonationConfigMgtService; import org.wso2.carbon.identity.oauth2.token.handler.clientauth.jwt.core.JWTClientAuthenticatorMgtService; import org.wso2.carbon.idp.mgt.IdentityProviderManager; @@ -118,6 +119,13 @@ private static class IdentityCompatibilitySettingsServiceHolder { .getOSGiService(CompatibilitySettingsService.class, null); } + private static class FapiConfigMgtServiceHolder { + + static final FapiConfigMgtService SERVICE = + (FapiConfigMgtService) PrivilegedCarbonContext.getThreadLocalCarbonContext() + .getOSGiService(FapiConfigMgtService.class, null); + } + /** * Get ApplicationManagementService osgi service. * @@ -237,4 +245,14 @@ public static CompatibilitySettingsService getIdentityCompatibilitySettingsServi return IdentityCompatibilitySettingsServiceHolder.SERVICE; } + + /** + * Get FapiConfigMgtService osgi service. + * + * @return FapiConfigMgtService + */ + public static FapiConfigMgtService getFapiConfigMgtService() { + + return FapiConfigMgtServiceHolder.SERVICE; + } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/Constants.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/Constants.java index 3ad3f6b0bb..f7554e5d98 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/Constants.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.common/src/main/java/org/wso2/carbon/identity/api/server/configs/common/Constants.java @@ -72,6 +72,7 @@ private Constants() { public static final String DCR_CONFIG_SSA_JWKS = "/ssaJwks"; public static final String DCR_CONFIG_AUTHENTICATION_REQUIRED = "/authenticationRequired"; public static final String DCR_CONFIG_MANDATE_SSA = "/mandateSSA"; + public static final String DCR_CONFIG_FAPI_PROFILE = "/fapiProfile"; /** * SAML2 metadata endpoint uri path. @@ -259,7 +260,18 @@ public enum ErrorMessage { "Server encountered an error while updating the Compatibility Settings."), ERROR_CODE_SETTING_GROUP_NOT_FOUND("60007", "Setting group not found.", - "Unable to find compatibility settings for the setting group %s."); + "Unable to find compatibility settings for the setting group %s."), + + /** + * FAPI Configuration errors. + */ + ERROR_CODE_FAPI_CONFIG_RETRIEVE("65033", + "Unable to retrieve FAPI configuration.", + "Server encountered an error while retrieving the FAPI configuration."), + + ERROR_CODE_FAPI_CONFIG_UPDATE("65034", + "Unable to update FAPI configuration.", + "Server encountered an error while updating the FAPI configuration."); private final String code; private final String message; diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml index 0fedf410cc..c117e4b8e8 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml @@ -30,39 +30,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + org.openapitools + openapi-generator-maven-plugin + 4.1.2 + + + + generate + + + ${project.basedir}/src/main/resources/configs.yaml + org.wso2.carbon.codegen.CxfWso2Generator + + src/gen/java + org.wso2.carbon.identity.api.server.configs.v1 + org.wso2.carbon.identity.api.server.configs.v1.model + org.wso2.carbon.identity.api.server.configs.v1 + java8 + true + + . + true + + + + + + org.openapitools + cxf-wso2-openapi-generator + 1.0.0 + + + org.codehaus.mojo build-helper-maven-plugin diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java index c9f0f3296c..b5be10ff89 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java @@ -33,6 +33,7 @@ import org.wso2.carbon.identity.api.server.configs.v1.model.DCRConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.DCRPatch; import org.wso2.carbon.identity.api.server.configs.v1.model.Error; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.FraudDetectionConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.ImpersonationConfiguration; import org.wso2.carbon.identity.api.server.configs.v1.model.ImpersonationPatch; @@ -1024,4 +1025,52 @@ public Response getCompatibilitySettingsByGroup(@ApiParam(value = "Setting group return delegate.getCompatibilitySettingsByGroup(settingGroup); } + + @Valid + @GET + @Path("/fapi") + + @Produces({ "application/json" }) + @ApiOperation(value = "Retrieve the tenant FAPI configuration.", notes = "Retrieve the tenant Financial-grade API (FAPI) configuration.", response = FapiConfig.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "FAPI Configurations", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successful Response", response = FapiConfig.class), + @ApiResponse(code = 400, message = "Bad Request", response = Error.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Forbidden", response = Void.class), + @ApiResponse(code = 404, message = "Not Found", response = Error.class), + @ApiResponse(code = 500, message = "Server Error", response = Error.class) + }) + public Response getFAPIConfiguration() { + + return delegate.getFAPIConfiguration(); + } + + @Valid + @PATCH + @Path("/fapi") + @Consumes({ "application/json" }) + @Produces({ "application/json" }) + @ApiOperation(value = "Patch the tenant FAPI configuration.", notes = "Patch the tenant Financial-grade API (FAPI) configuration. Scope (Permission) required:
* internal_config_update ", response = FapiConfig.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "FAPI Configurations", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Successful Response", response = FapiConfig.class), + @ApiResponse(code = 400, message = "Bad Request", response = Error.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Forbidden", response = Void.class), + @ApiResponse(code = 404, message = "Not Found", response = Error.class), + @ApiResponse(code = 500, message = "Server Error", response = Error.class) + }) + public Response patchFAPIConfiguration(@ApiParam(value = "" ,required=true) @Valid FapiConfig fapiConfig) { + + return delegate.patchFAPIConfiguration(fapiConfig ); + } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java index c7d7deac38..65d4b149b5 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java @@ -66,8 +66,11 @@ public interface ConfigsApiService { public Response getPassiveSTSInboundAuthConfig(); public Response getPrivatKeyJWTValidationConfiguration(); + public Response getDCRConfiguration(); + public Response getFAPIConfiguration(); + public Response getRemoteLoggingConfig(String logType); public Response getRemoteLoggingConfigs(); @@ -90,6 +93,8 @@ public interface ConfigsApiService { public Response patchDCRConfiguration(List patch); + public Response patchFAPIConfiguration(FapiConfig fapiConfig); + public Response restoreServerRemoteLoggingConfiguration(String logType); public Response restoreServerRemoteLoggingConfigurations(); diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/DCRConfig.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/DCRConfig.java index 32ed63eeb7..8c1b19e252 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/DCRConfig.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/DCRConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2023-2026, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -22,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiProfile; import javax.validation.constraints.*; @@ -35,6 +36,7 @@ public class DCRConfig { private Boolean authenticationRequired; private String ssaJwks; private Boolean enableFapiEnforcement; + private FapiProfile fapiProfile = null; private Boolean mandateSSA; /** @@ -94,6 +96,25 @@ public void setEnableFapiEnforcement(Boolean enableFapiEnforcement) { this.enableFapiEnforcement = enableFapiEnforcement; } + /** + * The FAPI security profile to enforce for applications created via DCR. Applicable only when enableFapiEnforcement is true. If enableFapiEnforcement is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. + **/ + public DCRConfig fapiProfile(FapiProfile fapiProfile) { + + this.fapiProfile = fapiProfile; + return this; + } + + @ApiModelProperty(example = "FAPI1_ADVANCED", value = "The FAPI security profile to enforce for applications created via DCR. Applicable only when enableFapiEnforcement is true. If enableFapiEnforcement is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. ") + @JsonProperty("fapiProfile") + @Valid + public FapiProfile getFapiProfile() { + return fapiProfile; + } + public void setFapiProfile(FapiProfile fapiProfile) { + this.fapiProfile = fapiProfile; + } + /** * If true, the software_statement parameter is mandatory for the DCR create request. **/ @@ -128,12 +149,13 @@ public boolean equals(java.lang.Object o) { return Objects.equals(this.authenticationRequired, dcRConfig.authenticationRequired) && Objects.equals(this.ssaJwks, dcRConfig.ssaJwks) && Objects.equals(this.enableFapiEnforcement, dcRConfig.enableFapiEnforcement) && + Objects.equals(this.fapiProfile, dcRConfig.fapiProfile) && Objects.equals(this.mandateSSA, dcRConfig.mandateSSA); } @Override public int hashCode() { - return Objects.hash(authenticationRequired, ssaJwks, enableFapiEnforcement, mandateSSA); + return Objects.hash(authenticationRequired, ssaJwks, enableFapiEnforcement, fapiProfile, mandateSSA); } @Override @@ -145,6 +167,7 @@ public String toString() { sb.append(" authenticationRequired: ").append(toIndentedString(authenticationRequired)).append("\n"); sb.append(" ssaJwks: ").append(toIndentedString(ssaJwks)).append("\n"); sb.append(" enableFapiEnforcement: ").append(toIndentedString(enableFapiEnforcement)).append("\n"); + sb.append(" fapiProfile: ").append(toIndentedString(fapiProfile)).append("\n"); sb.append(" mandateSSA: ").append(toIndentedString(mandateSSA)).append("\n"); sb.append("}"); return sb.toString(); diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java index 4d6f7c221b..37afde5dc3 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java @@ -192,8 +192,7 @@ public ServerConfigManagementService(ApplicationManagementService applicationMan FraudDetectionConfigsService fraudDetectionConfigsService, OAuth2OIDCConfigOrgUsageScopeMgtService oauth2OIDCConfigOrgUsageScopeMgtService, - CompatibilitySettingsService identityCompatibilitySettingsService, - FapiConfigMgtService fapiConfigMgtService) { + CompatibilitySettingsService identityCompatibilitySettingsService) { this.applicationManagementService = applicationManagementService; this.idpManager = idpManager; diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/factories/ServerConfigManagementServiceFactory.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/factories/ServerConfigManagementServiceFactory.java index df4b6c514e..a97fe9f1db 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/factories/ServerConfigManagementServiceFactory.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/factories/ServerConfigManagementServiceFactory.java @@ -8,6 +8,7 @@ import org.wso2.carbon.identity.fraud.detection.core.service.FraudDetectionConfigsService; import org.wso2.carbon.identity.oauth.dcr.DCRConfigurationMgtService; import org.wso2.carbon.identity.oauth2.config.services.OAuth2OIDCConfigOrgUsageScopeMgtService; +import org.wso2.carbon.identity.oauth2.fapi.services.FapiConfigMgtService; import org.wso2.carbon.identity.oauth2.impersonation.services.ImpersonationConfigMgtService; import org.wso2.carbon.identity.oauth2.token.handler.clientauth.jwt.core.JWTClientAuthenticatorMgtService; import org.wso2.carbon.idp.mgt.IdentityProviderManager; @@ -39,6 +40,7 @@ public class ServerConfigManagementServiceFactory { ConfigsServiceHolder.getOAuth2OIDCConfigOrgUsageScopeMgtService(); CompatibilitySettingsService compatibilitySettingsService = ConfigsServiceHolder .getIdentityCompatibilitySettingsService(); + FapiConfigMgtService fapiConfigMgtService = ConfigsServiceHolder.getFapiConfigMgtService(); if (applicationManagementService == null) { throw new IllegalStateException("ApplicationManagementService is not available from OSGi context."); @@ -81,6 +83,10 @@ public class ServerConfigManagementServiceFactory { throw new IllegalStateException("CompatibilitySettingsService is not available from OSGi context."); } + if (fapiConfigMgtService == null) { + throw new IllegalStateException("FapiConfigMgtService is not available from OSGi context."); + } + SERVICE = new ServerConfigManagementService(applicationManagementService, identityProviderManager, corsManagementService, remoteLoggingConfigService, @@ -89,7 +95,8 @@ public class ServerConfigManagementServiceFactory { jwtClientAuthenticatorMgtService, fraudDetectionConfigsService, oAuth2OIDCConfigOrgUsageScopeMgtService, - compatibilitySettingsService + compatibilitySettingsService, + fapiConfigMgtService ); } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/DCRConnectorUtil.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/DCRConnectorUtil.java index fa55d9de57..38f4d6be65 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/DCRConnectorUtil.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/function/DCRConnectorUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2024-2026, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -25,11 +25,13 @@ import org.wso2.carbon.identity.api.server.common.error.ErrorResponse; import org.wso2.carbon.identity.api.server.configs.common.Constants; import org.wso2.carbon.identity.api.server.configs.v1.model.DCRConfig; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiProfile; import org.wso2.carbon.identity.oauth.dcr.DCRConfigurationMgtService; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMClientException; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMException; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMServerException; import org.wso2.carbon.identity.oauth.dcr.model.DCRConfiguration; +import org.wso2.carbon.identity.oauth2.fapi.models.FapiProfileEnum; import javax.ws.rs.core.Response; @@ -72,6 +74,7 @@ private static DCRConfig dcrConfigurationToDCRConfig(DCRConfiguration dcrConfigu dcrConfig.setEnableFapiEnforcement(dcrConfiguration.getEnableFapiEnforcement()); dcrConfig.setSsaJwks(dcrConfiguration.getSsaJwks()); dcrConfig.setMandateSSA(dcrConfiguration.getMandateSSA()); + dcrConfig.setFapiProfile(FapiProfile.fromValue(dcrConfiguration.getFapiProfile())); return dcrConfig; } @@ -166,6 +169,8 @@ private static DCRConfiguration getDCRConfigurationFromDCRConfig (DCRConfig dcrC dcrConfiguration.setSsaJwks(dcrConfig.getSsaJwks()); dcrConfiguration.setAuthenticationRequired(dcrConfig.getAuthenticationRequired()); dcrConfiguration.setMandateSSA(dcrConfig.getMandateSSA()); + dcrConfiguration.setFapiProfile(dcrConfig.getFapiProfile() == null ? + null : FapiProfileEnum.fromValue(dcrConfig.getFapiProfile().value())); return dcrConfiguration; } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java index c7af9f4a0d..446411dad3 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java @@ -24,6 +24,7 @@ import org.wso2.carbon.identity.api.server.configs.v1.model.CORSPatch; import org.wso2.carbon.identity.api.server.configs.v1.model.CompatibilitySettings; import org.wso2.carbon.identity.api.server.configs.v1.model.DCRPatch; +import org.wso2.carbon.identity.api.server.configs.v1.model.FapiConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.FraudDetectionConfig; import org.wso2.carbon.identity.api.server.configs.v1.model.ImpersonationPatch; import org.wso2.carbon.identity.api.server.configs.v1.model.InboundAuthOAuth2Config; @@ -119,6 +120,12 @@ public Response getDCRConfiguration() { } + @Override + public Response getFAPIConfiguration() { + + return Response.ok().entity(configManagementService.getFAPIConfiguration()).build(); + } + @Override public Response getRemoteLoggingConfig(String logType) { @@ -161,6 +168,12 @@ public Response patchDCRConfiguration(List dcrPatch) { return Response.ok().build(); } + @Override + public Response patchFAPIConfiguration(final FapiConfig fapiConfig) { + + return Response.ok().entity(configManagementService.updateFAPIConfiguration(fapiConfig)).build(); + } + @Override public Response restoreServerRemoteLoggingConfiguration(String logType) { diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml index f1b1c8f91e..9fe7c40898 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml @@ -1402,6 +1402,87 @@ paths: schema: $ref: '#/components/schemas/Error' + /configs/fapi: + get: + tags: + - FAPI Configurations + summary: Retrieve the tenant FAPI configuration. + operationId: getFAPIConfiguration + description: Retrieve the tenant Financial-grade API (FAPI) configuration. + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/FapiConfig' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + '403': + description: Forbidden + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + patch: + tags: + - FAPI Configurations + summary: Patch the tenant FAPI configuration. + operationId: patchFAPIConfiguration + description: | + Patch the tenant Financial-grade API (FAPI) configuration. + Scope (Permission) required:
+ * internal_config_update + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/FapiConfig' + required: true + responses: + '200': + description: Successful Response + content: + application/json: + schema: + $ref: '#/components/schemas/FapiConfig' + '400': + description: Bad Request + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '401': + description: Unauthorized + '403': + description: Forbidden + '404': + description: Not Found + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Server Error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /configs/compatibility-settings: get: tags: @@ -1606,20 +1687,20 @@ components: type: object properties: adminUser: - type: string - description: "Username of the super admin user in the system." - example: "admin" - readOnly: true + type: string + description: "Username of the super admin user in the system." + example: "admin" + readOnly: true adminRole: - type: string - description: "Name of the super admin role in the system." - example: "Internal/admin" - readOnly: true + type: string + description: "Name of the super admin role in the system." + example: "Internal/admin" + readOnly: true everyoneRole: - type: string - description: "Name of the everyone role in the system." - example: "Internal/everyone" - readOnly: true + type: string + description: "Name of the everyone role in the system." + example: "Internal/everyone" + readOnly: true ProvisioningConfig: type: object properties: @@ -1732,7 +1813,7 @@ components: items: $ref: '#/components/schemas/AuthenticatorProperty' endpoint: - $ref: '#/components/schemas/Endpoint' + $ref: '#/components/schemas/Endpoint' required: - name - displayName @@ -1883,6 +1964,14 @@ components: type: boolean description: If true, a FAPI compliant app will be create with DCR create request. example: true + fapiProfile: + description: | + The FAPI security profile to enforce for applications created via DCR. Applicable only when enableFapiEnforcement is true. + If enableFapiEnforcement is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. + allOf: + - $ref: '#/components/schemas/FapiProfile' + default: FAPI1_ADVANCED + example: FAPI1_ADVANCED mandateSSA: type: boolean description: If true, the software_statement parameter is mandatory for the DCR create request. @@ -2234,3 +2323,32 @@ components: additionalProperties: true example: conflictOnClaimUniquenessViolation: true + FapiProfile: + type: string + description: | + FAPI security profile. + - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile. + - `FAPI2_SECURITY`: FAPI 2.0 Security Profile. + enum: + - FAPI1_ADVANCED + - FAPI2_SECURITY + FapiConfig: + type: object + description: Financial-grade API (FAPI) configuration for the tenant. + properties: + enabled: + type: boolean + description: Indicates whether FAPI compliance enforcement is enabled for the tenant. + example: false + default: false + supportedProfiles: + type: array + description: | + List of FAPI security profiles supported by the tenant. + - `FAPI1_ADVANCED`: FAPI 1.0 Advanced Security Profile (Read and Write API Security Profile). + - `FAPI2_SECURITY`: FAPI 2.0 Security Profile (baseline profile for high-security OAuth 2.0 APIs). + items: + $ref: '#/components/schemas/FapiProfile' + example: + - FAPI1_ADVANCED + - FAPI2_SECURITY From 030fbb30726990fc3eda30e6f07a0ccf601ff8b3 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Tue, 19 May 2026 17:08:18 +0530 Subject: [PATCH 3/6] feat(fapi2): Add FapiConfigMgtService --- .../management/v1/FapiMetadata.java | 2 +- .../management/v1/FapiProfile.java | 2 +- .../ServerApplicationManagementService.java | 6 +- .../ServerApplicationMetadataService.java | 1 - .../oauth2/OAuthConsumerAppToApiModel.java | 7 +- .../pom.xml | 66 +++++++++---------- .../server/configs/v1/model/FapiProfile.java | 3 - .../core/ServerConfigManagementService.java | 8 ++- 8 files changed, 51 insertions(+), 44 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java index 0985b770a0..8618cff220 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2026, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2023-2026, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java index ebc57b06af..0d04a83634 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/gen/java/org/wso2/carbon/identity/api/server/application/management/v1/FapiProfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024-2026, WSO2 LLC. (http://www.wso2.com). + * Copyright (c) 2026, WSO2 LLC. (http://www.wso2.com). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java index c86232b47c..618fb9cc2b 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java @@ -66,7 +66,6 @@ import org.wso2.carbon.identity.api.server.application.management.v1.SAML2Configuration; import org.wso2.carbon.identity.api.server.application.management.v1.SAML2ServiceProvider; import org.wso2.carbon.identity.api.server.application.management.v1.ScriptUpdateModel; -import org.wso2.carbon.identity.api.server.application.management.v1.FapiProfile; import org.wso2.carbon.identity.api.server.application.management.v1.WSTrustConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.ApiModelToServiceProvider; @@ -846,6 +845,11 @@ public String createApplication(ApplicationModel applicationModel, String templa UNSUPPORTED_ENHANCED_ORGANIZATION_AUTHENTICATION_ENABLED_CONFIGURATION.getDescription()); } + if (applicationModel.getEnhancedOrgAuthenticationEnabled() == null + && isEnhancedOrganizationAuthenticationFeatureEnabled()) { + applicationModel.setEnhancedOrgAuthenticationEnabled(isEnhancedOrgAuthEnabledByDefaultForNewApps()); + } + // Block application creation with name Console or MyAccount. if (FrameworkConstants.Application.CONSOLE_APP.equals(applicationModel.getName()) || FrameworkConstants.Application.MY_ACCOUNT_APP.equals(applicationModel.getName())) { diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java index d599433489..7347f27e57 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java @@ -77,7 +77,6 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; -import org.apache.commons.collections.CollectionUtils; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.DEFAULT_CERTIFICATE_ALIAS; import static org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants.DEFAULT_NAME_ID_FORMAT; diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java index 25390db743..78414eac7e 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java @@ -296,9 +296,10 @@ private FapiProfile buildFapiProfileConfiguration(OAuthConsumerAppDTO oauthAppDT try { return FapiProfile.fromValue(fapiProfileValue); } catch (IllegalArgumentException e) { - log.warn("Unrecognised fapiProfile value stored for application '" - + oauthAppDTO.getApplicationName() + "': " + fapiProfileValue - + ". Omitting from response."); + if (log.isDebugEnabled()) { + log.debug(String.format("Unrecognised fapiProfile value stored for application '%s': %s", + oauthAppDTO.getApplicationName(), fapiProfileValue), e); + } return null; } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml index c117e4b8e8..0fedf410cc 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/pom.xml @@ -30,39 +30,39 @@ - - org.openapitools - openapi-generator-maven-plugin - 4.1.2 - - - - generate - - - ${project.basedir}/src/main/resources/configs.yaml - org.wso2.carbon.codegen.CxfWso2Generator - - src/gen/java - org.wso2.carbon.identity.api.server.configs.v1 - org.wso2.carbon.identity.api.server.configs.v1.model - org.wso2.carbon.identity.api.server.configs.v1 - java8 - true - - . - true - - - - - - org.openapitools - cxf-wso2-openapi-generator - 1.0.0 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo build-helper-maven-plugin diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java index 5c8c8a4115..631ead9687 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiProfile.java @@ -70,6 +70,3 @@ public static FapiProfile fromValue(FapiProfileEnum fapiProfileEnum) { return fromValue(fapiProfileEnum.value()); } } - - - diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java index 37afde5dc3..98a293657a 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java @@ -112,6 +112,7 @@ import org.wso2.carbon.identity.fraud.detection.core.service.FraudDetectionConfigsService; import org.wso2.carbon.identity.oauth.dcr.DCRConfigurationMgtService; import org.wso2.carbon.identity.oauth.dcr.exception.DCRMException; +import org.wso2.carbon.identity.oauth2.config.exceptions.OAuth2OIDCConfigOrgUsageScopeMgtClientException; import org.wso2.carbon.identity.oauth2.config.exceptions.OAuth2OIDCConfigOrgUsageScopeMgtException; import org.wso2.carbon.identity.oauth2.config.models.IssuerUsageScopeConfig; import org.wso2.carbon.identity.oauth2.config.models.UsageScope; @@ -192,7 +193,8 @@ public ServerConfigManagementService(ApplicationManagementService applicationMan FraudDetectionConfigsService fraudDetectionConfigsService, OAuth2OIDCConfigOrgUsageScopeMgtService oauth2OIDCConfigOrgUsageScopeMgtService, - CompatibilitySettingsService identityCompatibilitySettingsService) { + CompatibilitySettingsService identityCompatibilitySettingsService, + FapiConfigMgtService fapiConfigMgtService) { this.applicationManagementService = applicationManagementService; this.idpManager = idpManager; @@ -2466,6 +2468,10 @@ public UsageScopePayload updateIssuerUsageScopeConfig(UsageScopePatch usageScope updateIssuerUsageScopeConfig(tenantDomain, issuerUsageScopeConfig); return buildIssuerUsageScopeConfig(updateIssuerUsageScopeConfig, tenantDomain); } catch (OAuth2OIDCConfigOrgUsageScopeMgtException | OrganizationManagementException e) { + if (e instanceof OAuth2OIDCConfigOrgUsageScopeMgtClientException) { + throw handleException(Response.Status.BAD_REQUEST, + Constants.ErrorMessage.ERROR_CODE_CLIENT_ERROR_ISSUER_USAGE_SCOPE_UPDATE, e.getMessage()); + } throw handleException(Response.Status.INTERNAL_SERVER_ERROR, Constants.ErrorMessage.ERROR_CODE_ERROR_ISSUER_USAGE_SCOPE_UPDATE, e.getMessage()); } From 76198be18473105471c55571ae1b6d11643357b7 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Wed, 10 Jun 2026 12:49:40 +0530 Subject: [PATCH 4/6] feat(fapi2): Resolve PR comments --- .../v1/core/ServerApplicationManagementService.java | 13 ++++++++++--- .../src/main/resources/applications.yaml | 5 +++-- .../identity/api/server/configs/v1/ConfigsApi.java | 8 ++++---- .../api/server/configs/v1/ConfigsApiService.java | 2 +- .../api/server/configs/v1/model/FapiConfig.java | 2 +- .../v1/core/ServerConfigManagementService.java | 6 ++---- .../configs/v1/impl/ConfigsApiServiceImpl.java | 2 +- .../src/main/resources/configs.yaml | 13 +++++++------ 8 files changed, 29 insertions(+), 22 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java index 618fb9cc2b..7c88e57870 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java @@ -2239,14 +2239,21 @@ private String buildFormattedDescription(String description, String... formatDat */ private void validateFapiProfile(OpenIDConnectConfiguration oidcConfig) { - // Validate — only needed when a profile is present. - if (oidcConfig.getFapiProfile() == null) { + // Only validate when the application is marked as FAPI and a specific profile is provided. + // If isFAPIApplication is false the profile field is ignored in storage, so validation would + // produce a misleading error for a field that has no effect. + if (!Boolean.TRUE.equals(oidcConfig.getIsFAPIApplication()) || oidcConfig.getFapiProfile() == null) { return; } + /* + * FapiConfigMgtService is treated as optional here. Profile validation is an enhancement — + * silently skipping it avoids blocking all OIDC application updates in deployments where + * the FAPI bundle is not present. The configs API module (/configs/fapi) hard-requires + * the service at startup and fails fast if it is absent. + */ FapiConfigMgtService fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); if (fapiConfigMgtService == null) { - // FapiConfigMgtService is optional. Skip validation rather than blocking all OIDC updates. log.debug("FapiConfigMgtService is unavailable. Skipping fapiProfile validation."); return; } diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml index ef0d19b73c..c9d1ec1734 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/resources/applications.yaml @@ -3983,7 +3983,6 @@ components: If isFAPIApplication is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. allOf: - $ref: '#/components/schemas/FapiProfile' - default: FAPI1_ADVANCED example: FAPI1_ADVANCED cibaAuthenticationRequest: $ref: '#/components/schemas/CIBAAuthenticationRequestConfiguration' @@ -4317,7 +4316,9 @@ components: type: object properties: allowedFapiProfiles: - $ref: '#/components/schemas/MetadataProperty' + description: The FAPI security profiles supported by the tenant for this application. + allOf: + - $ref: '#/components/schemas/MetadataProperty' allowedSignatureAlgorithms: $ref: '#/components/schemas/MetadataProperty' allowedEncryptionAlgorithms: diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java index b5be10ff89..840c7e3130 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApi.java @@ -1051,11 +1051,11 @@ public Response getFAPIConfiguration() { } @Valid - @PATCH + @PUT @Path("/fapi") @Consumes({ "application/json" }) @Produces({ "application/json" }) - @ApiOperation(value = "Patch the tenant FAPI configuration.", notes = "Patch the tenant Financial-grade API (FAPI) configuration. Scope (Permission) required:
* internal_config_update ", response = FapiConfig.class, authorizations = { + @ApiOperation(value = "Update the tenant FAPI configuration.", notes = "Update the tenant Financial-grade API (FAPI) configuration. Scope (Permission) required:
* internal_config_update ", response = FapiConfig.class, authorizations = { @Authorization(value = "BasicAuth"), @Authorization(value = "OAuth2", scopes = { @@ -1069,8 +1069,8 @@ public Response getFAPIConfiguration() { @ApiResponse(code = 404, message = "Not Found", response = Error.class), @ApiResponse(code = 500, message = "Server Error", response = Error.class) }) - public Response patchFAPIConfiguration(@ApiParam(value = "" ,required=true) @Valid FapiConfig fapiConfig) { + public Response updateFAPIConfiguration(@ApiParam(value = "" ,required=true) @Valid FapiConfig fapiConfig) { - return delegate.patchFAPIConfiguration(fapiConfig ); + return delegate.updateFAPIConfiguration(fapiConfig ); } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java index 65d4b149b5..203907d311 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/ConfigsApiService.java @@ -93,7 +93,7 @@ public interface ConfigsApiService { public Response patchDCRConfiguration(List patch); - public Response patchFAPIConfiguration(FapiConfig fapiConfig); + public Response updateFAPIConfiguration(FapiConfig fapiConfig); public Response restoreServerRemoteLoggingConfiguration(String logType); diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java index 002b913ed4..4bae0cd024 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/gen/java/org/wso2/carbon/identity/api/server/configs/v1/model/FapiConfig.java @@ -130,7 +130,7 @@ private String toIndentedString(java.lang.Object o) { if (o == null) { return "null"; } - return o.toString().replace("\n", "\n"); + return o.toString().replace("\n", "\n "); } } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java index 98a293657a..407b4c8982 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java @@ -535,9 +535,7 @@ public FapiConfig getFAPIConfiguration() { String tenantDomain = ContextLoader.getTenantDomainFromContext(); try { - org.wso2.carbon.identity.oauth2.fapi.models.FapiConfig fapiConfig = - fapiConfigMgtService.getFapiConfig(tenantDomain); - return FAPIConnectorUtil.toApiModel(fapiConfig); + return FAPIConnectorUtil.toApiModel(fapiConfigMgtService.getFapiConfig(tenantDomain)); } catch (FapiConfigMgtClientException e) { log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE.message(), e); throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, @@ -560,7 +558,7 @@ public FapiConfig updateFAPIConfiguration(FapiConfig fapiConfig) { String tenantDomain = ContextLoader.getTenantDomainFromContext(); try { fapiConfigMgtService.setFapiConfig(FAPIConnectorUtil.toOAuthModel(fapiConfig), tenantDomain); - return fapiConfig; + return FAPIConnectorUtil.toApiModel(fapiConfigMgtService.getFapiConfig(tenantDomain)); } catch (FapiConfigMgtClientException e) { log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE.message(), e); throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java index 446411dad3..5f8315d886 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/impl/ConfigsApiServiceImpl.java @@ -169,7 +169,7 @@ public Response patchDCRConfiguration(List dcrPatch) { } @Override - public Response patchFAPIConfiguration(final FapiConfig fapiConfig) { + public Response updateFAPIConfiguration(final FapiConfig fapiConfig) { return Response.ok().entity(configManagementService.updateFAPIConfiguration(fapiConfig)).build(); } diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml index 9fe7c40898..64bbd60b09 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/resources/configs.yaml @@ -1408,7 +1408,9 @@ paths: - FAPI Configurations summary: Retrieve the tenant FAPI configuration. operationId: getFAPIConfiguration - description: Retrieve the tenant Financial-grade API (FAPI) configuration. + description: | + Retrieve the tenant Financial-grade API (FAPI) configuration. + Scope (Permission) required: `internal_config_view` responses: '200': description: Successful Response @@ -1438,13 +1440,13 @@ paths: application/json: schema: $ref: '#/components/schemas/Error' - patch: + put: tags: - FAPI Configurations - summary: Patch the tenant FAPI configuration. - operationId: patchFAPIConfiguration + summary: Update the tenant FAPI configuration. + operationId: updateFAPIConfiguration description: | - Patch the tenant Financial-grade API (FAPI) configuration. + Update the tenant Financial-grade API (FAPI) configuration. Scope (Permission) required:
* internal_config_update requestBody: @@ -1970,7 +1972,6 @@ components: If enableFapiEnforcement is true and this property is omitted, `FAPI1_ADVANCED` will be applied by default. allOf: - $ref: '#/components/schemas/FapiProfile' - default: FAPI1_ADVANCED example: FAPI1_ADVANCED mandateSSA: type: boolean From f584a37d70dd01c0bce04b0e2109702d5498ce51 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Wed, 10 Jun 2026 14:29:39 +0530 Subject: [PATCH 5/6] feat(fapi2): Bump framework and oauth2 versions to latest --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index fa4371323f..e758d2d0c9 100644 --- a/pom.xml +++ b/pom.xml @@ -1109,7 +1109,7 @@ 1.4 1.2.4 1.11.103 - 7.11.112 + 7.11.115 3.0.5 4.9.8.2 4.9.8 @@ -1118,7 +1118,7 @@ **/gen/**/* 1.12.4 5.10.1 - 7.5.46 + 7.5.49 5.11.51 1.1.19 1.9.4 From 7c66b39cfbb3885e183b7dc2a8db7c2ab4a72e68 Mon Sep 17 00:00:00 2001 From: vimukthiRajapaksha Date: Fri, 12 Jun 2026 13:56:18 +0530 Subject: [PATCH 6/6] feat(fapi2): Resolve PR comments --- .../ServerApplicationManagementService.java | 3 ++- .../ServerApplicationMetadataService.java | 21 ++++++------------- .../oauth2/OAuthConsumerAppToApiModel.java | 9 ++++---- .../core/ServerConfigManagementService.java | 10 ++++----- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java index 7c88e57870..c1157d6caa 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationManagementService.java @@ -2242,7 +2242,8 @@ private void validateFapiProfile(OpenIDConnectConfiguration oidcConfig) { // Only validate when the application is marked as FAPI and a specific profile is provided. // If isFAPIApplication is false the profile field is ignored in storage, so validation would // produce a misleading error for a field that has no effect. - if (!Boolean.TRUE.equals(oidcConfig.getIsFAPIApplication()) || oidcConfig.getFapiProfile() == null) { + if (oidcConfig == null || !Boolean.TRUE.equals(oidcConfig.getIsFAPIApplication()) + || oidcConfig.getFapiProfile() == null) { return; } diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java index 7347f27e57..9e0606e84b 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/ServerApplicationMetadataService.java @@ -104,12 +104,9 @@ public ServerApplicationMetadataService(ApplicationManagementService application OAuthAdminServiceImpl oAuthAdminService, STSAdminServiceInterface sTSAdminServiceInterface) { - this.applicationManagementService = applicationManagementService; - this.samlSSOConfigService = samlSSOConfigService; - this.oAuthAdminService = oAuthAdminService; - this.sTSAdminServiceInterface = sTSAdminServiceInterface; - this.cibaAuthService = ApplicationManagementServiceHolder.getCibaAuthService(); - this.fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); + this(applicationManagementService, samlSSOConfigService, oAuthAdminService, sTSAdminServiceInterface, + ApplicationManagementServiceHolder.getCibaAuthService(), + ApplicationManagementServiceHolder.getFapiConfigMgtService()); } @Deprecated @@ -119,12 +116,8 @@ public ServerApplicationMetadataService(ApplicationManagementService application STSAdminServiceInterface sTSAdminServiceInterface, CibaAuthServiceImpl cibaAuthService) { - this.applicationManagementService = applicationManagementService; - this.samlSSOConfigService = samlSSOConfigService; - this.oAuthAdminService = oAuthAdminService; - this.sTSAdminServiceInterface = sTSAdminServiceInterface; - this.cibaAuthService = cibaAuthService; - this.fapiConfigMgtService = ApplicationManagementServiceHolder.getFapiConfigMgtService(); + this(applicationManagementService, samlSSOConfigService, oAuthAdminService, sTSAdminServiceInterface, + cibaAuthService, ApplicationManagementServiceHolder.getFapiConfigMgtService()); } public ServerApplicationMetadataService(ApplicationManagementService applicationManagementService, @@ -563,9 +556,7 @@ private List getAllowedIssuersForOrganization() { private List getAllowedFapiProfiles() { if (fapiConfigMgtService == null) { - if (LOG.isDebugEnabled()) { - LOG.debug("FapiConfigMgtService is not available. Returning empty FAPI profiles list."); - } + LOG.debug("FapiConfigMgtService is not available. Returning empty FAPI profiles list."); return Collections.emptyList(); } String tenantDomain = ContextLoader.getTenantDomainFromContext(); diff --git a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java index 78414eac7e..43e78301a4 100644 --- a/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java +++ b/components/org.wso2.carbon.identity.api.server.application.management/org.wso2.carbon.identity.api.server.application.management.v1/src/main/java/org/wso2/carbon/identity/api/server/application/management/v1/core/functions/application/inbound/oauth2/OAuthConsumerAppToApiModel.java @@ -51,7 +51,7 @@ */ public class OAuthConsumerAppToApiModel implements Function { - private static final Log log = LogFactory.getLog(OAuthConsumerAppToApiModel.class); + private static final Log LOG = LogFactory.getLog(OAuthConsumerAppToApiModel.class); @Override public OpenIDConnectConfiguration apply(OAuthConsumerAppDTO oauthAppDTO) { @@ -282,7 +282,6 @@ private AllowedIssuer buildIssuerOrganizationConfiguration(OAuthConsumerAppDTO o /** * Converts the stored FAPI profile string from the DTO into the API model enum. * Returns null if no profile is stored, which will omit the field from the response. - * Logs a warning if an unrecognised value is found (data integrity issue, not an API error). * * @param oauthAppDTO the DTO containing the stored FAPI profile string. * @return the {@link FapiProfile} enum constant, or null if not set. @@ -290,14 +289,14 @@ private AllowedIssuer buildIssuerOrganizationConfiguration(OAuthConsumerAppDTO o private FapiProfile buildFapiProfileConfiguration(OAuthConsumerAppDTO oauthAppDTO) { String fapiProfileValue = oauthAppDTO.getFapiProfile(); - if (fapiProfileValue == null) { + if (StringUtils.isBlank(fapiProfileValue)) { return null; } try { return FapiProfile.fromValue(fapiProfileValue); } catch (IllegalArgumentException e) { - if (log.isDebugEnabled()) { - log.debug(String.format("Unrecognised fapiProfile value stored for application '%s': %s", + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Unrecognised fapiProfile value stored for application '%s': %s", oauthAppDTO.getApplicationName(), fapiProfileValue), e); } return null; diff --git a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java index 407b4c8982..5fe5f6c3be 100644 --- a/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java +++ b/components/org.wso2.carbon.identity.api.server.configs/org.wso2.carbon.identity.api.server.configs.v1/src/main/java/org/wso2/carbon/identity/api/server/configs/v1/core/ServerConfigManagementService.java @@ -537,11 +537,9 @@ public FapiConfig getFAPIConfiguration() { try { return FAPIConnectorUtil.toApiModel(fapiConfigMgtService.getFapiConfig(tenantDomain)); } catch (FapiConfigMgtClientException e) { - log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE.message(), e); throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE, tenantDomain)); } catch (FapiConfigMgtException e) { - log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE.message(), e); throw new APIError(Response.Status.INTERNAL_SERVER_ERROR, this.getFapiConfigErrorResponse(e, Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_RETRIEVE, tenantDomain)); } @@ -555,16 +553,18 @@ public FapiConfig getFAPIConfiguration() { */ public FapiConfig updateFAPIConfiguration(FapiConfig fapiConfig) { - String tenantDomain = ContextLoader.getTenantDomainFromContext(); + if (fapiConfig == null) { + throw handleException(Response.Status.BAD_REQUEST, Constants.ErrorMessage.ERROR_CODE_INVALID_INPUT, + "FAPI configuration is required in the request body."); + } + final String tenantDomain = ContextLoader.getTenantDomainFromContext(); try { fapiConfigMgtService.setFapiConfig(FAPIConnectorUtil.toOAuthModel(fapiConfig), tenantDomain); return FAPIConnectorUtil.toApiModel(fapiConfigMgtService.getFapiConfig(tenantDomain)); } catch (FapiConfigMgtClientException e) { - log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE.message(), e); throw new APIError(Response.Status.BAD_REQUEST, this.getFapiConfigErrorResponse(e, Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE, tenantDomain)); } catch (FapiConfigMgtException e) { - log.error(Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE.message(), e); throw new APIError(Response.Status.INTERNAL_SERVER_ERROR, this.getFapiConfigErrorResponse(e, Constants.ErrorMessage.ERROR_CODE_FAPI_CONFIG_UPDATE, tenantDomain)); }