From 4fbf3868cde4121208d0567932a834557c4c25fd Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:18:37 +0530 Subject: [PATCH 1/7] Self-service API for consent management --- .../pom.xml | 36 + .../util/ConsentManagementServiceHolder.java | 46 ++ .../pom.xml | 166 +++++ .../identity/api/user/consent/v1/MeApi.java | 188 +++++ .../api/user/consent/v1/MeApiService.java | 51 ++ .../v1/factories/MeApiServiceFactory.java | 32 + .../v1/model/AuthorizationRequest.java | 132 ++++ .../v1/model/AuthorizationResponse.java | 176 +++++ .../v1/model/ConsentCreateResponse.java | 198 ++++++ .../user/consent/v1/model/ConsentInput.java | 267 +++++++ .../consent/v1/model/ConsentPurposeInput.java | 134 ++++ .../v1/model/ConsentPurposeResponse.java | 255 +++++++ .../consent/v1/model/ConsentResponse.java | 364 ++++++++++ .../user/consent/v1/model/ConsentSummary.java | 198 ++++++ .../v1/model/ConsentValidationResponse.java | 154 ++++ .../consent/v1/model/ConsentedElement.java | 121 ++++ .../api/user/consent/v1/model/ElementRef.java | 101 +++ .../api/user/consent/v1/model/Error.java | 165 +++++ .../user/consent/v1/model/KeyValuePair.java | 119 ++++ .../consent/v1/model/PIICategorySummary.java | 121 ++++ .../consent/v1/impl/MeApiServiceImpl.java | 92 +++ .../v1/impl/core/UserConsentService.java | 474 +++++++++++++ .../factories/UserConsentServiceFactory.java | 49 ++ .../src/main/resources/consent.yaml | 661 ++++++++++++++++++ .../pom.xml | 37 + pom.xml | 8 + 26 files changed, 4345 insertions(+) create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/pom.xml create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/src/main/java/org/wso2/carbon/identity/api/user/consent/common/util/ConsentManagementServiceHolder.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/pom.xml create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApiService.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/factories/MeApiServiceFactory.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationRequest.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationResponse.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentInput.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeInput.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeResponse.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentResponse.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentedElement.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ElementRef.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/Error.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/factories/UserConsentServiceFactory.java create mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml create mode 100644 components/org.wso2.carbon.identity.api.user.consent/pom.xml diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/pom.xml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/pom.xml new file mode 100644 index 00000000..565e97eb --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/pom.xml @@ -0,0 +1,36 @@ + + + + + + org.wso2.carbon.identity.user.api + org.wso2.carbon.identity.api.user.consent + 1.5.12-SNAPSHOT + + 4.0.0 + + org.wso2.carbon.identity.api.user.consent.common + + + + org.wso2.carbon.consent.mgt + org.wso2.carbon.consent.mgt.core + + + diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/src/main/java/org/wso2/carbon/identity/api/user/consent/common/util/ConsentManagementServiceHolder.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/src/main/java/org/wso2/carbon/identity/api/user/consent/common/util/ConsentManagementServiceHolder.java new file mode 100644 index 00000000..49295efd --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.common/src/main/java/org/wso2/carbon/identity/api/user/consent/common/util/ConsentManagementServiceHolder.java @@ -0,0 +1,46 @@ +/* + * 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.user.consent.common.util; + +import org.wso2.carbon.consent.mgt.core.PrivilegedConsentManager; +import org.wso2.carbon.context.PrivilegedCarbonContext; + +/** + * Service holder class for consent management OSGi services. + */ +public class ConsentManagementServiceHolder { + + private ConsentManagementServiceHolder() {} + + private static class PrivilegedConsentManagerHolder { + + static final PrivilegedConsentManager SERVICE = (PrivilegedConsentManager) PrivilegedCarbonContext + .getThreadLocalCarbonContext().getOSGiService(PrivilegedConsentManager.class, null); + } + + /** + * Returns the PrivilegedConsentManager OSGi service. + * + * @return PrivilegedConsentManager + */ + public static PrivilegedConsentManager getPrivilegedConsentManager() { + + return PrivilegedConsentManagerHolder.SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/pom.xml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/pom.xml new file mode 100644 index 00000000..21662195 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/pom.xml @@ -0,0 +1,166 @@ + + + + + + + org.wso2.carbon.identity.user.api + org.wso2.carbon.identity.api.user.consent + ../pom.xml + 1.5.12-SNAPSHOT + + 4.0.0 + org.wso2.carbon.identity.rest.api.user.consent.v1 + jar + WSO2 Identity Server - User Consent Management Rest API + WSO2 Identity Server - User Self-Service Consent Management Rest API + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + src/gen/java + + + + + + + + + + + org.apache.cxf + cxf-rt-frontend-jaxrs + provided + + + org.apache.cxf + cxf-rt-rs-service-description + provided + + + javax.ws.rs + javax.ws.rs-api + provided + + + io.swagger + swagger-jaxrs + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + javax.ws.rs + jsr311-api + + + com.google.guava + guava + + + + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + provided + + + org.wso2.carbon.identity.user.api + org.wso2.carbon.identity.api.user.common + provided + ${project.version} + + + org.wso2.carbon.identity.user.api + org.wso2.carbon.identity.api.user.consent.common + provided + ${project.version} + + + org.wso2.carbon.consent.mgt + org.wso2.carbon.consent.mgt.core + provided + + + org.testng + testng + test + + + diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java new file mode 100644 index 00000000..f1ccf6a5 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java @@ -0,0 +1,188 @@ +/* + * 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.user.consent.v1; + +import org.wso2.carbon.identity.api.user.consent.v1.factories.MeApiServiceFactory; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationRequest; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentCreateResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentInput; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentSummary; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentValidationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.Error; + +import javax.validation.Valid; +import javax.ws.rs.*; +import javax.ws.rs.core.Response; +import io.swagger.annotations.*; + +import javax.validation.constraints.*; + +@Path("/me") +@Api(description = "The me API") + +public class MeApi { + + private final MeApiService delegate; + + public MeApi() { + + this.delegate = MeApiServiceFactory.getMeApi(); + } + + @Valid + @POST + @Path("/consents") + @Consumes({ "application/json" }) + @Produces({ "application/json" }) + @ApiOperation(value = "Create a consent record", notes = "Record consent for specified purposes and elements. The authenticated user creates and gives consent simultaneously. The consent is immediately recorded as `ACTIVE` or `REJECTED` based on the provided state.
Permission required:
* None
Scope required:
* internal_login ", response = ConsentCreateResponse.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me", }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Consent created successfully.", response = ConsentCreateResponse.class), + @ApiResponse(code = 400, message = "Invalid input request", response = Error.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 409, message = "Conflict", response = Error.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response addConsentOfLoggedInUser(@ApiParam(value = "Consent to be created." ,required=true) @Valid ConsentInput consent) { + + return delegate.addConsentOfLoggedInUser(consent ); + } + + @Valid + @POST + @Path("/consents/{consent-id}/authorize") + @Consumes({ "application/json" }) + @Produces({ "application/json" }) + @ApiOperation(value = "Authorize a consent", notes = "Authorizes a PENDING consent. The authenticated user must be in the consent's authorization list, returns 403 otherwise. When all required users have approved, the consent transitions to ACTIVE state. If any user rejects, the consent transitions to REJECTED state.
Permission required:
* None
Scope required:
* internal_login ", response = AuthorizationResponse.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Authorization recorded successfully.", response = AuthorizationResponse.class), + @ApiResponse(code = 400, message = "Invalid input request", response = Error.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Resource Forbidden", response = Error.class), + @ApiResponse(code = 404, message = "Resource Not Found", response = Error.class), + @ApiResponse(code = 409, message = "Conflict", response = Error.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response authorizeConsentOfLoggedInUser(@ApiParam(value = "UUID of the consent receipt.",required=true) @PathParam("consent-id") String consentId, @ApiParam(value = "Authorization decision." ,required=true) @Valid AuthorizationRequest authorization) { + + return delegate.authorizeConsentOfLoggedInUser(consentId, authorization ); + } + + @Valid + @GET + @Path("/consents/{consent-id}") + + @Produces({ "application/json" }) + @ApiOperation(value = "Get a consent record", notes = "Retrieve a specific consent record by consent ID. Only the consent subject may retrieve the record. Returns 403 if the authenticated user is not the consent subject.
Permission required:
* None
Scope required:
* internal_login ", response = ConsentResponse.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Consent retrieved successfully.", response = ConsentResponse.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Resource Forbidden", response = Error.class), + @ApiResponse(code = 404, message = "Resource Not Found", response = Error.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response getConsentOfLoggedInUser(@ApiParam(value = "UUID of the consent receipt.",required=true) @PathParam("consent-id") String consentId) { + + return delegate.getConsentOfLoggedInUser(consentId ); + } + + @Valid + @GET + @Path("/consents") + + @Produces({ "application/json" }) + @ApiOperation(value = "List consent records", notes = "Retrieve consent records with optional filtering. Returns only the authenticated user's own consents.
Permission required:
* None
Scope required:
* internal_login ", response = ConsentSummary.class, responseContainer = "List", authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Consents retrieved successfully.", response = ConsentSummary.class, responseContainer = "List"), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response listConsentsOfLoggedInUser( @Valid@ApiParam(value = "Filter consents by service identifier.") @QueryParam("serviceId") String serviceId, @Valid@ApiParam(value = "Filter consents by state.", allowableValues="PENDING, ACTIVE, REJECTED, REVOKED, EXPIRED") @QueryParam("state") String state, @Valid@ApiParam(value = "Filter consents by purpose UUID.") @QueryParam("purposeId") String purposeId, @Valid@ApiParam(value = "Filter consents by specific purpose version UUID.") @QueryParam("purposeVersionId") String purposeVersionId, @Valid@ApiParam(value = "Filter consents by custom properties using dot notation `properties.`. Supports 'sw' (starts with), 'co' (contains), 'ew' (ends with), and 'eq' (equals) operations. Combine multiple conditions with 'and', 'or' logical operators. Examples: filter=properties.region eq EU ") @QueryParam("filter") String filter, @Valid @Min(1)@ApiParam(value = "Maximum number of records to return. Default is 10.", defaultValue="10") @DefaultValue("10") @QueryParam("limit") Integer limit, @Valid@ApiParam(value = "Cursor for forward pagination. Pass the base64-encoded UUID of the last item received from the previous page to retrieve the next page of results. ") @QueryParam("after") String after, @Valid@ApiParam(value = "Cursor for backward pagination. Pass the base64-encoded UUID of the first item received from the current page to retrieve the previous page of results. ") @QueryParam("before") String before) { + + return delegate.listConsentsOfLoggedInUser(serviceId, state, purposeId, purposeVersionId, filter, limit, after, before ); + } + + @Valid + @POST + @Path("/consents/{consent-id}/revoke") + + @Produces({ "*/*" }) + @ApiOperation(value = "Revoke a consent", notes = "Revokes the consent. The authenticated user must be the consent subject, returns 403 otherwise. Idempotent — if the consent is already revoked, returns 200 with no error.
Permission required:
* None
Scope required:
* internal_login ", response = Void.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me", }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", response = Void.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Resource Forbidden", response = Error.class), + @ApiResponse(code = 404, message = "Resource Not Found", response = Error.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response revokeConsentOfLoggedInUser(@ApiParam(value = "UUID of the consent receipt.",required=true) @PathParam("consent-id") String consentId) { + + return delegate.revokeConsentOfLoggedInUser(consentId ); + } + + @Valid + @GET + @Path("/consents/{consent-id}/validate") + + @Produces({ "application/json" }) + @ApiOperation(value = "Get the current state of a consent object", notes = "Returns the current state of a consent record, performing a lazy expiry check. The authenticated user must be the consent subject, returns 403 otherwise.
Permission required:
* None
Scope required:
* internal_login ", response = ConsentValidationResponse.class, authorizations = { + @Authorization(value = "BasicAuth"), + @Authorization(value = "OAuth2", scopes = { + + }) + }, tags={ "me" }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "Consent status retrieved successfully.", response = ConsentValidationResponse.class), + @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), + @ApiResponse(code = 403, message = "Resource Forbidden", response = Error.class), + @ApiResponse(code = 404, message = "Resource Not Found", response = Error.class), + @ApiResponse(code = 500, message = "Internal Server Error", response = Error.class) + }) + public Response validateConsentOfLoggedInUser(@ApiParam(value = "UUID of the consent receipt.",required=true) @PathParam("consent-id") String consentId) { + + return delegate.validateConsentOfLoggedInUser(consentId ); + } + +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApiService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApiService.java new file mode 100644 index 00000000..de59f672 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApiService.java @@ -0,0 +1,51 @@ +/* + * 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.user.consent.v1; + +import org.wso2.carbon.identity.api.user.consent.v1.*; +import org.wso2.carbon.identity.api.user.consent.v1.model.*; +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.Multipart; +import java.io.InputStream; +import java.util.List; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationRequest; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentCreateResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentInput; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentSummary; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentValidationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.Error; +import javax.ws.rs.core.Response; + + +public interface MeApiService { + + public Response addConsentOfLoggedInUser(ConsentInput consent); + + public Response authorizeConsentOfLoggedInUser(String consentId, AuthorizationRequest authorization); + + public Response getConsentOfLoggedInUser(String consentId); + + public Response listConsentsOfLoggedInUser(String serviceId, String state, String purposeId, String purposeVersionId, String filter, Integer limit, String after, String before); + + public Response revokeConsentOfLoggedInUser(String consentId); + + public Response validateConsentOfLoggedInUser(String consentId); +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/factories/MeApiServiceFactory.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/factories/MeApiServiceFactory.java new file mode 100644 index 00000000..7bf6a35c --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/factories/MeApiServiceFactory.java @@ -0,0 +1,32 @@ +/* + * 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.user.consent.v1.factories; + +import org.wso2.carbon.identity.api.user.consent.v1.MeApiService; +import org.wso2.carbon.identity.api.user.consent.v1.impl.MeApiServiceImpl; + +public class MeApiServiceFactory { + + private final static MeApiService service = new MeApiServiceImpl(); + + public static MeApiService getMeApi() + { + return service; + } +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationRequest.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationRequest.java new file mode 100644 index 00000000..c43f8dc7 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationRequest.java @@ -0,0 +1,132 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class AuthorizationRequest { + + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("APPROVED") APPROVED(String.valueOf("APPROVED")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state = StateEnum.APPROVED; + + /** + * Authorization decision. + **/ + public AuthorizationRequest state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "APPROVED", value = "Authorization decision.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AuthorizationRequest authorizationRequest = (AuthorizationRequest) o; + return Objects.equals(this.state, authorizationRequest.state); + } + + @Override + public int hashCode() { + return Objects.hash(state); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class AuthorizationRequest {\n"); + + sb.append(" state: ").append(toIndentedString(state)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationResponse.java new file mode 100644 index 00000000..b40bb2db --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/AuthorizationResponse.java @@ -0,0 +1,176 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class AuthorizationResponse { + + private String userId; + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("APPROVED") APPROVED(String.valueOf("APPROVED")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state; + private Long updatedTime; + + /** + * Username of the user who performed this authorization. + **/ + public AuthorizationResponse userId(String userId) { + + this.userId = userId; + return this; + } + + @ApiModelProperty(example = "john", value = "Username of the user who performed this authorization.") + @JsonProperty("userId") + @Valid + public String getUserId() { + return userId; + } + public void setUserId(String userId) { + this.userId = userId; + } + + /** + * Current state of this authorization. + **/ + public AuthorizationResponse state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "APPROVED", value = "Current state of this authorization.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + /** + * Milliseconds since epoch when this authorization was last updated. + **/ + public AuthorizationResponse updatedTime(Long updatedTime) { + + this.updatedTime = updatedTime; + return this; + } + + @ApiModelProperty(example = "1750156200000", value = "Milliseconds since epoch when this authorization was last updated.") + @JsonProperty("updatedTime") + @Valid + public Long getUpdatedTime() { + return updatedTime; + } + public void setUpdatedTime(Long updatedTime) { + this.updatedTime = updatedTime; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + AuthorizationResponse authorizationResponse = (AuthorizationResponse) o; + return Objects.equals(this.userId, authorizationResponse.userId) && + Objects.equals(this.state, authorizationResponse.state) && + Objects.equals(this.updatedTime, authorizationResponse.updatedTime); + } + + @Override + public int hashCode() { + return Objects.hash(userId, state, updatedTime); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class AuthorizationResponse {\n"); + + sb.append(" userId: ").append(toIndentedString(userId)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" updatedTime: ").append(toIndentedString(updatedTime)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java new file mode 100644 index 00000000..d4cea1e2 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java @@ -0,0 +1,198 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentCreateResponse { + + private String id; + private String subjectId; + private String serviceId; + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state; + + /** + * Unique identifier of the created consent. + **/ + public ConsentCreateResponse id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "d75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i", value = "Unique identifier of the created consent.") + @JsonProperty("id") + @Valid + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Identifier of the user who gave consent. + **/ + public ConsentCreateResponse subjectId(String subjectId) { + + this.subjectId = subjectId; + return this; + } + + @ApiModelProperty(example = "john", value = "Identifier of the user who gave consent.") + @JsonProperty("subjectId") + @Valid + public String getSubjectId() { + return subjectId; + } + public void setSubjectId(String subjectId) { + this.subjectId = subjectId; + } + + /** + * Identifier of the service the consent was given for. + **/ + public ConsentCreateResponse serviceId(String serviceId) { + + this.serviceId = serviceId; + return this; + } + + @ApiModelProperty(example = "sampleApp", value = "Identifier of the service the consent was given for.") + @JsonProperty("serviceId") + @Valid + public String getServiceId() { + return serviceId; + } + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + /** + * Initial state of the consent. + **/ + public ConsentCreateResponse state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "ACTIVE", value = "Initial state of the consent.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentCreateResponse consentCreateResponse = (ConsentCreateResponse) o; + return Objects.equals(this.id, consentCreateResponse.id) && + Objects.equals(this.subjectId, consentCreateResponse.subjectId) && + Objects.equals(this.serviceId, consentCreateResponse.serviceId) && + Objects.equals(this.state, consentCreateResponse.state); + } + + @Override + public int hashCode() { + return Objects.hash(id, subjectId, serviceId, state); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentCreateResponse {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" subjectId: ").append(toIndentedString(subjectId)).append("\n"); + sb.append(" serviceId: ").append(toIndentedString(serviceId)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentInput.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentInput.java new file mode 100644 index 00000000..fc581dad --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentInput.java @@ -0,0 +1,267 @@ +/* + * 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.user.consent.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.HashMap; +import java.util.List; +import java.util.Map; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentPurposeInput; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentInput { + + private String serviceId; + private String language; + private List purposes = new ArrayList<>(); + + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state = StateEnum.ACTIVE; + private Long expiryTime; + private Map properties = null; + + + /** + * Identifier of the service the consent is given for. + **/ + public ConsentInput serviceId(String serviceId) { + + this.serviceId = serviceId; + return this; + } + + @ApiModelProperty(example = "sampleApp", required = true, value = "Identifier of the service the consent is given for.") + @JsonProperty("serviceId") + @Valid + @NotNull(message = "Property serviceId cannot be null.") + @Size(min=1,max=255) + public String getServiceId() { + return serviceId; + } + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + /** + * Language code for the consent. + **/ + public ConsentInput language(String language) { + + this.language = language; + return this; + } + + @ApiModelProperty(example = "en", value = "Language code for the consent.") + @JsonProperty("language") + @Valid @Size(min=1,max=20) + public String getLanguage() { + return language; + } + public void setLanguage(String language) { + this.language = language; + } + + /** + * List of purposes the user is consenting to. + **/ + public ConsentInput purposes(List purposes) { + + this.purposes = purposes; + return this; + } + + @ApiModelProperty(required = true, value = "List of purposes the user is consenting to.") + @JsonProperty("purposes") + @Valid + @NotNull(message = "Property purposes cannot be null.") + @Size(min=1) + public List getPurposes() { + return purposes; + } + public void setPurposes(List purposes) { + this.purposes = purposes; + } + + public ConsentInput addPurposesItem(ConsentPurposeInput purposesItem) { + this.purposes.add(purposesItem); + return this; + } + + /** + * Initial state of the consent. Use ACTIVE when the user accepts (default). Use REJECTED when the user explicitly declines an optional policy — this records that the user saw and skipped this version so it is not shown again until a new version is published. + **/ + public ConsentInput state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "ACTIVE", value = "Initial state of the consent. Use ACTIVE when the user accepts (default). Use REJECTED when the user explicitly declines an optional policy — this records that the user saw and skipped this version so it is not shown again until a new version is published. ") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + /** + * Milliseconds since epoch until which the consent is valid. If omitted, the consent does not expire. + **/ + public ConsentInput expiryTime(Long expiryTime) { + + this.expiryTime = expiryTime; + return this; + } + + @ApiModelProperty(example = "1766383796000", value = "Milliseconds since epoch until which the consent is valid. If omitted, the consent does not expire.") + @JsonProperty("expiryTime") + @Valid + public Long getExpiryTime() { + return expiryTime; + } + public void setExpiryTime(Long expiryTime) { + this.expiryTime = expiryTime; + } + + /** + * Optional free-form key-value properties for this consent. + **/ + public ConsentInput properties(Map properties) { + + this.properties = properties; + return this; + } + + @ApiModelProperty(example = "{\"source\":\"onboarding-flow\"}", value = "Optional free-form key-value properties for this consent.") + @JsonProperty("properties") + @Valid + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + + + public ConsentInput putPropertiesItem(String key, String propertiesItem) { + if (this.properties == null) { + this.properties = new HashMap<>(); + } + this.properties.put(key, propertiesItem); + return this; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentInput consentInput = (ConsentInput) o; + return Objects.equals(this.serviceId, consentInput.serviceId) && + Objects.equals(this.language, consentInput.language) && + Objects.equals(this.purposes, consentInput.purposes) && + Objects.equals(this.state, consentInput.state) && + Objects.equals(this.expiryTime, consentInput.expiryTime) && + Objects.equals(this.properties, consentInput.properties); + } + + @Override + public int hashCode() { + return Objects.hash(serviceId, language, purposes, state, expiryTime, properties); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentInput {\n"); + + sb.append(" serviceId: ").append(toIndentedString(serviceId)).append("\n"); + sb.append(" language: ").append(toIndentedString(language)).append("\n"); + sb.append(" purposes: ").append(toIndentedString(purposes)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" expiryTime: ").append(toIndentedString(expiryTime)).append("\n"); + sb.append(" properties: ").append(toIndentedString(properties)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeInput.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeInput.java new file mode 100644 index 00000000..00859446 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeInput.java @@ -0,0 +1,134 @@ +/* + * 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.user.consent.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.user.consent.v1.model.ElementRef; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentPurposeInput { + + private String id; + private List elements = new ArrayList<>(); + + + /** + * UUID of the purpose. + **/ + public ConsentPurposeInput id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "a43f8d09-2e1f-4b3a-9f6e-3a1b2c4d5e6f", required = true, value = "UUID of the purpose.") + @JsonProperty("id") + @Valid + @NotNull(message = "Property id cannot be null.") + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Consent elements (PII categories) included in this consent purpose. + **/ + public ConsentPurposeInput elements(List elements) { + + this.elements = elements; + return this; + } + + @ApiModelProperty(example = "[{id=c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h}]", required = true, value = "Consent elements (PII categories) included in this consent purpose.") + @JsonProperty("elements") + @Valid + @NotNull(message = "Property elements cannot be null.") + @Size(min=1) + public List getElements() { + return elements; + } + public void setElements(List elements) { + this.elements = elements; + } + + public ConsentPurposeInput addElementsItem(ElementRef elementsItem) { + this.elements.add(elementsItem); + return this; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentPurposeInput consentPurposeInput = (ConsentPurposeInput) o; + return Objects.equals(this.id, consentPurposeInput.id) && + Objects.equals(this.elements, consentPurposeInput.elements); + } + + @Override + public int hashCode() { + return Objects.hash(id, elements); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentPurposeInput {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" elements: ").append(toIndentedString(elements)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeResponse.java new file mode 100644 index 00000000..5d313df8 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentPurposeResponse.java @@ -0,0 +1,255 @@ +/* + * 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.user.consent.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.HashMap; +import java.util.List; +import java.util.Map; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentedElement; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentPurposeResponse { + + private String id; + private String name; + private String type; + private String versionId; + private String version; + private List elements = null; + + private Map properties = null; + + + /** + * UUID of the purpose. + **/ + public ConsentPurposeResponse id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "a43f8d09-2e1f-4b3a-9f6e-3a1b2c4d5e6f", value = "UUID of the purpose.") + @JsonProperty("id") + @Valid + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Name of the purpose. + **/ + public ConsentPurposeResponse name(String name) { + + this.name = name; + return this; + } + + @ApiModelProperty(example = "Marketing communications", value = "Name of the purpose.") + @JsonProperty("name") + @Valid + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + /** + * Purpose type classification. + **/ + public ConsentPurposeResponse type(String type) { + + this.type = type; + return this; + } + + @ApiModelProperty(example = "Policy", value = "Purpose type classification.") + @JsonProperty("type") + @Valid + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + /** + * UUID of the purpose version consented to. + **/ + public ConsentPurposeResponse versionId(String versionId) { + + this.versionId = versionId; + return this; + } + + @ApiModelProperty(example = "b53g9e10-3f2g-5c4b-0g7f-4b2c3d5e6f7g", value = "UUID of the purpose version consented to.") + @JsonProperty("versionId") + @Valid + public String getVersionId() { + return versionId; + } + public void setVersionId(String versionId) { + this.versionId = versionId; + } + + /** + * Human-readable version label. + **/ + public ConsentPurposeResponse version(String version) { + + this.version = version; + return this; + } + + @ApiModelProperty(example = "2", value = "Human-readable version label.") + @JsonProperty("version") + @Valid + public String getVersion() { + return version; + } + public void setVersion(String version) { + this.version = version; + } + + /** + * Consent elements included in this purpose. + **/ + public ConsentPurposeResponse elements(List elements) { + + this.elements = elements; + return this; + } + + @ApiModelProperty(value = "Consent elements included in this purpose.") + @JsonProperty("elements") + @Valid + public List getElements() { + return elements; + } + public void setElements(List elements) { + this.elements = elements; + } + + public ConsentPurposeResponse addElementsItem(ConsentedElement elementsItem) { + if (this.elements == null) { + this.elements = new ArrayList<>(); + } + this.elements.add(elementsItem); + return this; + } + + /** + * Key-value properties from the consented purpose version. + **/ + public ConsentPurposeResponse properties(Map properties) { + + this.properties = properties; + return this; + } + + @ApiModelProperty(value = "Key-value properties from the consented purpose version.") + @JsonProperty("properties") + @Valid + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + + + public ConsentPurposeResponse putPropertiesItem(String key, String propertiesItem) { + if (this.properties == null) { + this.properties = new HashMap<>(); + } + this.properties.put(key, propertiesItem); + return this; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentPurposeResponse consentPurposeResponse = (ConsentPurposeResponse) o; + return Objects.equals(this.id, consentPurposeResponse.id) && + Objects.equals(this.name, consentPurposeResponse.name) && + Objects.equals(this.type, consentPurposeResponse.type) && + Objects.equals(this.versionId, consentPurposeResponse.versionId) && + Objects.equals(this.version, consentPurposeResponse.version) && + Objects.equals(this.elements, consentPurposeResponse.elements) && + Objects.equals(this.properties, consentPurposeResponse.properties); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, type, versionId, version, elements, properties); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentPurposeResponse {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" versionId: ").append(toIndentedString(versionId)).append("\n"); + sb.append(" version: ").append(toIndentedString(version)).append("\n"); + sb.append(" elements: ").append(toIndentedString(elements)).append("\n"); + sb.append(" properties: ").append(toIndentedString(properties)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentResponse.java new file mode 100644 index 00000000..1ec05776 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentResponse.java @@ -0,0 +1,364 @@ +/* + * 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.user.consent.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.HashMap; +import java.util.List; +import java.util.Map; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentPurposeResponse; +import javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentResponse { + + private String id; + private String subjectId; + private String serviceId; + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("PENDING") PENDING(String.valueOf("PENDING")), @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state; + private String language; + private Long timestamp; + private Long expiryTime; + private List purposes = null; + + private List authorizations = null; + + private Map properties = null; + + + /** + * Unique identifier of the consent. + **/ + public ConsentResponse id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "d75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i", value = "Unique identifier of the consent.") + @JsonProperty("id") + @Valid + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Identifier of the user who gave consent. + **/ + public ConsentResponse subjectId(String subjectId) { + + this.subjectId = subjectId; + return this; + } + + @ApiModelProperty(example = "john", value = "Identifier of the user who gave consent.") + @JsonProperty("subjectId") + @Valid + public String getSubjectId() { + return subjectId; + } + public void setSubjectId(String subjectId) { + this.subjectId = subjectId; + } + + /** + * Identifier of the service the consent was given for. + **/ + public ConsentResponse serviceId(String serviceId) { + + this.serviceId = serviceId; + return this; + } + + @ApiModelProperty(example = "sampleApp", value = "Identifier of the service the consent was given for.") + @JsonProperty("serviceId") + @Valid + public String getServiceId() { + return serviceId; + } + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + /** + * Current state of the consent. + **/ + public ConsentResponse state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "ACTIVE", value = "Current state of the consent.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + /** + * Language code for the consent. + **/ + public ConsentResponse language(String language) { + + this.language = language; + return this; + } + + @ApiModelProperty(example = "en", value = "Language code for the consent.") + @JsonProperty("language") + @Valid + public String getLanguage() { + return language; + } + public void setLanguage(String language) { + this.language = language; + } + + /** + * Milliseconds since epoch when the consent was created. + **/ + public ConsentResponse timestamp(Long timestamp) { + + this.timestamp = timestamp; + return this; + } + + @ApiModelProperty(example = "1750156200000", value = "Milliseconds since epoch when the consent was created.") + @JsonProperty("timestamp") + @Valid + public Long getTimestamp() { + return timestamp; + } + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + /** + * Milliseconds since epoch until which the consent is valid. Null if no expiry. + **/ + public ConsentResponse expiryTime(Long expiryTime) { + + this.expiryTime = expiryTime; + return this; + } + + @ApiModelProperty(example = "1766383796000", value = "Milliseconds since epoch until which the consent is valid. Null if no expiry.") + @JsonProperty("expiryTime") + @Valid + public Long getExpiryTime() { + return expiryTime; + } + public void setExpiryTime(Long expiryTime) { + this.expiryTime = expiryTime; + } + + /** + * List of purposes included in the consent. + **/ + public ConsentResponse purposes(List purposes) { + + this.purposes = purposes; + return this; + } + + @ApiModelProperty(value = "List of purposes included in the consent.") + @JsonProperty("purposes") + @Valid + public List getPurposes() { + return purposes; + } + public void setPurposes(List purposes) { + this.purposes = purposes; + } + + public ConsentResponse addPurposesItem(ConsentPurposeResponse purposesItem) { + if (this.purposes == null) { + this.purposes = new ArrayList<>(); + } + this.purposes.add(purposesItem); + return this; + } + + /** + * Authorization records associated with this consent. + **/ + public ConsentResponse authorizations(List authorizations) { + + this.authorizations = authorizations; + return this; + } + + @ApiModelProperty(value = "Authorization records associated with this consent.") + @JsonProperty("authorizations") + @Valid + public List getAuthorizations() { + return authorizations; + } + public void setAuthorizations(List authorizations) { + this.authorizations = authorizations; + } + + public ConsentResponse addAuthorizationsItem(AuthorizationResponse authorizationsItem) { + if (this.authorizations == null) { + this.authorizations = new ArrayList<>(); + } + this.authorizations.add(authorizationsItem); + return this; + } + + /** + * Properties associated with this consent. + **/ + public ConsentResponse properties(Map properties) { + + this.properties = properties; + return this; + } + + @ApiModelProperty(value = "Properties associated with this consent.") + @JsonProperty("properties") + @Valid + public Map getProperties() { + return properties; + } + public void setProperties(Map properties) { + this.properties = properties; + } + + + public ConsentResponse putPropertiesItem(String key, String propertiesItem) { + if (this.properties == null) { + this.properties = new HashMap<>(); + } + this.properties.put(key, propertiesItem); + return this; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentResponse consentResponse = (ConsentResponse) o; + return Objects.equals(this.id, consentResponse.id) && + Objects.equals(this.subjectId, consentResponse.subjectId) && + Objects.equals(this.serviceId, consentResponse.serviceId) && + Objects.equals(this.state, consentResponse.state) && + Objects.equals(this.language, consentResponse.language) && + Objects.equals(this.timestamp, consentResponse.timestamp) && + Objects.equals(this.expiryTime, consentResponse.expiryTime) && + Objects.equals(this.purposes, consentResponse.purposes) && + Objects.equals(this.authorizations, consentResponse.authorizations) && + Objects.equals(this.properties, consentResponse.properties); + } + + @Override + public int hashCode() { + return Objects.hash(id, subjectId, serviceId, state, language, timestamp, expiryTime, purposes, authorizations, properties); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentResponse {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" subjectId: ").append(toIndentedString(subjectId)).append("\n"); + sb.append(" serviceId: ").append(toIndentedString(serviceId)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" language: ").append(toIndentedString(language)).append("\n"); + sb.append(" timestamp: ").append(toIndentedString(timestamp)).append("\n"); + sb.append(" expiryTime: ").append(toIndentedString(expiryTime)).append("\n"); + sb.append(" purposes: ").append(toIndentedString(purposes)).append("\n"); + sb.append(" authorizations: ").append(toIndentedString(authorizations)).append("\n"); + sb.append(" properties: ").append(toIndentedString(properties)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java new file mode 100644 index 00000000..3b8fede6 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java @@ -0,0 +1,198 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentSummary { + + private String id; + private String serviceId; + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state; + private Long timestamp; + + /** + * Unique identifier of the consent. + **/ + public ConsentSummary id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "d75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i", value = "Unique identifier of the consent.") + @JsonProperty("id") + @Valid + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Identifier of the service the consent was given for. + **/ + public ConsentSummary serviceId(String serviceId) { + + this.serviceId = serviceId; + return this; + } + + @ApiModelProperty(example = "sampleApp", value = "Identifier of the service the consent was given for.") + @JsonProperty("serviceId") + @Valid + public String getServiceId() { + return serviceId; + } + public void setServiceId(String serviceId) { + this.serviceId = serviceId; + } + + /** + * Current state of the consent. + **/ + public ConsentSummary state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "ACTIVE", value = "Current state of the consent.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + /** + * Milliseconds since epoch when the consent was created. + **/ + public ConsentSummary timestamp(Long timestamp) { + + this.timestamp = timestamp; + return this; + } + + @ApiModelProperty(example = "1750156200000", value = "Milliseconds since epoch when the consent was created.") + @JsonProperty("timestamp") + @Valid + public Long getTimestamp() { + return timestamp; + } + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentSummary consentSummary = (ConsentSummary) o; + return Objects.equals(this.id, consentSummary.id) && + Objects.equals(this.serviceId, consentSummary.serviceId) && + Objects.equals(this.state, consentSummary.state) && + Objects.equals(this.timestamp, consentSummary.timestamp); + } + + @Override + public int hashCode() { + return Objects.hash(id, serviceId, state, timestamp); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentSummary {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" serviceId: ").append(toIndentedString(serviceId)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" timestamp: ").append(toIndentedString(timestamp)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java new file mode 100644 index 00000000..82577cf5 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java @@ -0,0 +1,154 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentValidationResponse { + + +@XmlType(name="StateEnum") +@XmlEnum(String.class) +public enum StateEnum { + + @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + + + private String value; + + StateEnum(String v) { + value = v; + } + + public String value() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StateEnum fromValue(String value) { + for (StateEnum b : StateEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } +} + + private StateEnum state; + private Long expiryTime; + + /** + * Current state of the consent. + **/ + public ConsentValidationResponse state(StateEnum state) { + + this.state = state; + return this; + } + + @ApiModelProperty(example = "ACTIVE", value = "Current state of the consent.") + @JsonProperty("state") + @Valid + public StateEnum getState() { + return state; + } + public void setState(StateEnum state) { + this.state = state; + } + + /** + * Milliseconds since epoch until which the consent is valid. Null if no expiry. + **/ + public ConsentValidationResponse expiryTime(Long expiryTime) { + + this.expiryTime = expiryTime; + return this; + } + + @ApiModelProperty(example = "1766383796000", value = "Milliseconds since epoch until which the consent is valid. Null if no expiry.") + @JsonProperty("expiryTime") + @Valid + public Long getExpiryTime() { + return expiryTime; + } + public void setExpiryTime(Long expiryTime) { + this.expiryTime = expiryTime; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentValidationResponse consentValidationResponse = (ConsentValidationResponse) o; + return Objects.equals(this.state, consentValidationResponse.state) && + Objects.equals(this.expiryTime, consentValidationResponse.expiryTime); + } + + @Override + public int hashCode() { + return Objects.hash(state, expiryTime); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentValidationResponse {\n"); + + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" expiryTime: ").append(toIndentedString(expiryTime)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentedElement.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentedElement.java new file mode 100644 index 00000000..f00dfe20 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentedElement.java @@ -0,0 +1,121 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ConsentedElement { + + private String id; + private String name; + + /** + * UUID of the consent element. + **/ + public ConsentedElement id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h", value = "UUID of the consent element.") + @JsonProperty("id") + @Valid + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + /** + * Name of the consent element. + **/ + public ConsentedElement name(String name) { + + this.name = name; + return this; + } + + @ApiModelProperty(example = "Email Address", value = "Name of the consent element.") + @JsonProperty("name") + @Valid + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ConsentedElement consentedElement = (ConsentedElement) o; + return Objects.equals(this.id, consentedElement.id) && + Objects.equals(this.name, consentedElement.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ConsentedElement {\n"); + + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" name: ").append(toIndentedString(name)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ElementRef.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ElementRef.java new file mode 100644 index 00000000..d2eed873 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ElementRef.java @@ -0,0 +1,101 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class ElementRef { + + private String id; + + /** + * UUID of the consent element. + **/ + public ElementRef id(String id) { + + this.id = id; + return this; + } + + @ApiModelProperty(example = "c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h", required = true, value = "UUID of the consent element.") + @JsonProperty("id") + @Valid + @NotNull(message = "Property id cannot be null.") + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ElementRef elementRef = (ElementRef) o; + return Objects.equals(this.id, elementRef.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class ElementRef {\n"); + + sb.append(" id: ").append(toIndentedString(id)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/Error.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/Error.java new file mode 100644 index 00000000..5f74a9ce --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/Error.java @@ -0,0 +1,165 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class Error { + + private String code; + private String message; + private String description; + private String traceId; + + /** + **/ + public Error code(String code) { + + this.code = code; + return this; + } + + @ApiModelProperty(example = "CMT-00000", required = true, value = "") + @JsonProperty("code") + @Valid + @NotNull(message = "Property code cannot be null.") + + public String getCode() { + return code; + } + public void setCode(String code) { + this.code = code; + } + + /** + **/ + public Error message(String message) { + + this.message = message; + return this; + } + + @ApiModelProperty(example = "Some Error Message", required = true, value = "") + @JsonProperty("message") + @Valid + @NotNull(message = "Property message cannot be null.") + + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + + /** + **/ + public Error description(String description) { + + this.description = description; + return this; + } + + @ApiModelProperty(example = "Some Error Description", value = "") + @JsonProperty("description") + @Valid + public String getDescription() { + return description; + } + public void setDescription(String description) { + this.description = description; + } + + /** + **/ + public Error traceId(String traceId) { + + this.traceId = traceId; + return this; + } + + @ApiModelProperty(example = "e0fbcfeb-3617-43c4-8dd0-7b7d38e13047", value = "") + @JsonProperty("traceId") + @Valid + public String getTraceId() { + return traceId; + } + public void setTraceId(String traceId) { + this.traceId = traceId; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Error error = (Error) o; + return Objects.equals(this.code, error.code) && + Objects.equals(this.message, error.message) && + Objects.equals(this.description, error.description) && + Objects.equals(this.traceId, error.traceId); + } + + @Override + public int hashCode() { + return Objects.hash(code, message, description, traceId); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class Error {\n"); + + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" description: ").append(toIndentedString(description)).append("\n"); + sb.append(" traceId: ").append(toIndentedString(traceId)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java new file mode 100644 index 00000000..2c01149a --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java @@ -0,0 +1,119 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class KeyValuePair { + + private String key; + private String value; + + /** + **/ + public KeyValuePair key(String key) { + + this.key = key; + return this; + } + + @ApiModelProperty(example = "source", value = "") + @JsonProperty("key") + @Valid + public String getKey() { + return key; + } + public void setKey(String key) { + this.key = key; + } + + /** + **/ + public KeyValuePair value(String value) { + + this.value = value; + return this; + } + + @ApiModelProperty(example = "onboarding-flow", value = "") + @JsonProperty("value") + @Valid + public String getValue() { + return value; + } + public void setValue(String value) { + this.value = value; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + KeyValuePair keyValuePair = (KeyValuePair) o; + return Objects.equals(this.key, keyValuePair.key) && + Objects.equals(this.value, keyValuePair.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class KeyValuePair {\n"); + + sb.append(" key: ").append(toIndentedString(key)).append("\n"); + sb.append(" value: ").append(toIndentedString(value)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java new file mode 100644 index 00000000..61468252 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java @@ -0,0 +1,121 @@ +/* + * 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.user.consent.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 javax.validation.constraints.*; + + +import io.swagger.annotations.*; +import java.util.Objects; +import javax.validation.Valid; +import javax.xml.bind.annotation.*; + +public class PIICategorySummary { + + private String piiCategoryId; + private String piiCategoryName; + + /** + * UUID of the PII category. + **/ + public PIICategorySummary piiCategoryId(String piiCategoryId) { + + this.piiCategoryId = piiCategoryId; + return this; + } + + @ApiModelProperty(example = "c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h", value = "UUID of the PII category.") + @JsonProperty("piiCategoryId") + @Valid + public String getPiiCategoryId() { + return piiCategoryId; + } + public void setPiiCategoryId(String piiCategoryId) { + this.piiCategoryId = piiCategoryId; + } + + /** + * Name of the PII category. + **/ + public PIICategorySummary piiCategoryName(String piiCategoryName) { + + this.piiCategoryName = piiCategoryName; + return this; + } + + @ApiModelProperty(example = "Email Address", value = "Name of the PII category.") + @JsonProperty("piiCategoryName") + @Valid + public String getPiiCategoryName() { + return piiCategoryName; + } + public void setPiiCategoryName(String piiCategoryName) { + this.piiCategoryName = piiCategoryName; + } + + + + @Override + public boolean equals(java.lang.Object o) { + + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PIICategorySummary piICategorySummary = (PIICategorySummary) o; + return Objects.equals(this.piiCategoryId, piICategorySummary.piiCategoryId) && + Objects.equals(this.piiCategoryName, piICategorySummary.piiCategoryName); + } + + @Override + public int hashCode() { + return Objects.hash(piiCategoryId, piiCategoryName); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append("class PIICategorySummary {\n"); + + sb.append(" piiCategoryId: ").append(toIndentedString(piiCategoryId)).append("\n"); + sb.append(" piiCategoryName: ").append(toIndentedString(piiCategoryName)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java new file mode 100644 index 00000000..8222bc55 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java @@ -0,0 +1,92 @@ +/* + * 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.user.consent.v1.impl; + +import org.wso2.carbon.identity.api.user.consent.v1.MeApiService; +import org.wso2.carbon.identity.api.user.consent.v1.impl.core.UserConsentService; +import org.wso2.carbon.identity.api.user.consent.v1.impl.factories.UserConsentServiceFactory; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationRequest; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentCreateResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentInput; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentSummary; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentValidationResponse; + +import java.util.List; + +import javax.ws.rs.core.Response; + +/** + * Implementation of the self-service consent API for the authenticated user. + */ +public class MeApiServiceImpl implements MeApiService { + + private final UserConsentService userConsentService; + + public MeApiServiceImpl() { + + userConsentService = UserConsentServiceFactory.getUserConsentService(); + } + + @Override + public Response addConsentOfLoggedInUser(ConsentInput consent) { + + ConsentCreateResponse response = userConsentService.addConsent(consent); + return Response.status(Response.Status.CREATED).entity(response).build(); + } + + @Override + public Response authorizeConsentOfLoggedInUser(String consentId, AuthorizationRequest authorization) { + + AuthorizationResponse response = userConsentService.authorizeConsent(consentId, authorization); + return Response.ok(response).build(); + } + + @Override + public Response getConsentOfLoggedInUser(String consentId) { + + ConsentResponse response = userConsentService.getConsent(consentId); + return Response.ok(response).build(); + } + + @Override + public Response listConsentsOfLoggedInUser(String serviceId, String state, String purposeId, + String purposeVersionId, String filter, + Integer limit, String after, String before) { + + List summaries = userConsentService.listConsents( + serviceId, state, purposeId, purposeVersionId, filter, limit, after, before); + return Response.ok(summaries).build(); + } + + @Override + public Response revokeConsentOfLoggedInUser(String consentId) { + + userConsentService.revokeConsent(consentId); + return Response.ok().build(); + } + + @Override + public Response validateConsentOfLoggedInUser(String consentId) { + + ConsentValidationResponse response = userConsentService.validateConsent(consentId); + return Response.ok(response).build(); + } +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java new file mode 100644 index 00000000..dfd21915 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -0,0 +1,474 @@ +/* + * 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.user.consent.v1.impl.core; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.consent.mgt.core.PrivilegedConsentManager; +import org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ErrorMessages; +import org.wso2.carbon.consent.mgt.core.exception.ConsentManagementClientException; +import org.wso2.carbon.consent.mgt.core.exception.ConsentManagementException; +import org.wso2.carbon.consent.mgt.core.model.AddReceiptResponse; +import org.wso2.carbon.consent.mgt.core.model.ConsentAuthorization; +import org.wso2.carbon.consent.mgt.core.model.ConsentPurpose; +import org.wso2.carbon.consent.mgt.core.model.PIICategory; +import org.wso2.carbon.consent.mgt.core.model.PIICategoryValidity; +import org.wso2.carbon.consent.mgt.core.model.Purpose; +import org.wso2.carbon.consent.mgt.core.model.PurposePIICategoryBinding; +import org.wso2.carbon.consent.mgt.core.model.PurposeVersion; +import org.wso2.carbon.consent.mgt.core.model.Receipt; +import org.wso2.carbon.consent.mgt.core.model.ReceiptInput; +import org.wso2.carbon.consent.mgt.core.model.ReceiptService; +import org.wso2.carbon.consent.mgt.core.util.ConsentReceiptUtils; +import org.wso2.carbon.consent.mgt.core.util.FilterQueriesUtil; +import org.wso2.carbon.identity.api.user.common.ContextLoader; +import org.wso2.carbon.identity.api.user.common.error.APIError; +import org.wso2.carbon.identity.api.user.common.error.ErrorResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationRequest; +import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentCreateResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentInput; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentPurposeInput; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentPurposeResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentSummary; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentValidationResponse; +import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentedElement; +import org.wso2.carbon.identity.api.user.consent.v1.model.ElementRef; +import org.wso2.carbon.identity.core.model.ExpressionNode; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.core.Response; + +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ACTIVE_STATE; +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ErrorMessages.ERROR_CODE_INVALID_FILTER_EXPRESSION; +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ErrorMessages.ERROR_CODE_INVALID_QUERY_PARAM; +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.FilterConstants; +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.PENDING_STATE; +import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.REVOKE_STATE; +import static org.wso2.carbon.consent.mgt.core.util.ConsentUtils.handleClientException; + +/** + * Core service for user self-service consent management operations. + * Always scopes operations to the currently authenticated user. + */ +public class UserConsentService { + + private static final Log LOG = LogFactory.getLog(UserConsentService.class); + + private static final Set NOT_FOUND_ERROR_CODES = new HashSet<>(Arrays.asList( + ErrorMessages.ERROR_CODE_RECEIPT_ID_INVALID.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_ID_INVALID.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_CATEGORY_ID_INVALID.getCode(), + ErrorMessages.ERROR_CODE_PII_CATEGORY_ID_INVALID.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_UUID_NOT_FOUND.getCode(), + ErrorMessages.ERROR_CODE_ELEMENT_UUID_NOT_FOUND.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_VERSION_ID_INVALID.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_VERSION_NOT_FOUND.getCode() + )); + + private static final Set CONFLICT_ERROR_CODES = new HashSet<>(Arrays.asList( + ErrorMessages.ERROR_CODE_PURPOSE_ALREADY_EXIST.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_CATEGORY_ALREADY_EXIST.getCode(), + ErrorMessages.ERROR_CODE_PII_CATEGORY_ALREADY_EXIST.getCode(), + ErrorMessages.ERROR_CODE_PURPOSE_VERSION_ALREADY_EXISTS.getCode(), + ErrorMessages.ERROR_CODE_CONSENT_INVALID_STATE_FOR_AUTHORIZE.getCode() + )); + + private static final Set FORBIDDEN_ERROR_CODES = new HashSet<>(Arrays.asList( + ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getCode() + )); + + private final PrivilegedConsentManager consentManager; + + public UserConsentService(PrivilegedConsentManager consentManager) { + + this.consentManager = consentManager; + } + + public ConsentCreateResponse addConsent(ConsentInput consentInput) { + + String subjectId = ContextLoader.getUsernameFromContext(); + String tenantDomain = ContextLoader.getTenantDomainFromContext(); + + boolean rejected = ConsentInput.StateEnum.REJECTED.equals(consentInput.getState()); + String language = consentInput.getLanguage(); + Timestamp expiryTimestamp = consentInput.getExpiryTime() != null + ? new Timestamp(consentInput.getExpiryTime()) : null; + + try { + List purposeBindings = buildPurposeBindings(consentInput); + Map properties = consentInput.getProperties(); + + ReceiptInput receiptInput = ConsentReceiptUtils.buildReceiptInput( + language, subjectId, tenantDomain, expiryTimestamp, rejected, null, + properties, consentInput.getServiceId(), purposeBindings, consentManager); + + AddReceiptResponse addReceiptResponse = consentManager.addConsent(receiptInput); + + ConsentInput.StateEnum requestedState = consentInput.getState() != null + ? consentInput.getState() : ConsentInput.StateEnum.ACTIVE; + ConsentCreateResponse response = new ConsentCreateResponse(); + response.setId(addReceiptResponse.getConsentReceiptId()); + response.setSubjectId(subjectId); + response.setServiceId(consentInput.getServiceId()); + response.setState(ConsentCreateResponse.StateEnum.fromValue(requestedState.value())); + return response; + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + public List listConsents(String serviceId, String state, String purposeId, + String purposeVersionId, String filter, + Integer limit, String after, String before) { + + String subjectId = ContextLoader.getUsernameFromContext(); + + try { + int resolvedLimit = limit != null ? limit : 10; + if (resolvedLimit <= 0) { + throw handleClientException(ERROR_CODE_INVALID_QUERY_PARAM, String.valueOf(resolvedLimit)); + } + + if (StringUtils.isNotBlank(before) && StringUtils.isNotBlank(after)) { + throw handleClientException(ERROR_CODE_INVALID_QUERY_PARAM, + "Both 'before' and 'after' parameters are provided."); + } + + List expressionNodes = FilterQueriesUtil.getExpressionNodes(filter, after, before); + for (ExpressionNode node : expressionNodes) { + String attr = node.getAttributeValue(); + if (FilterConstants.FILTER_ATTR_AFTER.equals(attr) || + FilterConstants.FILTER_ATTR_BEFORE.equals(attr)) { + continue; + } + if (attr == null || !attr.startsWith("properties.") || attr.length() == "properties.".length()) { + throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, + "Only 'properties.' attributes are supported in consent filter. Got: " + attr); + } + if (!"eq".equals(node.getOperation())) { + throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, + "Only 'eq' operation is supported for consent property filter."); + } + } + + List receipts = consentManager.listReceipts( + subjectId, serviceId, state, purposeId, purposeVersionId, expressionNodes, resolvedLimit + 1); + + if (receipts != null && receipts.size() > resolvedLimit) { + receipts = new ArrayList<>(receipts.subList(0, resolvedLimit)); + } + + List summaries = new ArrayList<>(); + if (receipts != null) { + for (Receipt receipt : receipts) { + summaries.add(toConsentSummary(receipt)); + } + } + return summaries; + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + public ConsentResponse getConsent(String consentId) { + + String subjectId = ContextLoader.getUsernameFromContext(); + + try { + Receipt receipt = consentManager.getReceiptWithExtendedSchema(consentId); + validateOwnership(receipt, consentId, subjectId); + return toConsentResponse(receipt); + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + public void revokeConsent(String consentId) { + + String subjectId = ContextLoader.getUsernameFromContext(); + + try { + Receipt receipt = consentManager.getReceiptWithExtendedSchema(consentId); + validateOwnership(receipt, consentId, subjectId); + consentManager.authorizeConsent(consentId, subjectId, REVOKE_STATE); + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + public AuthorizationResponse authorizeConsent(String consentId, AuthorizationRequest authorizationRequest) { + + String subjectId = ContextLoader.getUsernameFromContext(); + + try { + AuthorizationRequest.StateEnum requestState = authorizationRequest.getState(); + String authStatus = requestState != null ? requestState.value() : + AuthorizationRequest.StateEnum.APPROVED.value(); + + Receipt receipt = consentManager.getReceiptWithExtendedSchema(consentId); + validateOwnership(receipt, consentId, subjectId); + consentManager.authorizeConsent(consentId, subjectId, authStatus); + + List authorizations = consentManager.getConsentAuthorizations(consentId); + ConsentAuthorization userAuth = null; + if (authorizations != null) { + for (ConsentAuthorization auth : authorizations) { + if (subjectId.equals(auth.getUserId())) { + userAuth = auth; + break; + } + } + } + + AuthorizationResponse response = new AuthorizationResponse(); + response.setUserId(subjectId); + if (userAuth != null) { + response.setState(AuthorizationResponse.StateEnum.fromValue(userAuth.getStatus().name())); + response.setUpdatedTime(userAuth.getUpdatedTime()); + } else { + response.setState(AuthorizationResponse.StateEnum.fromValue(authStatus)); + response.setUpdatedTime(System.currentTimeMillis()); + } + return response; + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + public ConsentValidationResponse validateConsent(String consentId) { + + String subjectId = ContextLoader.getUsernameFromContext(); + + try { + Receipt receipt = consentManager.getReceiptWithExtendedSchema(consentId); + validateOwnership(receipt, consentId, subjectId); + + String status = consentManager.validateConsentStatus(consentId); + ConsentValidationResponse response = new ConsentValidationResponse(); + response.setState(ConsentValidationResponse.StateEnum.fromValue(status)); + response.setExpiryTime(receipt.getExpiryTime() != null ? receipt.getExpiryTime().getTime() : null); + return response; + } catch (ConsentManagementException e) { + throw handleException(e); + } + } + + private List buildPurposeBindings(ConsentInput consentInput) + throws ConsentManagementException { + + List purposeBindings = new ArrayList<>(); + if (consentInput.getPurposes() == null) { + return purposeBindings; + } + for (ConsentPurposeInput purposeInput : consentInput.getPurposes()) { + List piiCategories = new ArrayList<>(); + if (purposeInput.getElements() != null) { + for (ElementRef elementRef : purposeInput.getElements()) { + PIICategory piiCategory = consentManager.getPIICategoryByUuid(elementRef.getId()); + if (piiCategory == null) { + throw new ConsentManagementClientException( + "Element not found: " + elementRef.getId(), + ErrorMessages.ERROR_CODE_ELEMENT_UUID_NOT_FOUND.getCode()); + } + piiCategories.add(piiCategory); + } + } + purposeBindings.add(new PurposePIICategoryBinding(purposeInput.getId(), piiCategories)); + } + return purposeBindings; + } + + private void validateOwnership(Receipt receipt, String consentId, String subjectId) { + + if (receipt == null) { + throw new APIError(Response.Status.NOT_FOUND, new ErrorResponse.Builder() + .withCode(ErrorMessages.ERROR_CODE_RECEIPT_ID_INVALID.getCode()) + .withMessage("Consent not found.") + .withDescription("No consent found for ID: " + consentId) + .build()); + } + if (!subjectId.equals(receipt.getPiiPrincipalId())) { + throw new APIError(Response.Status.FORBIDDEN, new ErrorResponse.Builder() + .withCode(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getCode()) + .withMessage(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getMessage()) + .build()); + } + } + + private ConsentResponse toConsentResponse(Receipt receipt) { + + ConsentResponse dto = new ConsentResponse(); + dto.setId(receipt.getConsentReceiptId()); + dto.setSubjectId(receipt.getPiiPrincipalId()); + dto.setLanguage(receipt.getLanguage()); + String state = StringUtils.isNotBlank(receipt.getState()) ? receipt.getState() : ACTIVE_STATE; + dto.setState(ConsentResponse.StateEnum.fromValue(state)); + dto.setTimestamp(receipt.getConsentTimestamp()); + dto.setExpiryTime(receipt.getExpiryTime() != null ? receipt.getExpiryTime().getTime() : null); + dto.setProperties(receipt.getProperties()); + + List purposeResponses = new ArrayList<>(); + List services = receipt.getServices(); + if (services != null && !services.isEmpty()) { + ReceiptService receiptService = services.get(0); + dto.setServiceId(receiptService.getService()); + if (receiptService.getPurposes() != null) { + for (ConsentPurpose consentPurpose : receiptService.getPurposes()) { + purposeResponses.add(toConsentPurposeResponse(consentPurpose)); + } + } + } + dto.setPurposes(purposeResponses); + + List authResponses = new ArrayList<>(); + try { + List auths = consentManager.getConsentAuthorizations(receipt.getConsentReceiptId()); + if (auths != null) { + for (ConsentAuthorization auth : auths) { + if (PENDING_STATE.equals(auth.getStatus().name())) { + continue; + } + try { + AuthorizationResponse authResponse = new AuthorizationResponse(); + authResponse.setUserId(auth.getUserId()); + authResponse.setState(AuthorizationResponse.StateEnum.fromValue(auth.getStatus().name())); + authResponse.setUpdatedTime(auth.getUpdatedTime()); + authResponses.add(authResponse); + } catch (IllegalArgumentException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Skipping unrecognized authorization state: " + auth.getStatus(), e); + } + } + } + } + } catch (ConsentManagementException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Could not retrieve authorizations for consent: " + receipt.getConsentReceiptId(), e); + } + } + dto.setAuthorizations(authResponses); + return dto; + } + + private ConsentPurposeResponse toConsentPurposeResponse(ConsentPurpose consentPurpose) { + + ConsentPurposeResponse dto = new ConsentPurposeResponse(); + dto.setName(consentPurpose.getPurpose()); + + String versionUuid = consentPurpose.getPurposeVersionId(); + try { + Purpose purpose = consentManager.getPurposeByUuid(consentPurpose.getUuid()); + if (purpose != null) { + if (StringUtils.isNotBlank(purpose.getUuid())) { + dto.setId(purpose.getUuid()); + } + if (StringUtils.isNotBlank(purpose.getGroupType())) { + dto.setType(purpose.getGroupType()); + } + if (StringUtils.isNotBlank(versionUuid)) { + dto.setVersionId(versionUuid); + PurposeVersion latestVersion = purpose.getLatestVersion(); + if (latestVersion != null && versionUuid.equals(latestVersion.getUuid())) { + dto.setVersion(latestVersion.getVersion()); + dto.setProperties(latestVersion.getProperties()); + } else if (dto.getId() != null) { + PurposeVersion pv = consentManager.getPurposeVersion(dto.getId(), versionUuid); + if (pv != null) { + dto.setVersion(pv.getVersion()); + dto.setProperties(pv.getProperties()); + } + } + } + } + } catch (ConsentManagementException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Could not resolve purpose UUID: " + consentPurpose.getUuid(), e); + } + } + + List elements = new ArrayList<>(); + if (consentPurpose.getPiiCategory() != null) { + for (PIICategoryValidity piiCategoryValidity : consentPurpose.getPiiCategory()) { + ConsentedElement element = new ConsentedElement(); + element.setName(piiCategoryValidity.getName()); + try { + PIICategory piiCategory = consentManager.getPIICategoryByUuid(piiCategoryValidity.getUuid()); + if (piiCategory != null) { + element.setId(piiCategory.getUuid()); + } + } catch (ConsentManagementException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Could not resolve element UUID: " + piiCategoryValidity.getUuid(), e); + } + } + elements.add(element); + } + } + dto.setElements(elements); + return dto; + } + + private ConsentSummary toConsentSummary(Receipt receipt) { + + ConsentSummary summary = new ConsentSummary(); + summary.setId(receipt.getConsentReceiptId()); + summary.setTimestamp(receipt.getConsentTimestamp()); + String state = StringUtils.isNotBlank(receipt.getState()) ? receipt.getState() : ACTIVE_STATE; + summary.setState(ConsentSummary.StateEnum.fromValue(state)); + if (receipt.getServices() != null && !receipt.getServices().isEmpty()) { + summary.setServiceId(receipt.getServices().get(0).getService()); + } + return summary; + } + + private APIError handleException(ConsentManagementException e) { + + if (e instanceof ConsentManagementClientException) { + String errorCode = e.getErrorCode(); + Response.Status status = Response.Status.BAD_REQUEST; + if (errorCode != null && NOT_FOUND_ERROR_CODES.contains(errorCode)) { + status = Response.Status.NOT_FOUND; + } else if (errorCode != null && FORBIDDEN_ERROR_CODES.contains(errorCode)) { + status = Response.Status.FORBIDDEN; + } else if (errorCode != null && CONFLICT_ERROR_CODES.contains(errorCode)) { + status = Response.Status.CONFLICT; + } + return new APIError(status, new ErrorResponse.Builder() + .withCode(errorCode) + .withMessage(e.getMessage()) + .withDescription(e.getMessage()) + .build()); + } + LOG.error("Unexpected error in consent management.", e); + return new APIError(Response.Status.INTERNAL_SERVER_ERROR, new ErrorResponse.Builder() + .withCode(e.getErrorCode()) + .withMessage("Server error occurred during consent management.") + .build()); + } +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/factories/UserConsentServiceFactory.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/factories/UserConsentServiceFactory.java new file mode 100644 index 00000000..5952fc23 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/factories/UserConsentServiceFactory.java @@ -0,0 +1,49 @@ +/* + * 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.user.consent.v1.impl.factories; + +import org.wso2.carbon.consent.mgt.core.PrivilegedConsentManager; +import org.wso2.carbon.identity.api.user.consent.common.util.ConsentManagementServiceHolder; +import org.wso2.carbon.identity.api.user.consent.v1.impl.core.UserConsentService; + +/** + * Factory class for UserConsentService. + */ +public class UserConsentServiceFactory { + + private static final UserConsentService SERVICE; + + static { + PrivilegedConsentManager consentManager = ConsentManagementServiceHolder.getPrivilegedConsentManager(); + if (consentManager == null) { + throw new IllegalStateException("PrivilegedConsentManager is not available in the OSGi context."); + } + SERVICE = new UserConsentService(consentManager); + } + + /** + * Returns the UserConsentService instance. + * + * @return UserConsentService + */ + public static UserConsentService getUserConsentService() { + + return SERVICE; + } +} diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml new file mode 100644 index 00000000..ed62e0c1 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml @@ -0,0 +1,661 @@ +swagger: '2.0' +info: + description: > + This is the RESTful API for managing consents in WSO2 Identity Server. The APIs provide the capability + for an authenticated user to create, retrieve, and revoke their own consents (self-service). + version: 'v1' + title: WSO2 Identity Server - User Consent Management API Definition + contact: + name: 'WSO2 Identity Server' + url: 'https://wso2.com/identity-and-access-management/' + email: 'architecture@wso2.com' + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' + +schemes: + - https + +host: localhost:9443 +basePath: /t/{tenant-domain}/api/users/v1 + +tags: + - name: me + description: Consent management operations for the authenticated user. + +security: + - OAuth2: [] + - BasicAuth: [] + +paths: + /me/consents: + post: + tags: + - me + summary: Create a consent record + description: > + Record consent for specified purposes and elements. + The authenticated user creates and gives consent simultaneously. The consent is immediately recorded as `ACTIVE` or `REJECTED` based on the provided state.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: addConsentOfLoggedInUser + consumes: + - application/json + produces: + - application/json + parameters: + - in: body + name: consent + description: Consent to be created. + required: true + schema: + $ref: '#/definitions/ConsentInput' + responses: + 201: + description: Consent created successfully. + schema: + $ref: '#/definitions/ConsentCreateResponse' + 400: + $ref: '#/responses/InvalidInput' + 401: + $ref: '#/responses/Unauthorized' + 409: + $ref: '#/responses/Conflict' + 500: + $ref: '#/responses/ServerError' + + get: + tags: + - me + summary: List consent records + description: > + Retrieve consent records with optional filtering. + Returns only the authenticated user's own consents.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: listConsentsOfLoggedInUser + produces: + - application/json + parameters: + - $ref: '#/parameters/serviceIdQueryParam' + - $ref: '#/parameters/stateQueryParam' + - $ref: '#/parameters/purposeIdQueryParam' + - $ref: '#/parameters/purposeVersionIdQueryParam' + - $ref: '#/parameters/filterQueryParam' + - $ref: '#/parameters/limitQueryParam' + - $ref: '#/parameters/afterQueryParam' + - $ref: '#/parameters/beforeQueryParam' + responses: + 200: + description: Consents retrieved successfully. + schema: + type: array + items: + $ref: '#/definitions/ConsentSummary' + 401: + $ref: '#/responses/Unauthorized' + 500: + $ref: '#/responses/ServerError' + + /me/consents/{consent-id}: + get: + tags: + - me + summary: Get a consent record + description: > + Retrieve a specific consent record by consent ID. + Only the consent subject may retrieve the record. Returns 403 if the authenticated user is not the consent subject.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: getConsentOfLoggedInUser + produces: + - application/json + parameters: + - $ref: '#/parameters/consentIdPathParam' + responses: + 200: + description: Consent retrieved successfully. + schema: + $ref: '#/definitions/ConsentResponse' + 401: + $ref: '#/responses/Unauthorized' + 403: + $ref: '#/responses/Forbidden' + 404: + $ref: '#/responses/NotFound' + 500: + $ref: '#/responses/ServerError' + + /me/consents/{consent-id}/revoke: + post: + tags: + - me + summary: Revoke a consent + description: > + Revokes the consent. The authenticated user must be the consent subject, returns 403 otherwise. + Idempotent — if the consent is already revoked, returns 200 with no error.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: revokeConsentOfLoggedInUser + parameters: + - $ref: '#/parameters/consentIdPathParam' + responses: + 200: + $ref: '#/responses/OK' + 401: + $ref: '#/responses/Unauthorized' + 403: + $ref: '#/responses/Forbidden' + 404: + $ref: '#/responses/NotFound' + 500: + $ref: '#/responses/ServerError' + + /me/consents/{consent-id}/authorize: + post: + tags: + - me + summary: Authorize a consent + description: > + Authorizes a PENDING consent. The authenticated user must be in the consent's authorization list, returns 403 otherwise. + When all required users have approved, the consent transitions to ACTIVE state. + If any user rejects, the consent transitions to REJECTED state.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: authorizeConsentOfLoggedInUser + consumes: + - application/json + produces: + - application/json + parameters: + - $ref: '#/parameters/consentIdPathParam' + - in: body + name: authorization + description: Authorization decision. + required: true + schema: + $ref: '#/definitions/AuthorizationRequest' + responses: + 200: + description: Authorization recorded successfully. + schema: + $ref: '#/definitions/AuthorizationResponse' + 400: + $ref: '#/responses/InvalidInput' + 401: + $ref: '#/responses/Unauthorized' + 403: + $ref: '#/responses/Forbidden' + 404: + $ref: '#/responses/NotFound' + 409: + $ref: '#/responses/Conflict' + 500: + $ref: '#/responses/ServerError' + + /me/consents/{consent-id}/validate: + get: + tags: + - me + summary: Get the current state of a consent object + description: > + Returns the current state of a consent record, performing a lazy expiry check. + The authenticated user must be the consent subject, returns 403 otherwise.
+ Permission required:
+ * None
+ Scope required:
+ * internal_login + operationId: validateConsentOfLoggedInUser + produces: + - application/json + parameters: + - $ref: '#/parameters/consentIdPathParam' + responses: + 200: + description: Consent status retrieved successfully. + schema: + $ref: '#/definitions/ConsentValidationResponse' + 401: + $ref: '#/responses/Unauthorized' + 403: + $ref: '#/responses/Forbidden' + 404: + $ref: '#/responses/NotFound' + 500: + $ref: '#/responses/ServerError' + +#----------------------------------------------------- +# Descriptions of common responses +#----------------------------------------------------- +responses: + NotFound: + description: Resource Not Found + schema: + $ref: '#/definitions/Error' + Unauthorized: + description: Unauthorized + ServerError: + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + InvalidInput: + description: Invalid input request + schema: + $ref: '#/definitions/Error' + Forbidden: + description: Resource Forbidden + schema: + $ref: '#/definitions/Error' + Conflict: + description: Conflict + schema: + $ref: '#/definitions/Error' + OK: + description: OK + NoContent: + description: No Content + +definitions: + ConsentInput: + type: object + required: + - serviceId + - purposes + properties: + serviceId: + type: string + minLength: 1 + maxLength: 255 + description: Identifier of the service the consent is given for. + example: 'sampleApp' + language: + type: string + minLength: 1 + maxLength: 20 + description: Language code for the consent. + example: 'en' + purposes: + type: array + minItems: 1 + description: List of purposes the user is consenting to. + items: + $ref: '#/definitions/ConsentPurposeInput' + state: + type: string + enum: + - ACTIVE + - REJECTED + default: ACTIVE + description: > + Initial state of the consent. Use ACTIVE when the user accepts (default). + Use REJECTED when the user explicitly declines an optional policy — this records + that the user saw and skipped this version so it is not shown again until a new + version is published. + example: 'ACTIVE' + expiryTime: + type: integer + format: int64 + x-nullable: true + description: Milliseconds since epoch until which the consent is valid. If omitted, the consent does not expire. + example: 1766383796000 + properties: + type: object + description: Optional free-form key-value properties for this consent. + additionalProperties: + type: string + example: + source: 'onboarding-flow' + + ConsentPurposeInput: + type: object + required: + - id + - elements + properties: + id: + type: string + description: UUID of the purpose. + example: 'a43f8d09-2e1f-4b3a-9f6e-3a1b2c4d5e6f' + elements: + type: array + minItems: 1 + description: Consent elements (PII categories) included in this consent purpose. + items: + $ref: '#/definitions/ElementRef' + example: + - id: 'c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h' + + ElementRef: + type: object + required: + - id + properties: + id: + type: string + description: UUID of the consent element. + example: 'c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h' + + ConsentSummary: + type: object + properties: + id: + type: string + description: Unique identifier of the consent. + example: 'd75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i' + serviceId: + type: string + description: Identifier of the service the consent was given for. + example: 'sampleApp' + state: + type: string + description: Current state of the consent. + enum: + - ACTIVE + - REVOKED + - EXPIRED + example: 'ACTIVE' + timestamp: + type: integer + format: int64 + description: Milliseconds since epoch when the consent was created. + example: 1750156200000 + + ConsentCreateResponse: + type: object + properties: + id: + type: string + description: Unique identifier of the created consent. + example: 'd75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i' + subjectId: + type: string + description: Identifier of the user who gave consent. + example: 'john' + serviceId: + type: string + description: Identifier of the service the consent was given for. + example: 'sampleApp' + state: + type: string + description: Initial state of the consent. + enum: + - ACTIVE + - REVOKED + - EXPIRED + example: 'ACTIVE' + + ConsentResponse: + type: object + properties: + id: + type: string + description: Unique identifier of the consent. + example: 'd75i1g32-5h4i-7e6d-2i9h-6d4e5f7g8h9i' + subjectId: + type: string + description: Identifier of the user who gave consent. + example: 'john' + serviceId: + type: string + description: Identifier of the service the consent was given for. + example: 'sampleApp' + state: + type: string + description: Current state of the consent. + enum: + - PENDING + - ACTIVE + - REJECTED + - REVOKED + - EXPIRED + example: 'ACTIVE' + language: + type: string + description: Language code for the consent. + example: 'en' + timestamp: + type: integer + format: int64 + description: Milliseconds since epoch when the consent was created. + example: 1750156200000 + expiryTime: + type: integer + format: int64 + x-nullable: true + description: Milliseconds since epoch until which the consent is valid. Null if no expiry. + example: 1766383796000 + purposes: + type: array + description: List of purposes included in the consent. + items: + $ref: '#/definitions/ConsentPurposeResponse' + authorizations: + type: array + description: Authorization records associated with this consent. + items: + $ref: '#/definitions/AuthorizationResponse' + properties: + type: object + x-nullable: true + description: Properties associated with this consent. + additionalProperties: + type: string + + ConsentPurposeResponse: + type: object + properties: + id: + type: string + description: UUID of the purpose. + example: 'a43f8d09-2e1f-4b3a-9f6e-3a1b2c4d5e6f' + name: + type: string + description: Name of the purpose. + example: 'Marketing communications' + type: + type: string + description: Purpose type classification. + example: 'Policy' + versionId: + type: string + description: UUID of the purpose version consented to. + example: 'b53g9e10-3f2g-5c4b-0g7f-4b2c3d5e6f7g' + version: + type: string + x-nullable: true + description: Human-readable version label. + example: '2' + elements: + type: array + description: Consent elements included in this purpose. + items: + $ref: '#/definitions/ConsentedElement' + properties: + type: object + x-nullable: true + description: Key-value properties from the consented purpose version. + additionalProperties: + type: string + + ConsentedElement: + type: object + properties: + id: + type: string + description: UUID of the consent element. + example: 'c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h' + name: + type: string + description: Name of the consent element. + example: 'Email Address' + + ConsentValidationResponse: + type: object + properties: + state: + type: string + description: Current state of the consent. + enum: + - ACTIVE + - REVOKED + - EXPIRED + example: 'ACTIVE' + expiryTime: + type: integer + format: int64 + x-nullable: true + description: Milliseconds since epoch until which the consent is valid. Null if no expiry. + example: 1766383796000 + + AuthorizationRequest: + type: object + properties: + state: + type: string + enum: + - APPROVED + - REJECTED + default: APPROVED + description: Authorization decision. + example: 'APPROVED' + + AuthorizationResponse: + type: object + properties: + userId: + type: string + description: Username of the user who performed this authorization. + example: 'john' + state: + type: string + enum: + - APPROVED + - REJECTED + - REVOKED + - EXPIRED + description: Current state of this authorization. + example: 'APPROVED' + updatedTime: + type: integer + format: int64 + description: Milliseconds since epoch when this authorization was last updated. + example: 1750156200000 + + Error: + type: object + required: + - code + - message + properties: + code: + type: string + example: 'CMT-00000' + message: + type: string + example: 'Some Error Message' + description: + type: string + example: 'Some Error Description' + traceId: + type: string + example: 'e0fbcfeb-3617-43c4-8dd0-7b7d38e13047' + +#-------------------- +# Parameters +#-------------------- +parameters: + consentIdPathParam: + in: path + name: consent-id + description: UUID of the consent receipt. + required: true + type: string + limitQueryParam: + in: query + name: limit + required: false + description: Maximum number of records to return. Default is 10. + type: integer + format: int32 + default: 10 + minimum: 1 + serviceIdQueryParam: + in: query + name: serviceId + required: false + description: Filter consents by service identifier. + type: string + stateQueryParam: + in: query + name: state + required: false + description: Filter consents by state. + type: string + enum: + - PENDING + - ACTIVE + - REJECTED + - REVOKED + - EXPIRED + purposeIdQueryParam: + in: query + name: purposeId + required: false + description: Filter consents by purpose UUID. + type: string + purposeVersionIdQueryParam: + in: query + name: purposeVersionId + required: false + description: Filter consents by specific purpose version UUID. + type: string + afterQueryParam: + in: query + name: after + required: false + description: > + Cursor for forward pagination. Pass the base64-encoded UUID of the last item + received from the previous page to retrieve the next page of results. + type: string + beforeQueryParam: + in: query + name: before + required: false + description: > + Cursor for backward pagination. Pass the base64-encoded UUID of the first item + received from the current page to retrieve the previous page of results. + type: string + filterQueryParam: + in: query + name: filter + required: false + description: > + Filter consents by custom properties using dot notation `properties.`. + Supports 'sw' (starts with), 'co' (contains), 'ew' (ends with), and 'eq' (equals) operations. + Combine multiple conditions with 'and', 'or' logical operators. + Examples: filter=properties.region eq EU + type: string + +#--------------------- +# Security Definitions +#--------------------- +securityDefinitions: + BasicAuth: + type: basic + OAuth2: + type: oauth2 + flow: accessCode + authorizationUrl: https://localhost:9443/oauth2/authorize + tokenUrl: https://localhost:9443/oauth2/token + scopes: + internal_login: Grants access to self-service operations for the authenticated user diff --git a/components/org.wso2.carbon.identity.api.user.consent/pom.xml b/components/org.wso2.carbon.identity.api.user.consent/pom.xml new file mode 100644 index 00000000..573517c6 --- /dev/null +++ b/components/org.wso2.carbon.identity.api.user.consent/pom.xml @@ -0,0 +1,37 @@ + + + + + + identity-api-user + org.wso2.carbon.identity.user.api + 1.5.12-SNAPSHOT + ../../pom.xml + + + 4.0.0 + + org.wso2.carbon.identity.api.user.consent + pom + + org.wso2.carbon.identity.api.user.consent.common + org.wso2.carbon.identity.api.user.consent.v1 + + + diff --git a/pom.xml b/pom.xml index 90fe7b57..87e99392 100644 --- a/pom.xml +++ b/pom.xml @@ -380,6 +380,12 @@ ${fido2.version} provided + + org.wso2.carbon.consent.mgt + org.wso2.carbon.consent.mgt.core + ${carbon.consent.mgt.version} + provided + @@ -550,6 +556,7 @@ 1.4.122 4.1.2 1.1.6 + 2.9.9 @@ -571,6 +578,7 @@ components/org.wso2.carbon.identity.api.user.approval components/org.wso2.carbon.identity.api.user.password components/org.wso2.carbon.identity.api.user.credential + components/org.wso2.carbon.identity.api.user.consent From c34cb4fdcd84c350812daa78f9d72c44f73c7ff2 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Thu, 25 Jun 2026 22:17:45 +0530 Subject: [PATCH 2/7] Fix review comments --- .../v1/model/ConsentCreateResponse.java | 2 +- .../v1/impl/core/UserConsentService.java | 70 +++++++++++++------ .../src/main/resources/consent.yaml | 3 +- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java index d4cea1e2..188ec188 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java @@ -40,7 +40,7 @@ public class ConsentCreateResponse { @XmlEnum(String.class) public enum StateEnum { - @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")); private String value; diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java index dfd21915..f3fef7de 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -232,19 +232,12 @@ public AuthorizationResponse authorizeConsent(String consentId, AuthorizationReq AuthorizationRequest.StateEnum.APPROVED.value(); Receipt receipt = consentManager.getReceiptWithExtendedSchema(consentId); - validateOwnership(receipt, consentId, subjectId); + List authorizations = consentManager.getConsentAuthorizations(consentId); + validateAuthorizer(receipt, consentId, subjectId, authorizations); consentManager.authorizeConsent(consentId, subjectId, authStatus); - List authorizations = consentManager.getConsentAuthorizations(consentId); - ConsentAuthorization userAuth = null; - if (authorizations != null) { - for (ConsentAuthorization auth : authorizations) { - if (subjectId.equals(auth.getUserId())) { - userAuth = auth; - break; - } - } - } + ConsentAuthorization userAuth = findUserAuthorization( + consentManager.getConsentAuthorizations(consentId), subjectId); AuthorizationResponse response = new AuthorizationResponse(); response.setUserId(subjectId); @@ -307,18 +300,55 @@ private List buildPurposeBindings(ConsentInput consen private void validateOwnership(Receipt receipt, String consentId, String subjectId) { if (receipt == null) { - throw new APIError(Response.Status.NOT_FOUND, new ErrorResponse.Builder() - .withCode(ErrorMessages.ERROR_CODE_RECEIPT_ID_INVALID.getCode()) - .withMessage("Consent not found.") - .withDescription("No consent found for ID: " + consentId) - .build()); + throw consentNotFoundError(consentId); } if (!subjectId.equals(receipt.getPiiPrincipalId())) { - throw new APIError(Response.Status.FORBIDDEN, new ErrorResponse.Builder() - .withCode(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getCode()) - .withMessage(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getMessage()) - .build()); + throw userNotAuthorizedError(); + } + } + + private void validateAuthorizer(Receipt receipt, String consentId, String subjectId, + List authorizations) { + + if (receipt == null) { + throw consentNotFoundError(consentId); + } + if (subjectId.equals(receipt.getPiiPrincipalId())) { + return; + } + if (findUserAuthorization(authorizations, subjectId) != null) { + return; } + throw userNotAuthorizedError(); + } + + private ConsentAuthorization findUserAuthorization(List authorizations, String subjectId) { + + if (authorizations != null) { + for (ConsentAuthorization auth : authorizations) { + if (subjectId.equals(auth.getUserId())) { + return auth; + } + } + } + return null; + } + + private APIError consentNotFoundError(String consentId) { + + return new APIError(Response.Status.NOT_FOUND, new ErrorResponse.Builder() + .withCode(ErrorMessages.ERROR_CODE_RECEIPT_ID_INVALID.getCode()) + .withMessage("Consent not found.") + .withDescription("No consent found for ID: " + consentId) + .build()); + } + + private APIError userNotAuthorizedError() { + + return new APIError(Response.Status.FORBIDDEN, new ErrorResponse.Builder() + .withCode(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getCode()) + .withMessage(ErrorMessages.ERROR_CODE_USER_NOT_AUTHORIZED.getMessage()) + .build()); } private ConsentResponse toConsentResponse(Receipt receipt) { diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml index ed62e0c1..bb78c099 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml @@ -390,8 +390,7 @@ definitions: description: Initial state of the consent. enum: - ACTIVE - - REVOKED - - EXPIRED + - REJECTED example: 'ACTIVE' ConsentResponse: From a04138fef8355f4d5a002e9d7a84376e28f751f6 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Thu, 25 Jun 2026 22:22:55 +0530 Subject: [PATCH 3/7] Remove incorrect responses from body --- .../identity/api/user/consent/v1/MeApi.java | 4 +- .../v1/model/ConsentCreateResponse.java | 61 +-------- .../user/consent/v1/model/KeyValuePair.java | 119 ----------------- .../consent/v1/model/PIICategorySummary.java | 121 ------------------ .../consent/v1/impl/MeApiServiceImpl.java | 5 +- .../v1/impl/core/UserConsentService.java | 26 +--- .../src/main/resources/consent.yaml | 9 -- 7 files changed, 9 insertions(+), 336 deletions(-) delete mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java delete mode 100644 components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java index f1ccf6a5..eb75705d 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/MeApi.java @@ -75,14 +75,14 @@ public Response addConsentOfLoggedInUser(@ApiParam(value = "Consent to be create @Path("/consents/{consent-id}/authorize") @Consumes({ "application/json" }) @Produces({ "application/json" }) - @ApiOperation(value = "Authorize a consent", notes = "Authorizes a PENDING consent. The authenticated user must be in the consent's authorization list, returns 403 otherwise. When all required users have approved, the consent transitions to ACTIVE state. If any user rejects, the consent transitions to REJECTED state.
Permission required:
* None
Scope required:
* internal_login ", response = AuthorizationResponse.class, authorizations = { + @ApiOperation(value = "Authorize a consent", notes = "Authorizes a PENDING consent. The authenticated user must be in the consent's authorization list, returns 403 otherwise. When all required users have approved, the consent transitions to ACTIVE state. If any user rejects, the consent transitions to REJECTED state.
Permission required:
* None
Scope required:
* internal_login ", response = Void.class, authorizations = { @Authorization(value = "BasicAuth"), @Authorization(value = "OAuth2", scopes = { }) }, tags={ "me", }) @ApiResponses(value = { - @ApiResponse(code = 200, message = "Authorization recorded successfully.", response = AuthorizationResponse.class), + @ApiResponse(code = 200, message = "Authorization recorded successfully.", response = Void.class), @ApiResponse(code = 400, message = "Invalid input request", response = Error.class), @ApiResponse(code = 401, message = "Unauthorized", response = Void.class), @ApiResponse(code = 403, message = "Resource Forbidden", response = Error.class), diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java index 188ec188..2f89261d 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentCreateResponse.java @@ -36,40 +36,6 @@ public class ConsentCreateResponse { private String subjectId; private String serviceId; -@XmlType(name="StateEnum") -@XmlEnum(String.class) -public enum StateEnum { - - @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")); - - - private String value; - - StateEnum(String v) { - value = v; - } - - public String value() { - return value; - } - - @Override - public String toString() { - return String.valueOf(value); - } - - public static StateEnum fromValue(String value) { - for (StateEnum b : StateEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } -} - - private StateEnum state; - /** * Unique identifier of the created consent. **/ @@ -127,27 +93,6 @@ public void setServiceId(String serviceId) { this.serviceId = serviceId; } - /** - * Initial state of the consent. - **/ - public ConsentCreateResponse state(StateEnum state) { - - this.state = state; - return this; - } - - @ApiModelProperty(example = "ACTIVE", value = "Initial state of the consent.") - @JsonProperty("state") - @Valid - public StateEnum getState() { - return state; - } - public void setState(StateEnum state) { - this.state = state; - } - - - @Override public boolean equals(java.lang.Object o) { @@ -160,13 +105,12 @@ public boolean equals(java.lang.Object o) { ConsentCreateResponse consentCreateResponse = (ConsentCreateResponse) o; return Objects.equals(this.id, consentCreateResponse.id) && Objects.equals(this.subjectId, consentCreateResponse.subjectId) && - Objects.equals(this.serviceId, consentCreateResponse.serviceId) && - Objects.equals(this.state, consentCreateResponse.state); + Objects.equals(this.serviceId, consentCreateResponse.serviceId); } @Override public int hashCode() { - return Objects.hash(id, subjectId, serviceId, state); + return Objects.hash(id, subjectId, serviceId); } @Override @@ -178,7 +122,6 @@ public String toString() { sb.append(" id: ").append(toIndentedString(id)).append("\n"); sb.append(" subjectId: ").append(toIndentedString(subjectId)).append("\n"); sb.append(" serviceId: ").append(toIndentedString(serviceId)).append("\n"); - sb.append(" state: ").append(toIndentedString(state)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java deleted file mode 100644 index 2c01149a..00000000 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/KeyValuePair.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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.user.consent.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 javax.validation.constraints.*; - - -import io.swagger.annotations.*; -import java.util.Objects; -import javax.validation.Valid; -import javax.xml.bind.annotation.*; - -public class KeyValuePair { - - private String key; - private String value; - - /** - **/ - public KeyValuePair key(String key) { - - this.key = key; - return this; - } - - @ApiModelProperty(example = "source", value = "") - @JsonProperty("key") - @Valid - public String getKey() { - return key; - } - public void setKey(String key) { - this.key = key; - } - - /** - **/ - public KeyValuePair value(String value) { - - this.value = value; - return this; - } - - @ApiModelProperty(example = "onboarding-flow", value = "") - @JsonProperty("value") - @Valid - public String getValue() { - return value; - } - public void setValue(String value) { - this.value = value; - } - - - - @Override - public boolean equals(java.lang.Object o) { - - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - KeyValuePair keyValuePair = (KeyValuePair) o; - return Objects.equals(this.key, keyValuePair.key) && - Objects.equals(this.value, keyValuePair.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - - @Override - public String toString() { - - StringBuilder sb = new StringBuilder(); - sb.append("class KeyValuePair {\n"); - - sb.append(" key: ").append(toIndentedString(key)).append("\n"); - sb.append(" value: ").append(toIndentedString(value)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java deleted file mode 100644 index 61468252..00000000 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/PIICategorySummary.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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.user.consent.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 javax.validation.constraints.*; - - -import io.swagger.annotations.*; -import java.util.Objects; -import javax.validation.Valid; -import javax.xml.bind.annotation.*; - -public class PIICategorySummary { - - private String piiCategoryId; - private String piiCategoryName; - - /** - * UUID of the PII category. - **/ - public PIICategorySummary piiCategoryId(String piiCategoryId) { - - this.piiCategoryId = piiCategoryId; - return this; - } - - @ApiModelProperty(example = "c64h0f21-4g3h-6d5c-1h8g-5c3d4e6f7g8h", value = "UUID of the PII category.") - @JsonProperty("piiCategoryId") - @Valid - public String getPiiCategoryId() { - return piiCategoryId; - } - public void setPiiCategoryId(String piiCategoryId) { - this.piiCategoryId = piiCategoryId; - } - - /** - * Name of the PII category. - **/ - public PIICategorySummary piiCategoryName(String piiCategoryName) { - - this.piiCategoryName = piiCategoryName; - return this; - } - - @ApiModelProperty(example = "Email Address", value = "Name of the PII category.") - @JsonProperty("piiCategoryName") - @Valid - public String getPiiCategoryName() { - return piiCategoryName; - } - public void setPiiCategoryName(String piiCategoryName) { - this.piiCategoryName = piiCategoryName; - } - - - - @Override - public boolean equals(java.lang.Object o) { - - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PIICategorySummary piICategorySummary = (PIICategorySummary) o; - return Objects.equals(this.piiCategoryId, piICategorySummary.piiCategoryId) && - Objects.equals(this.piiCategoryName, piICategorySummary.piiCategoryName); - } - - @Override - public int hashCode() { - return Objects.hash(piiCategoryId, piiCategoryName); - } - - @Override - public String toString() { - - StringBuilder sb = new StringBuilder(); - sb.append("class PIICategorySummary {\n"); - - sb.append(" piiCategoryId: ").append(toIndentedString(piiCategoryId)).append("\n"); - sb.append(" piiCategoryName: ").append(toIndentedString(piiCategoryName)).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.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java index 8222bc55..9cf9eeb9 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/MeApiServiceImpl.java @@ -22,7 +22,6 @@ import org.wso2.carbon.identity.api.user.consent.v1.impl.core.UserConsentService; import org.wso2.carbon.identity.api.user.consent.v1.impl.factories.UserConsentServiceFactory; import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationRequest; -import org.wso2.carbon.identity.api.user.consent.v1.model.AuthorizationResponse; import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentCreateResponse; import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentInput; import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentResponse; @@ -55,8 +54,8 @@ public Response addConsentOfLoggedInUser(ConsentInput consent) { @Override public Response authorizeConsentOfLoggedInUser(String consentId, AuthorizationRequest authorization) { - AuthorizationResponse response = userConsentService.authorizeConsent(consentId, authorization); - return Response.ok(response).build(); + userConsentService.authorizeConsent(consentId, authorization); + return Response.ok().build(); } @Override diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java index f3fef7de..723f2642 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -64,7 +64,6 @@ import javax.ws.rs.core.Response; -import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ACTIVE_STATE; import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ErrorMessages.ERROR_CODE_INVALID_FILTER_EXPRESSION; import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.ErrorMessages.ERROR_CODE_INVALID_QUERY_PARAM; import static org.wso2.carbon.consent.mgt.core.constant.ConsentConstants.FilterConstants; @@ -130,13 +129,10 @@ public ConsentCreateResponse addConsent(ConsentInput consentInput) { AddReceiptResponse addReceiptResponse = consentManager.addConsent(receiptInput); - ConsentInput.StateEnum requestedState = consentInput.getState() != null - ? consentInput.getState() : ConsentInput.StateEnum.ACTIVE; ConsentCreateResponse response = new ConsentCreateResponse(); response.setId(addReceiptResponse.getConsentReceiptId()); response.setSubjectId(subjectId); response.setServiceId(consentInput.getServiceId()); - response.setState(ConsentCreateResponse.StateEnum.fromValue(requestedState.value())); return response; } catch (ConsentManagementException e) { throw handleException(e); @@ -222,7 +218,7 @@ public void revokeConsent(String consentId) { } } - public AuthorizationResponse authorizeConsent(String consentId, AuthorizationRequest authorizationRequest) { + public void authorizeConsent(String consentId, AuthorizationRequest authorizationRequest) { String subjectId = ContextLoader.getUsernameFromContext(); @@ -235,20 +231,6 @@ public AuthorizationResponse authorizeConsent(String consentId, AuthorizationReq List authorizations = consentManager.getConsentAuthorizations(consentId); validateAuthorizer(receipt, consentId, subjectId, authorizations); consentManager.authorizeConsent(consentId, subjectId, authStatus); - - ConsentAuthorization userAuth = findUserAuthorization( - consentManager.getConsentAuthorizations(consentId), subjectId); - - AuthorizationResponse response = new AuthorizationResponse(); - response.setUserId(subjectId); - if (userAuth != null) { - response.setState(AuthorizationResponse.StateEnum.fromValue(userAuth.getStatus().name())); - response.setUpdatedTime(userAuth.getUpdatedTime()); - } else { - response.setState(AuthorizationResponse.StateEnum.fromValue(authStatus)); - response.setUpdatedTime(System.currentTimeMillis()); - } - return response; } catch (ConsentManagementException e) { throw handleException(e); } @@ -357,8 +339,7 @@ private ConsentResponse toConsentResponse(Receipt receipt) { dto.setId(receipt.getConsentReceiptId()); dto.setSubjectId(receipt.getPiiPrincipalId()); dto.setLanguage(receipt.getLanguage()); - String state = StringUtils.isNotBlank(receipt.getState()) ? receipt.getState() : ACTIVE_STATE; - dto.setState(ConsentResponse.StateEnum.fromValue(state)); + dto.setState(ConsentResponse.StateEnum.fromValue(receipt.getState())); dto.setTimestamp(receipt.getConsentTimestamp()); dto.setExpiryTime(receipt.getExpiryTime() != null ? receipt.getExpiryTime().getTime() : null); dto.setProperties(receipt.getProperties()); @@ -469,8 +450,7 @@ private ConsentSummary toConsentSummary(Receipt receipt) { ConsentSummary summary = new ConsentSummary(); summary.setId(receipt.getConsentReceiptId()); summary.setTimestamp(receipt.getConsentTimestamp()); - String state = StringUtils.isNotBlank(receipt.getState()) ? receipt.getState() : ACTIVE_STATE; - summary.setState(ConsentSummary.StateEnum.fromValue(state)); + summary.setState(ConsentSummary.StateEnum.fromValue(receipt.getState())); if (receipt.getServices() != null && !receipt.getServices().isEmpty()) { summary.setServiceId(receipt.getServices().get(0).getService()); } diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml index bb78c099..6098479a 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml @@ -188,8 +188,6 @@ paths: responses: 200: description: Authorization recorded successfully. - schema: - $ref: '#/definitions/AuthorizationResponse' 400: $ref: '#/responses/InvalidInput' 401: @@ -385,13 +383,6 @@ definitions: type: string description: Identifier of the service the consent was given for. example: 'sampleApp' - state: - type: string - description: Initial state of the consent. - enum: - - ACTIVE - - REJECTED - example: 'ACTIVE' ConsentResponse: type: object From 22c954eb09143722ab39bf4969473041dcf881a2 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Fri, 26 Jun 2026 07:35:31 +0530 Subject: [PATCH 4/7] Fix review comments --- .../user/consent/v1/model/ConsentSummary.java | 2 +- .../v1/model/ConsentValidationResponse.java | 2 +- .../v1/impl/core/UserConsentService.java | 23 ++++++++++++++----- .../src/main/resources/consent.yaml | 4 ++++ findbugs-exclude-filter.xml | 8 +++++++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java index 3b8fede6..43263c63 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentSummary.java @@ -39,7 +39,7 @@ public class ConsentSummary { @XmlEnum(String.class) public enum StateEnum { - @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + @XmlEnumValue("PENDING") PENDING(String.valueOf("PENDING")), @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); private String value; diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java index 82577cf5..a1b7db40 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/gen/java/org/wso2/carbon/identity/api/user/consent/v1/model/ConsentValidationResponse.java @@ -37,7 +37,7 @@ public class ConsentValidationResponse { @XmlEnum(String.class) public enum StateEnum { - @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); + @XmlEnumValue("PENDING") PENDING(String.valueOf("PENDING")), @XmlEnumValue("ACTIVE") ACTIVE(String.valueOf("ACTIVE")), @XmlEnumValue("REJECTED") REJECTED(String.valueOf("REJECTED")), @XmlEnumValue("REVOKED") REVOKED(String.valueOf("REVOKED")), @XmlEnumValue("EXPIRED") EXPIRED(String.valueOf("EXPIRED")); private String value; diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java index 723f2642..6679f19f 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -163,13 +163,14 @@ public List listConsents(String serviceId, String state, String FilterConstants.FILTER_ATTR_BEFORE.equals(attr)) { continue; } - if (attr == null || !attr.startsWith("properties.") || attr.length() == "properties.".length()) { + if (attr == null || !attr.startsWith("properties.") || attr.length() <= "properties.".length()) { throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, "Only 'properties.' attributes are supported in consent filter. Got: " + attr); } - if (!"eq".equals(node.getOperation())) { + String op = node.getOperation() != null ? node.getOperation().toLowerCase() : ""; + if (!("eq".equals(op) || "sw".equals(op) || "co".equals(op) || "ew".equals(op))) { throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, - "Only 'eq' operation is supported for consent property filter."); + "Only 'eq', 'sw', 'co', and 'ew' operations are supported for consent property filter."); } } @@ -395,7 +396,11 @@ private ConsentPurposeResponse toConsentPurposeResponse(ConsentPurpose consentPu String versionUuid = consentPurpose.getPurposeVersionId(); try { Purpose purpose = consentManager.getPurposeByUuid(consentPurpose.getUuid()); - if (purpose != null) { + if (purpose == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Could not resolve purpose UUID for purposeId: " + consentPurpose.getUuid()); + } + } else { if (StringUtils.isNotBlank(purpose.getUuid())) { dto.setId(purpose.getUuid()); } @@ -430,8 +435,14 @@ private ConsentPurposeResponse toConsentPurposeResponse(ConsentPurpose consentPu element.setName(piiCategoryValidity.getName()); try { PIICategory piiCategory = consentManager.getPIICategoryByUuid(piiCategoryValidity.getUuid()); - if (piiCategory != null) { - element.setId(piiCategory.getUuid()); + if (piiCategory == null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Could not resolve element UUID for elementId: " + piiCategoryValidity.getUuid()); + } + } else { + if (StringUtils.isNotBlank(piiCategory.getUuid())) { + element.setId(piiCategory.getUuid()); + } } } catch (ConsentManagementException e) { if (LOG.isDebugEnabled()) { diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml index 6098479a..09753d13 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml @@ -358,7 +358,9 @@ definitions: type: string description: Current state of the consent. enum: + - PENDING - ACTIVE + - REJECTED - REVOKED - EXPIRED example: 'ACTIVE' @@ -496,7 +498,9 @@ definitions: type: string description: Current state of the consent. enum: + - PENDING - ACTIVE + - REJECTED - REVOKED - EXPIRED example: 'ACTIVE' diff --git a/findbugs-exclude-filter.xml b/findbugs-exclude-filter.xml index 1384955e..ff74a503 100644 --- a/findbugs-exclude-filter.xml +++ b/findbugs-exclude-filter.xml @@ -62,4 +62,12 @@ + + + + + + + + From 8450917d4401ac38801132c64f1131479c4d33a5 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:56:16 +0530 Subject: [PATCH 5/7] Add upperbound to limit --- .../user/consent/v1/impl/core/UserConsentService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java index 6679f19f..fbb03e17 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -53,6 +53,7 @@ import org.wso2.carbon.identity.api.user.consent.v1.model.ConsentedElement; import org.wso2.carbon.identity.api.user.consent.v1.model.ElementRef; import org.wso2.carbon.identity.core.model.ExpressionNode; +import org.wso2.carbon.identity.core.util.IdentityUtil; import java.sql.Timestamp; import java.util.ArrayList; @@ -150,6 +151,14 @@ public List listConsents(String serviceId, String state, String if (resolvedLimit <= 0) { throw handleClientException(ERROR_CODE_INVALID_QUERY_PARAM, String.valueOf(resolvedLimit)); } + int maximumItemPerPage = IdentityUtil.getMaximumItemPerPage(); + if (resolvedLimit > maximumItemPerPage) { + if (LOG.isDebugEnabled()) { + LOG.debug("Given limit exceeds the maximum limit. Therefore the configured maximum limit: " + + maximumItemPerPage + " is set as the limit."); + } + resolvedLimit = maximumItemPerPage; + } if (StringUtils.isNotBlank(before) && StringUtils.isNotBlank(after)) { throw handleClientException(ERROR_CODE_INVALID_QUERY_PARAM, From 0e8d0203b17f636dcafa82175c1c1d6300a4fc79 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Fri, 26 Jun 2026 10:49:56 +0530 Subject: [PATCH 6/7] Bump version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 87e99392..676b1a07 100644 --- a/pom.xml +++ b/pom.xml @@ -556,7 +556,7 @@ 1.4.122 4.1.2 1.1.6 - 2.9.9 + 2.9.10 From 320236a4cb11e4136df422515b3c9bdba04cb7d4 Mon Sep 17 00:00:00 2001 From: Udara Pathum <46132469+hwupathum@users.noreply.github.com> Date: Fri, 26 Jun 2026 20:21:01 +0530 Subject: [PATCH 7/7] Fix review comments --- .../api/user/consent/v1/impl/core/UserConsentService.java | 3 ++- .../src/main/resources/consent.yaml | 3 ++- findbugs-exclude-filter.xml | 1 - 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java index fbb03e17..6162faea 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/java/org/wso2/carbon/identity/api/user/consent/v1/impl/core/UserConsentService.java @@ -60,6 +60,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -176,7 +177,7 @@ public List listConsents(String serviceId, String state, String throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, "Only 'properties.' attributes are supported in consent filter. Got: " + attr); } - String op = node.getOperation() != null ? node.getOperation().toLowerCase() : ""; + String op = node.getOperation() != null ? node.getOperation().toLowerCase(Locale.ROOT) : ""; if (!("eq".equals(op) || "sw".equals(op) || "co".equals(op) || "ew".equals(op))) { throw handleClientException(ERROR_CODE_INVALID_FILTER_EXPRESSION, "Only 'eq', 'sw', 'co', and 'ew' operations are supported for consent property filter."); diff --git a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml index 09753d13..8d1a2313 100644 --- a/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml +++ b/components/org.wso2.carbon.identity.api.user.consent/org.wso2.carbon.identity.api.user.consent.v1/src/main/resources/consent.yaml @@ -165,7 +165,8 @@ paths: - me summary: Authorize a consent description: > - Authorizes a PENDING consent. The authenticated user must be in the consent's authorization list, returns 403 otherwise. + Authorizes a PENDING consent. The authenticated user must either be the subject of the consent, + or be listed in the consent's authorization list; returns 403 otherwise. When all required users have approved, the consent transitions to ACTIVE state. If any user rejects, the consent transitions to REJECTED state.
Permission required:
diff --git a/findbugs-exclude-filter.xml b/findbugs-exclude-filter.xml index ff74a503..e1d112cf 100644 --- a/findbugs-exclude-filter.xml +++ b/findbugs-exclude-filter.xml @@ -67,7 +67,6 @@ -