Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2b99e3d
Introducing User Sharing APIs V2
BimsaraBodaragama Dec 8, 2025
6658088
Update the year of the license header in gen files.
BimsaraBodaragama Dec 11, 2025
95120a2
Update API contract - Remove immediate support from general share.
BimsaraBodaragama Dec 12, 2025
10deb85
Comment openapi-generator-plugin.
BimsaraBodaragama Dec 12, 2025
6a3c072
Implement the api core logic.
BimsaraBodaragama Dec 17, 2025
2545e70
Add debug logs to the starting of each end points.
BimsaraBodaragama Dec 17, 2025
a3b625b
Update snapshot version of user sharing v2
BimsaraBodaragama Dec 18, 2025
381eb80
Address wso2-engineering bot comments.
BimsaraBodaragama Dec 18, 2025
533154f
Format.
BimsaraBodaragama Dec 18, 2025
b6bdeef
Address comments of copilot
BimsaraBodaragama Dec 18, 2025
18f4dc9
Update pom.
BimsaraBodaragama Dec 18, 2025
795deca
Update pom version.
BimsaraBodaragama Dec 18, 2025
e8db4ea
Address code-rabbit comments.
BimsaraBodaragama Dec 19, 2025
64a0a4c
Address code-rabbit comments -2.
BimsaraBodaragama Dec 19, 2025
1bc3ef4
Address code-rabbit comments -3.
BimsaraBodaragama Dec 19, 2025
2ddaf94
Address code-rabbit comments -4.
BimsaraBodaragama Dec 19, 2025
936483d
Address code-rabbit comments -5.
BimsaraBodaragama Dec 22, 2025
a848cd5
Address code-rabbit comments -6.
BimsaraBodaragama Dec 22, 2025
b4b2dd4
Address code-rabbit comments -7.
BimsaraBodaragama Dec 22, 2025
512480a
Address code-rabbit comments -8.
BimsaraBodaragama Dec 22, 2025
d8c4bf5
Address code-rabbit comments -9.
BimsaraBodaragama Dec 22, 2025
693f836
Merge branch 'master' into user-sharing-v2
BimsaraBodaragama Jan 17, 2026
270811b
Updating getUserSharedOrganizations business logic to handle pagination.
BimsaraBodaragama Jan 17, 2026
250a505
Merge remote-tracking branch 'origin/user-sharing-v2' into user-shari…
BimsaraBodaragama Jan 17, 2026
d66d784
Update pom version and checkstyle.
BimsaraBodaragama Jan 17, 2026
2573650
Update pom version and address coderabbit's suggestions.
BimsaraBodaragama Jan 17, 2026
c15bab8
Add organization metadata fields to UserSharedOrganization response m…
BimsaraBodaragama Jan 19, 2026
6f8510d
Bug fixing - 1
BimsaraBodaragama Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (c) 2025, 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.wso2.carbon.identity.server.api</groupId>
<artifactId>org.wso2.carbon.identity.api.server.organization.user.sharing.management</artifactId>
<version>1.3.226-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2</artifactId>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-service-description</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</exclusion>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.server.api</groupId>
<artifactId>org.wso2.carbon.identity.api.server.organization.user.sharing.management.common</artifactId>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.server.api</groupId>
<artifactId>org.wso2.carbon.identity.api.server.common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.organization.management</groupId>
<artifactId>org.wso2.carbon.identity.organization.management.organization.user.sharing</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wso2.carbon.identity.organization.management</groupId>
<artifactId>org.wso2.carbon.identity.organization.resource.sharing.policy.management</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!--<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>4.1.2</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/organization-user-share-v2.yaml</inputSpec>
<generatorName>org.wso2.carbon.codegen.CxfWso2Generator</generatorName>
<configOptions>
<sourceFolder>src/gen/java</sourceFolder>
<apiPackage>org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2</apiPackage>
<modelPackage>org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model</modelPackage>
<packageName>org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2</packageName>
<dateLibrary>java8</dateLibrary>
<hideGenerationTimestamp>true</hideGenerationTimestamp>
</configOptions>
<output>.</output>
<skipOverwrite>false</skipOverwrite>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>cxf-wso2-openapi-generator</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</plugin>-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/gen/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2;

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.server.organization.user.sharing.management.v2.factories.UsersApiServiceFactory;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.Error;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.ProcessSuccessResponse;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserShareAllRequestBody;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserShareSelectedRequestBody;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserSharedOrganizationsResponse;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserSharingPatchRequest;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserUnshareAllRequestBody;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.model.UserUnshareSelectedRequestBody;
import org.wso2.carbon.identity.api.server.organization.user.sharing.management.v2.UsersApiService;

import javax.validation.Valid;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import io.swagger.annotations.*;

import javax.validation.constraints.*;

@Path("/users")
@Api(description = "The users API")

public class UsersApi {

private final UsersApiService delegate;

public UsersApi() {

this.delegate = UsersApiServiceFactory.getUsersApi();
}

@Valid
@GET
@Path("/{userId}/share")

@Produces({ "application/json" })
@ApiOperation(value = "List organizations where the user has shared access", notes = "Retrieve the list of organizations where the specified user has shared access, including per-organization effective role assignments. This follows the same pattern as **`GET /applications/{applicationId}/share`**. **Scope required:** `internal_user_shared_access_view`", response = UserSharedOrganizationsResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Accessible Organizations", })
@ApiResponses(value = {
@ApiResponse(code = 200, message = "Successful response with the user's shared organizations.", response = UserSharedOrganizationsResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response getUserSharedOrganizations(@ApiParam(value = "The ID of the user.",required=true) @PathParam("userId") String userId, @Valid@ApiParam(value = "Base64 encoded cursor for forward pagination.") @QueryParam("after") String after, @Valid@ApiParam(value = "Base64 encoded cursor for backward pagination.") @QueryParam("before") String before, @Valid@ApiParam(value = "Maximum number of records to return.") @QueryParam("limit") Integer limit, @Valid@ApiParam(value = "Condition to filter the retrieval of records. Supports operations like `sw`, `co`, `ew`, and `eq` depending on implementation.") @QueryParam("filter") String filter, @Valid@ApiParam(value = "Whether to include shared organizations recursively in the hierarchy.") @QueryParam("recursive") Boolean recursive) {

return delegate.getUserSharedOrganizations(userId, after, before, limit, filter, recursive );
}

@Valid
@PATCH
@Path("/share")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Perform incremental role assignment operations for already shared users", notes = "Perform **incremental updates** to the role assignments of already shared users. This endpoint supports **SCIM-like PATCH semantics**: - `op: \"add\"` → assign additional roles. - `op: \"remove\"` → remove specific roles. > **Note:** > Only **role assignments** are managed here. Sharing/unsharing organizations > is handled via `/users/share`, `/users/share-with-all`, `/users/unshare`, > and `/users/unshare-with-all`. **Scope required:** `internal_user_share`", response = ProcessSuccessResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Sharing", })
@ApiResponses(value = {
@ApiResponse(code = 202, message = "Role assignment patch operation processed successfully.", response = ProcessSuccessResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 404, message = "Not Found", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response patchUserSharing(@ApiParam(value = "" ,required=true) @Valid UserSharingPatchRequest userSharingPatchRequest) {

return delegate.patchUserSharing(userSharingPatchRequest );
}

@Valid
@POST
@Path("/share-with-all")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Share users with all organizations", notes = "Share one or more users with **all organizations**, or all immediate child organizations, according to the specified policy. A common `roleAssignment` can be provided to assign roles in all matching organizations. This endpoint is treated as a **processing function** and responds with `202 Accepted`. **Scope required:** `internal_user_share`", response = ProcessSuccessResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Sharing", })
@ApiResponses(value = {
@ApiResponse(code = 202, message = "Share-all process triggered successfully.", response = ProcessSuccessResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response shareUsersWithAll(@ApiParam(value = "" ,required=true) @Valid UserShareAllRequestBody userShareAllRequestBody) {

return delegate.shareUsersWithAll(userShareAllRequestBody );
}

@Valid
@POST
@Path("/share")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Share users with specific organizations", notes = "Share one or more users with a selected set of organizations, optionally assigning roles to each shared user in each target organization. This endpoint is treated as a **processing function**: it triggers a sharing process and responds with `202 Accepted`. **Scope required:** `internal_user_share`", response = ProcessSuccessResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Sharing", })
@ApiResponses(value = {
@ApiResponse(code = 202, message = "User sharing process triggered successfully.", response = ProcessSuccessResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response shareUsersWithSelected(@ApiParam(value = "" ,required=true) @Valid UserShareSelectedRequestBody userShareSelectedRequestBody) {

return delegate.shareUsersWithSelected(userShareSelectedRequestBody );
}

@Valid
@POST
@Path("/unshare-with-all")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Unshare users from all organizations", notes = "Completely remove all shared access for one or more users from **all organizations**. This endpoint is treated as a **processing function** and responds with `202 Accepted`. **Scope required:** `internal_user_unshare`", response = ProcessSuccessResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Sharing", })
@ApiResponses(value = {
@ApiResponse(code = 202, message = "Unshare-all process triggered successfully.", response = ProcessSuccessResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response unshareUsersFromAll(@ApiParam(value = "" ,required=true) @Valid UserUnshareAllRequestBody userUnshareAllRequestBody) {

return delegate.unshareUsersFromAll(userUnshareAllRequestBody );
}

@Valid
@POST
@Path("/unshare")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@ApiOperation(value = "Unshare users from specific organizations", notes = "Unshare one or more users from a selected set of organizations. > **Note:** > This only removes the user from the specified organizations. If the user > was shared with a parent org plus its children via a broader policy, > you must explicitly include all relevant organization IDs when unsharing. This endpoint is treated as a **processing function** and responds with `202 Accepted`. **Scope required:** `internal_user_unshare`", response = ProcessSuccessResponse.class, authorizations = {
@Authorization(value = "BasicAuth"),
@Authorization(value = "OAuth2", scopes = {

})
}, tags={ "User Sharing" })
@ApiResponses(value = {
@ApiResponse(code = 202, message = "Unsharing process triggered successfully.", response = ProcessSuccessResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = Error.class),
@ApiResponse(code = 500, message = "Internal Server Error", response = Error.class)
})
public Response unshareUsersFromSelected(@ApiParam(value = "" ,required=true) @Valid UserUnshareSelectedRequestBody userUnshareSelectedRequestBody) {

return delegate.unshareUsersFromSelected(userUnshareSelectedRequestBody );
}

}
Loading