Skip to content

Add file-based import and export endpoints for OIDC scopes#1053

Open
RovinKYK wants to merge 3 commits intowso2:masterfrom
RovinKYK:ctl_improve_2
Open

Add file-based import and export endpoints for OIDC scopes#1053
RovinKYK wants to merge 3 commits intowso2:masterfrom
RovinKYK:ctl_improve_2

Conversation

@RovinKYK
Copy link
Contributor

@RovinKYK RovinKYK commented Feb 2, 2026

Purpose

This PR introduces file-based configuration management capabilities for OIDC scopes. This enhancement enables administrators to export, import, and update OIDC scope configurations using standard configuration file formats (XML, YAML, JSON), facilitating easier scope management, backup, and migration workflows.

Related to https://github.com/wso2-enterprise/iam-product-management/issues/662

Goals

  • Enable export of OIDC scope configurations to files for backup and migration purposes
  • Support import of OIDC scope configurations from files to simplify scope creation and restoration
  • Allow updating existing OIDC scopes by importing configuration files
  • Provide a consistent file-based configuration approach aligned with other identity management components

Approach

1. New API Endpoints:

  • Added GET /oidc/scopes/{id}/export endpoint to export a scope in the requested format (XML, YAML, or JSON) based on the Accept header
  • Added POST /oidc/scopes/import endpoint to create a new scope from an uploaded configuration file
  • Added PUT /oidc/scopes/{id}/import endpoint to update an existing scope from an uploaded configuration file

2. Implementation Details:

  • Introduced ScopeConfiguration class as a dedicated model for file serialization with XML annotations
  • Leveraged existing FileSerializationUtil infrastructure for consistent serialization across formats
  • Configured YAML serialization to use block style for better readability
  • Added proper error handling with new error codes
  • Implemented multipart/form-data file upload handling
  • Added appropriate HTTP headers for file downloads (Content-Disposition, Cache-Control)

User stories

Summary of user stories addressed by this change>

Developer Checklist (Mandatory)

  • Complete the Developer Checklist in the related product-is issue to track any behavioral change or migration impact.

Release note

Brief description of the new feature or bug fix as it will appear in the release notes

Documentation

Link(s) to product documentation that addresses the changes of this PR. If no doc impact, enter “N/A” plus brief explanation of why there’s no doc impact

Training

Link to the PR for changes to the training content in https://github.com/wso2/WSO2-Training, if applicable

Certification

Type “Sent” when you have provided new/updated certification questions, plus four answers for each question (correct answer highlighted in bold), based on this change. Certification questions/answers should be sent to certification@wso2.com and NOT pasted in this PR. If there is no impact on certification exams, type “N/A” and explain why.

Marketing

Link to drafts of marketing content that will describe and promote this feature, including product page changes, technical articles, blog posts, videos, etc., if applicable

Automation tests

  • Unit tests

    Code coverage information

  • Integration tests

    Details about the test cases and coverage

Security checks

Samples

Provide high-level details about the samples related to this feature

Related PRs

List any other related PRs

Migrations (if applicable)

Describe migration steps and platforms on which migration has been tested

Test environment

List all JDK versions, operating systems, databases, and browser/versions on which this feature/fix was tested

Learning

Describe the research phase and any blog posts, patterns, libraries, or add-ons you used to solve the problem.

Summary by CodeRabbit

  • New Features
    • Export OIDC scope configurations to files in multiple formats (YAML, JSON, XML)
    • Import new OIDC scopes from uploaded configuration files with automatic creation
    • Update existing OIDC scopes by uploading new configuration files
    • Enhanced multipart file handling for streamlined scope management workflows

Copilot AI review requested due to automatic review settings February 2, 2026 04:25
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Walkthrough

Adds file-based import/export/update for OIDC scopes: new API endpoints, service methods, model for file-backed scope configuration, and three new error codes with descriptions; updates OpenAPI spec and REST implementation to handle multipart file uploads and file downloads.

Changes

Cohort / File(s) Summary
Constants
components/org.wso2.carbon.identity.api.server.oidc.scope.management/.../OidcScopeConstants.java
Added three server error enum constants (ERROR_CODE_ERROR_EXPORTING_SCOPE, ERROR_CODE_ERROR_IMPORTING_SCOPE, ERROR_CODE_ERROR_UPDATING_SCOPE), a new description field, a 3-arg constructor, and getDescription(); adjusted punctuation to allow new constants.
Service layer
components/.../v1/.../OidcScopeManagementService.java
Added public methods exportScopeToFile(String,String), importScopeFromFile(InputStream,Attachment), updateScopeFromFile(String,InputStream,Attachment) plus helpers to serialize/deserialize Scope ↔ file formats and exception-handling overloads.
REST implementation
components/.../v1/.../OidcApiServiceImpl.java
Added endpoints exportScopeToFile(String, String), importScopeFromFile(InputStream, Attachment), updateScopeFromFile(String, InputStream, Attachment); set response headers for downloads and handle multipart uploads.
Model
components/.../v1/.../model/ScopeConfiguration.java
New JAXB-annotated ScopeConfiguration class with constructors, getters/setters, toScope() and a constructor from Scope; defensively copies claims list.
OpenAPI spec
components/.../v1/.../resources/oidc-scope-management.yaml
Added endpoints /oidc/scopes/import (POST), /oidc/scopes/{id}/export (GET), /oidc/scopes/{id}/import (PUT); added FileUpload schema and response/content variations for JSON/XML/YAML exports.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant API as OidcApiServiceImpl
    participant Service as OidcScopeManagementService
    participant Store as ScopeStore

    Client->>API: POST /oidc/scopes/import (multipart file)
    API->>Service: importScopeFromFile(fileStream, attachment)
    Service->>Service: parse file -> ScopeConfiguration -> Scope
    Service->>Store: persist new Scope
    Store-->>Service: created scope name
    Service-->>API: created scope name
    API-->>Client: 201 Created (Location header)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibble bytes and bind them tight,

Scopes hop in YAML, JSON, light.
Import, export — I twirl with glee,
A rabbit's stamp on CI/CD tree. 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description is incomplete. While it has Purpose and Goals sections filled, most required sections from the template remain unfilled or have only placeholder text. Complete the mandatory Developer Checklist, Release note, Documentation, and Security checks sections. Address User stories, Training, Certification, Marketing, Automation tests, Samples, Migrations, Test environment, and Learning sections with substantive content or explicit N/A with justification.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding file-based import and export endpoints for OIDC scopes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@wso2-engineering wso2-engineering bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Agent Log Improvement Checklist

⚠️ Warning: AI-Generated Review Comments

  • The log-related comments and suggestions in this review were generated by an AI tool to assist with identifying potential improvements. Purpose of reviewing the code for log improvements is to improve the troubleshooting capabilities of our products.
  • Please make sure to manually review and validate all suggestions before applying any changes. Not every code suggestion would make sense or add value to our purpose. Therefore, you have the freedom to decide which of the suggestions are helpful.

✅ Before merging this pull request:

  • Review all AI-generated comments for accuracy and relevance.
  • Complete and verify the table below. We need your feedback to measure the accuracy of these suggestions and the value they add. If you are rejecting a certain code suggestion, please mention the reason briefly in the suggestion for us to capture it.
Comment Accepted (Y/N) Reason
#### Log Improvement Suggestion No: 1
#### Log Improvement Suggestion No: 2
#### Log Improvement Suggestion No: 3
#### Log Improvement Suggestion No: 4
#### Log Improvement Suggestion No: 5
#### Log Improvement Suggestion No: 6

@RovinKYK RovinKYK changed the title Ctl improve 2 Add file-based import and export endpoints for OIDC scopes Feb 2, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In
`@components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.common/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/common/OidcScopeConstants.java`:
- Line 31: INVALID_REQUEST and ERROR_CODE_INVALID_INPUT use confusingly similar
numeric codes ("OAUTH-60001" vs "60001"); update ERROR_CODE_INVALID_INPUT
(constant name ERROR_CODE_INVALID_INPUT) to use a clearly distinct code (e.g.,
change its value to "OAUTH-60002" or "60002" with an explicit different prefix)
or reuse INVALID_REQUEST's code where appropriate so codes are not
ambiguous—modify the constant value in OidcScopeConstants accordingly and ensure
any usages reflect the new distinct code.

In
`@components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.v1/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/v1/core/OidcScopeManagementService.java`:
- Around line 230-236: The code constructs a ScopeUpdateRequest from the
uploaded scope but always calls updateScope(scopeName, updateRequest) without
checking whether the uploaded scope's name (e.g., scope.getName()) matches the
path variable scopeName; add a guard in OidcScopeManagementService to compare
scopeName with scope.getName() and throw a BadRequest/Conflict (HTTP 400/409) if
they differ, otherwise proceed to call updateScope(scopeName, updateRequest);
ensure the validation occurs before creating/using ScopeUpdateRequest so
mismatched uploads are rejected with a clear error.
- Around line 262-275: In getScopeFromFile, validate that fileInputStream and
fileDetail (and fileDetail.getDataHandler()) are not null before using them; if
any are null, throw an IdentityOAuthClientException indicating a bad client
request (e.g., "Missing or invalid upload file") so it returns a client error
instead of NPE/500; after validation proceed to build the FileContent and call
generateModelFromFile as before, and keep the existing try/catch/finally for IO
handling.
- Around line 166-168: Replace the UnsupportedOperationException in
OidcScopeManagementService with API error handling that returns HTTP 400 for
missing/invalid fileType: detect the blank fileType (the current
StringUtils.isBlank(fileType) check) and throw/return an API error representing
Bad Request (HTTP 400) with a clear message like "No valid media type found" and
appropriate error code instead of letting it surface as a 500; use the project’s
API error helper/exception builder (the APIError/BadRequest-style helper used
elsewhere in the service layer) so the controller returns a 400 response.

In
`@components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.v1/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/v1/impl/OidcApiServiceImpl.java`:
- Around line 69-82: The filename from FileContent (fileContent.getFileName())
is used directly in the Content-Disposition header in exportScopeToFile, which
allows CR/LF or quote injection; sanitize/normalize the filename before using
it: remove or replace CR (\r), LF (\n) and both single and double quotes, and
fall back to a safe default (e.g., "scope-export.txt") if the result is empty;
then use the sanitized value when building the Content-Disposition header so
exportScopeToFile never inserts raw filename characters into the response
header.
🧹 Nitpick comments (6)
components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.common/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/common/OidcScopeConstants.java (1)

36-44: Naming convention inconsistency with existing entries.

The new enum constants use an ERROR_CODE_ prefix (e.g., ERROR_CODE_ERROR_EXPORTING_SCOPE), while existing entries like INVALID_REQUEST, ERROR_CONFLICT_REQUEST, and SCOPE_NOT_FOUND do not follow this pattern. Additionally, ERROR_CODE_ERROR_EXPORTING_SCOPE contains "ERROR" twice, which is redundant.

For consistency, consider aligning with the existing naming style:

♻️ Suggested naming alignment
-        ERROR_CODE_ERROR_EXPORTING_SCOPE("65001",
+        ERROR_EXPORTING_SCOPE("65001",
                 "Unable to export the OIDC scope configurations."),
-        ERROR_CODE_ERROR_IMPORTING_SCOPE("65002",
+        ERROR_IMPORTING_SCOPE("65002",
                 "Unable to import the OIDC scope configurations."),
-        ERROR_CODE_ERROR_UPDATING_SCOPE("65003",
+        ERROR_UPDATING_SCOPE("65003",
                 "Unable to update the OIDC scope configurations."),

         // Client Errors - 600xx
-        ERROR_CODE_INVALID_INPUT("60001", "Invalid Input");
+        INVALID_INPUT("60001", "Invalid Input");
components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.v1/src/main/resources/oidc-scope-management.yaml (4)

93-131: Consider adding 415 Unsupported Media Type response.

The endpoint accepts XML, YAML, or JSON files but doesn't specify a 415 response for unsupported file formats. This would improve API clarity when clients upload files with unsupported formats.

📝 Suggested addition
          $ref: '#/components/responses/Conflict'
+       415:
+         description: Unsupported file format.
+         content:
+           application/json:
+             schema:
+               $ref: '#/components/schemas/ErrorResponse'
          $ref: '#/components/responses/ServerError'

260-291: Response content types don't cover all Accept header variants.

The Accept header enum includes text/yaml, text/xml, and text/json, but the response content section only defines application/json, application/xml, and application/yaml. Clients sending text/* variants won't see matching response content definitions.

Either align the response content types with all accepted variants, or simplify the Accept enum to only include the application/* variants that are actually returned.

📝 Option 1: Simplify Accept header enum
          schema:
            type: string
            enum:
              - application/json
              - application/xml
              - application/yaml
-             - application/x-yaml
-             - text/yaml
-             - text/xml
-             - text/json
            default: application/yaml

302-348: Clarify behavior when path {id} differs from scope name in file.

The endpoint updates scope {id} from an imported file. If the file contains a different scope name than the path parameter, the expected behavior is ambiguous. Consider documenting whether:

  • The path {id} takes precedence (file's name field is ignored)
  • A mismatch results in a 400 error
  • The scope is renamed

This clarification in the description would prevent unexpected behavior for API consumers.


388-396: Pre-existing issue: Header name should be Location, not Set-Cookie.

The Created response component uses Set-Cookie as the header name, but the description indicates it should be the location of the newly created scope. The new import endpoint correctly uses Location (line 118). Consider fixing this for consistency.

📝 Suggested fix
    Created:
      description: Created
      headers:
-       Set-Cookie:
+       Location:
          description: Location of the newly created scope
          schema:
            type: string
            format: uri
            example: https://apis.is.com/t/wso2.com/api/server/v1/oidc/scopes/Scope1
components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.v1/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/v1/model/ScopeConfiguration.java (1)

104-109: Defensively copy claims in setter/getter to prevent external mutation.

Right now external callers can mutate internal state or pass null. Consider normalizing to an internal copy and returning copies.

Suggested diff
 public List<String> getClaims() {
-    return claims;
+    return claims == null ? new ArrayList<>() : new ArrayList<>(claims);
 }

 public void setClaims(List<String> claims) {
-    this.claims = claims;
+    this.claims = claims == null ? new ArrayList<>() : new ArrayList<>(claims);
 }

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds file-based import and export capabilities for OIDC scopes, aligned with existing application, IDP, and userstore import/export patterns and the shared file serialization utilities.

Changes:

  • Extends the OIDC scope OpenAPI definition with new /oidc/scopes/import, /oidc/scopes/{id}/export, and /oidc/scopes/{id}/import operations and a FileUpload schema for multipart file handling.
  • Implements core service logic to serialize/deserialize OIDC scopes to/from XML, JSON, and YAML using the common FileSerializationUtil, plus a dedicated ScopeConfiguration model for file representation.
  • Wires the new operations through the generated JAX-RS API (OidcApi, OidcApiService) and the concrete implementation (OidcApiServiceImpl), and adds new error codes for import/export/update failures.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
.../oidc-scope-management.yaml Adds import/export endpoints and the FileUpload schema for OIDC scopes, defining the HTTP contracts for file-based operations.
.../model/ScopeConfiguration.java Introduces a JAXB-annotated DTO used as the on-disk representation of scope configurations for serialization/deserialization.
.../impl/OidcApiServiceImpl.java Implements the new API methods to delegate to the core service and construct appropriate Response objects (headers, content type, body) for import/export.
.../core/OidcScopeManagementService.java Implements the core logic to export scopes to FileContent, import scopes from uploaded files, update existing scopes from files, and handle related errors via the shared file-serialization utilities.
.../gen/.../model/Scope.java Cleans up XML binding imports in the generated Scope model, keeping it as a pure JSON-validation DTO used throughout the scope APIs.
.../gen/.../model/FileUpload.java Adds a generated FileUpload model with validation for the uploaded file, matching the new OpenAPI FileUpload schema.
.../gen/.../OidcApiService.java Extends the generated service interface with methods for exporting scopes to files and importing/updating scopes from uploaded files.
.../gen/.../OidcApi.java Adds the new JAX-RS endpoints (paths, verbs, Swagger metadata, multipart parameters) for file-based scope import/export/update, delegating to OidcApiService.
.../common/OidcScopeConstants.java Introduces new error codes/messages for failures during scope export, import, and update, used by the core service for structured API errors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.common/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/common/OidcScopeConstants.java`:
- Around line 48-61: Make the enum's description field final to ensure
immutability: change the ErrorMessage enum's "description" field to final and
update the two constructors so the two-argument constructor delegates to the
three-argument one (or explicitly sets this.description = null) to guarantee a
defined value; modify ErrorMessage(String code, String message) to call
ErrorMessage(code, message, null) (or set description = null) and leave
ErrorMessage(String code, String message, String description) assigning the
final field, and ensure any getDescription() continues to read the final
description field.
🧹 Nitpick comments (1)
components/org.wso2.carbon.identity.api.server.oidc.scope.management/org.wso2.carbon.identity.api.server.oidc.scope.management.v1/src/main/java/org/wso2/carbon/identity/api/server/oidc/scope/management/v1/core/OidcScopeManagementService.java (1)

372-380: Minor formatting inconsistency.

The closing brace at line 380 has 3 spaces of indentation instead of 4, which is inconsistent with the rest of the file.

Suggested fix
     private APIError handleException(Response.Status status, OidcScopeConstants.ErrorMessage errorMessage) {
 
         ErrorResponse errorResponse = new ErrorResponse.Builder()
                 .withCode(errorMessage.getCode())
                 .withMessage(errorMessage.getMessage())
                 .withDescription(errorMessage.getDescription())
                 .build(LOG, errorMessage.getMessage());
         return new APIError(status, errorResponse);
-   }
+    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants