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 0269340477..aa0ead9b6f 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 @@ -79,7 +79,9 @@ private ApplicationManagementConstants() { public static final String NON_EXISTING_USER_CODE = "30007 - "; public static final String APPLICATION_BASED_OUTBOUND_PROVISIONING_ENABLED = "OutboundProvisioning.enableApplicationBasedOutboundProvisioning"; - + public static final String CODE_TOKEN = "code token"; + public static final String CODE_IDTOKEN = "code id_token"; + public static final String CODE_IDTOKEN_TOKEN = "code id_token token"; /** * Enums for error messages. @@ -160,6 +162,13 @@ public enum ErrorMessage { BLOCK_RENAME_APP_NAME_TO_RESERVED_APP_NAME("60516", "Renaming application name to a system reserved name is blocked", "The application name %s is marked as systems reserved application name."), + Hybrid_FLOW_RESPONSE_TYPE_NOT_FOUND("60517", + "Hybrid flow response type not found.", + "Hybrid flow response type cannot be found for the application"), + Hybrid_FLOW_RESPONSE_TYPE_INCORRECT("60518", + "Hybrid flow response type is incorrect.", + "The response type for the hybrid flow should be either 'code token' or 'code id_token' or " + + "'code id_token token'"), // Server Errors. ERROR_RETRIEVING_SAML_METADATA("65001", 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/HybridFlowConfiguration.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/HybridFlowConfiguration.java new file mode 100644 index 0000000000..feb38dd6e5 --- /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/HybridFlowConfiguration.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024, 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 com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonCreator; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class HybridFlowConfiguration { + + private Boolean enable; + private String responseType; + + /** + **/ + public HybridFlowConfiguration enable(Boolean enable) { + + this.enable = enable; + return this; + } + + @ApiModelProperty(example = "true", value = "") + @JsonProperty("enable") + @Valid + public Boolean getEnable() { + return enable; + } + public void setEnable(Boolean enable) { + this.enable = enable; + } + + /** + **/ + public HybridFlowConfiguration responseType(String responseType) { + + this.responseType = responseType; + return this; + } + + @ApiModelProperty(example = "code id_token", value = "") + @JsonProperty("responseType") + @Valid + public String getResponseType() { + return responseType; + } + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HybridFlowConfiguration hybridFlowConfiguration = (HybridFlowConfiguration) o; + return Objects.equals(this.enable, hybridFlowConfiguration.enable) && + Objects.equals(this.responseType, hybridFlowConfiguration.responseType); + } + + @Override + public int hashCode() { + return Objects.hash(enable, responseType); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class HybridFlowConfiguration {\n"); + + sb.append(" enable: ").append(toIndentedString(enable)).append("\n"); + sb.append(" responseType: ").append(toIndentedString(responseType)).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.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 2c61ebb129..a851bfeddd 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 @@ -83,6 +83,7 @@ public static StateEnum fromValue(String value) { private Boolean publicClient = false; private OAuth2PKCEConfiguration pkce; + private HybridFlowConfiguration hybridFlow; private AccessTokenConfiguration accessToken; private RefreshTokenConfiguration refreshToken; private IdTokenConfiguration idToken; @@ -266,6 +267,24 @@ public void setPkce(OAuth2PKCEConfiguration pkce) { this.pkce = pkce; } + /** + **/ + public OpenIDConnectConfiguration hybridFlow(HybridFlowConfiguration hybridFlow) { + + this.hybridFlow = hybridFlow; + return this; + } + + @ApiModelProperty(value = "") + @JsonProperty("hybridFlow") + @Valid + public HybridFlowConfiguration getHybridFlow() { + return hybridFlow; + } + public void setHybridFlow(HybridFlowConfiguration hybridFlow) { + this.hybridFlow = hybridFlow; + } + /** **/ public OpenIDConnectConfiguration accessToken(AccessTokenConfiguration accessToken) { @@ -509,6 +528,7 @@ public boolean equals(java.lang.Object o) { Objects.equals(this.allowedOrigins, openIDConnectConfiguration.allowedOrigins) && Objects.equals(this.publicClient, openIDConnectConfiguration.publicClient) && Objects.equals(this.pkce, openIDConnectConfiguration.pkce) && + Objects.equals(this.hybridFlow, openIDConnectConfiguration.hybridFlow) && Objects.equals(this.accessToken, openIDConnectConfiguration.accessToken) && Objects.equals(this.refreshToken, openIDConnectConfiguration.refreshToken) && Objects.equals(this.idToken, openIDConnectConfiguration.idToken) && @@ -525,7 +545,7 @@ public boolean equals(java.lang.Object o) { @Override public int hashCode() { - return Objects.hash(clientId, clientSecret, state, grantTypes, callbackURLs, allowedOrigins, publicClient, pkce, accessToken, refreshToken, idToken, logout, validateRequestObjectSignature, scopeValidators, clientAuthentication, requestObject, pushAuthorizationRequest, subject, isFAPIApplication, fapiMetadata); + return Objects.hash(clientId, clientSecret, state, grantTypes, callbackURLs, allowedOrigins, publicClient, pkce, hybridFlow, accessToken, refreshToken, idToken, logout, validateRequestObjectSignature, scopeValidators, clientAuthentication, requestObject, pushAuthorizationRequest, subject, isFAPIApplication, fapiMetadata); } @Override @@ -542,6 +562,7 @@ public String toString() { sb.append(" allowedOrigins: ").append(toIndentedString(allowedOrigins)).append("\n"); sb.append(" publicClient: ").append(toIndentedString(publicClient)).append("\n"); sb.append(" pkce: ").append(toIndentedString(pkce)).append("\n"); + sb.append(" hybridFlow: ").append(toIndentedString(hybridFlow)).append("\n"); sb.append(" accessToken: ").append(toIndentedString(accessToken)).append("\n"); sb.append(" refreshToken: ").append(toIndentedString(refreshToken)).append("\n"); sb.append(" idToken: ").append(toIndentedString(idToken)).append("\n"); 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 f9eeac0f8d..cb6b6c771a 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 @@ -16,9 +16,12 @@ package org.wso2.carbon.identity.api.server.application.management.v1.core.functions.application.inbound.oauth2; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.api.server.application.management.common.ApplicationManagementConstants; import org.wso2.carbon.identity.api.server.application.management.v1.AccessTokenConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.ClientAuthenticationConfiguration; +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.OAuth2PKCEConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.OIDCLogoutConfiguration; @@ -28,12 +31,16 @@ import org.wso2.carbon.identity.api.server.application.management.v1.RequestObjectConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.SubjectConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils; +import org.wso2.carbon.identity.api.server.common.error.APIError; +import org.wso2.carbon.identity.api.server.common.error.ErrorResponse; import org.wso2.carbon.identity.oauth.common.OAuthConstants; import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO; import java.util.List; import java.util.Optional; +import javax.ws.rs.core.Response; + import static org.wso2.carbon.identity.api.server.application.management.v1.core.functions.Utils.setIfNotNull; /** @@ -63,6 +70,7 @@ public OAuthConsumerAppDTO apply(String appName, OpenIDConnectConfiguration oidc updateAllowedOrigins(consumerAppDTO, oidcModel.getAllowedOrigins()); updatePkceConfigurations(consumerAppDTO, oidcModel.getPkce()); + updateHybridFlowConfigurations(consumerAppDTO, oidcModel.getHybridFlow()); updateAccessTokenConfiguration(consumerAppDTO, oidcModel.getAccessToken()); updateRefreshTokenConfiguration(consumerAppDTO, oidcModel.getRefreshToken()); updateIdTokenConfiguration(consumerAppDTO, oidcModel.getIdToken()); @@ -168,6 +176,47 @@ private void updatePkceConfigurations(OAuthConsumerAppDTO consumerAppDTO, OAuth2 } } + private void updateHybridFlowConfigurations(OAuthConsumerAppDTO consumerAppDTO, + HybridFlowConfiguration hybridFlow) { + + if (hybridFlow != null) { + + consumerAppDTO.setHybridFlowEnabled(hybridFlow.getEnable()); + if (hybridFlow.getEnable()) { + validateHybridFlowResponseType(consumerAppDTO, hybridFlow); + consumerAppDTO.setHybridFlowResponseType(hybridFlow.getResponseType()); + } + } + } + + private void validateHybridFlowResponseType(OAuthConsumerAppDTO consumerAppDTO, + HybridFlowConfiguration hybridFlowResponseType) { + + String[] allowedResponseTypes = {ApplicationManagementConstants.CODE_TOKEN, + ApplicationManagementConstants.CODE_IDTOKEN, + ApplicationManagementConstants.CODE_IDTOKEN_TOKEN}; + + if (StringUtils.isBlank(hybridFlowResponseType.getResponseType())) { + throw new APIError(Response.Status.BAD_REQUEST, + new ErrorResponse.Builder().withCode(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_NOT_FOUND.getCode()) + .withMessage(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_NOT_FOUND.getMessage()) + .withDescription(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_NOT_FOUND.getDescription()).build()); + } + + if (!ArrayUtils.contains(allowedResponseTypes, hybridFlowResponseType.getResponseType())) { + throw new APIError(Response.Status.BAD_REQUEST, + new ErrorResponse.Builder().withCode(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_INCORRECT.getCode()) + .withMessage(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_INCORRECT.getMessage()) + .withDescription(ApplicationManagementConstants.ErrorMessage + .Hybrid_FLOW_RESPONSE_TYPE_INCORRECT.getDescription()).build()); + } + } + private String[] getScopeValidators(OpenIDConnectConfiguration oidcModel) { return Optional.ofNullable(oidcModel.getScopeValidators()) 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 7567c27aee..f801f421ad 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,6 +18,7 @@ import org.apache.commons.lang.StringUtils; import org.wso2.carbon.identity.api.server.application.management.v1.AccessTokenConfiguration; import org.wso2.carbon.identity.api.server.application.management.v1.ClientAuthenticationConfiguration; +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; import org.wso2.carbon.identity.api.server.application.management.v1.OAuth2PKCEConfiguration; @@ -53,6 +54,7 @@ public OpenIDConnectConfiguration apply(OAuthConsumerAppDTO oauthAppDTO) { .callbackURLs(getCallbackUrls(oauthAppDTO)) .allowedOrigins(getAllowedOrigins(oauthAppDTO)) .pkce(buildPKCEConfiguration(oauthAppDTO)) + .hybridFlow(buildHybridFlowConfiguration(oauthAppDTO)) .accessToken(buildTokenConfiguration(oauthAppDTO)) .refreshToken(buildRefreshTokenConfiguration(oauthAppDTO)) .idToken(buildIdTokenConfiguration(oauthAppDTO)) @@ -86,6 +88,13 @@ private OAuth2PKCEConfiguration buildPKCEConfiguration(OAuthConsumerAppDTO oAuth .supportPlainTransformAlgorithm(oAuthConsumerAppDTO.getPkceSupportPlain()); } + private HybridFlowConfiguration buildHybridFlowConfiguration(OAuthConsumerAppDTO oAuthConsumerAppDTO) { + + return new HybridFlowConfiguration() + .enable(oAuthConsumerAppDTO.isHybridFlowEnabled()) + .responseType(oAuthConsumerAppDTO.getHybridFlowResponseType()); + } + private AccessTokenConfiguration buildTokenConfiguration(OAuthConsumerAppDTO oAuthConsumerAppDTO) { return new AccessTokenConfiguration() 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 f032fedf30..a0383629be 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 @@ -3559,6 +3559,8 @@ components: $ref: '#/components/schemas/OAuth2PKCEConfiguration' accessToken: $ref: '#/components/schemas/AccessTokenConfiguration' + hybridFlow: + $ref: '#/components/schemas/HybridFlowConfiguration' refreshToken: $ref: '#/components/schemas/RefreshTokenConfiguration' idToken: @@ -3598,6 +3600,15 @@ components: supportPlainTransformAlgorithm: type: boolean example: true + HybridFlowConfiguration: + type: object + properties: + enable: + type: boolean + example: true + responseType: + type: string + example: code id_token AccessTokenConfiguration: type: object properties: