feat(scim): Restructure SCIM package into discovery/users/groups modules with shared response and filter utilities - #4842
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
0ffc00d to
fe25dfe
Compare
…rtise pagination support Allow POST /Users to omit the ThunderID extension schema URN when the request carries only core SCIM attributes. CreateUser then defaults to the sole configured user type via resolveDefaultEntityTypeName, erroring if zero or more than one type is configured. ReplaceUser (and Me PUT) still require the extension URN explicitly; no fallback on update. Also advertise the RFC 9865 pagination attribute on GET /ServiceProviderConfig: index-based pagination supported, cursor based pagination not implemented.
…ch,Me and Discovery endpoints
d6789dc to
e3d242b
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
45f6c60 to
c27eb6e
Compare
Split the generic handler.go/service.go into discovery_handler.go and discovery_service.go, and rename group_*.go to groups_*.go to match the existing users_*.go convention. Extract shared response/error handling into response.go and filter parsing into scim_filter.go so all three resource handlers use the same code paths instead of duplicating them. Normalize license headers across the SCIM package and its integration tests from the WSO2 Apache boilerplate to the ThunderID SPDX header. Fix bugs found while doing the split: - getCredentialKeys silently swallowed entity-type lookup failures and returned an empty credential set instead of surfacing an error - filter parse errors on GET /Users and POST /Users/.search bypassed the SCIM error/i18n pipeline with a hardcoded, untranslated response - unsupported SCIM route stubs were registered without CORS middleware - /Me GET and PUT ignored the attributes/excludedAttributes query parameters and always returned the full resource Rename scimService/scimHandler to scimDiscoveryService/scimDiscoveryHandler to match the discovery_*.go file names, and drop the unused userService dependency from the discovery service, since only scimUsersService needs it. Regenerate api/scim.yaml to reflect the above.
c27eb6e to
6a0cbd2
Compare
Purpose
This PR restructures the
backend/internal/scimpackage from a small set of generic, monolithic files into resource-scoped modules (discovery, users, groups) that share common response/error/filter utilities. It also normalizes license headers across the whole SCIM package (main + integration tests) from the WSO2 Apache boilerplate to the ThunderID SPDX header, and fixes several bugs found while doing this split: swallowed credential-lookup errors,filtererrors bypassing the SCIM error/i18n pipeline, CORS not being applied to unsupported-route handlers, and/MeGET/PUT ignoringattributes/excludedAttributes.SCIM wire-level behavior is unchanged: HTTP paths, methods, status codes, and JSON payload shapes stay the same for existing supported operations. The breaking surface is internal Go package structure (file layout, renamed/unexported functions, changed function signatures) plus stricter server-side error handling in a couple of edge cases.
🔧 Summary of Breaking Changes
1. License header normalization
All 44 files under
backend/internal/scim/andtests/integration/scim/had their header changed from the WSO2 Apache License boilerplate to:2. File restructuring
handler.gosplit intodiscovery_handler.go(ServiceProviderConfig/Schemas/ResourceTypes handlers) andresponse.go(shared response/error helpers).handler_test.go→discovery_handler_test.go; newresponse_test.goadded.service.go→discovery_service.go;service_test.go→discovery_service_test.go.group_model.go→groups_model.go,group_resource.go→groups_resource.go,group_resource_test.go→groups_resource_test.go,group_service.go→groups_service.go,group_service_test.go→groups_service_test.go,group_handler_test.go→groups_handler_test.go.group_handler.goremoved, replaced bygroups_handler.go.group_patch_validator.go/group_patch_validator_test.goremoved; their logic merged intoscim_validator.go/scim_validator_test.go.scim_filter.go/scim_filter_test.go— filter parsing extracted out ofusers_handler.go.group*→groups*where applicable, for naming consistency with the existingusers_*.gofiles.scimService/scimHandlerrenamed toscimDiscoveryService/scimDiscoveryHandler(and their constructorsnewSCIMService/newSCIMHandler→newSCIMDiscoveryService/newSCIMDiscoveryHandler) to match thediscovery_*.gofile names.3. Go API surface changes (package-internal)
ValidateSCIMUserRequest(exported) renamed tovalidateSCIMUserRequest(unexported).reverseMapCoreAttrsForSchema(coreAttrs, schema)now returns(map[string]json.RawMessage, error)— dropped theconsumedCoreKeysreturn value.undeclaredAttrs(extensionAttrs, schema)— dropped the now-unusedcoreAttrsandconsumedCoreKeysparameters.scimUsersService.getCredentialKeys(ctx, canonicalName)now returns(map[string]struct{}, *tidcommon.ServiceError)instead of silently swallowing the lookup error and returning an empty map.ListUsers,GetUser,CreateUser, andReplaceUsernow propagate this error asErrorInternalServerinstead of silently returning users with unstripped/incorrectly-stripped credential fields.parseSCIMFilterForEqnow returns*tidcommon.ServiceErrorinstead of a plainerror.scimDiscoveryService(formerlyscimService) dropped its unuseduserServicedependency — it never called into it; onlyscimUsersServiceneeds a user service.4. Filter errors now go through the standard SCIM error pipeline
filterparse failures onGET /UsersandPOST /Users/.searchpreviously built a rawSCIMErrorResponseinline with a hardcoded, un-translatedDetailstring, bypassing i18n and the standardmapSCIMErrormapping. This is now a properServiceError(SCIM-1033,ErrorInvalidFilterSyntax) with i18n keyserror.scim.invalid_filter_syntax/error.scim.invalid_filter_syntax_descriptionadded todefaults.go. ResponseDetailtext for these errors may now differ from before.5. CORS now applied to "unsupported request" routes
init.gopreviously registered unsupported route stubs directly withmux.HandleFunc, bypassing CORS middleware. They're now wrapped withmiddleware.WithCORS, consistent with every other SCIM route.6.
/MeGET and PUT now honorattributes/excludedAttributesHandleMeGetRequestandHandleMeReplaceRequestpreviously ignored these query params and always returned the full resource. They now apply attribute projection, matchingGET/PUT /Users/{id}behavior.7.
FilterMaxResultssource changedbackend/internal/scim/config/config.go:FilterMaxResultswas a hardcoded200, now derived fromserverconst.MaxPageSize.Approach
License headers
Normalized all 44 SCIM main-package and integration-test files from the WSO2 boilerplate to the 2-line ThunderID SPDX header, ahead of the structural refactor below.
Package restructuring
handler.go/service.go(ServiceProviderConfig, Schemas, ResourceTypes) intodiscovery_handler.go/discovery_service.go, matching the existingusers_*.gonaming convention. The shared response/error helpers that used to live inhandler.gowere pulled out intoresponse.go.group_*.go) to plural (groups_*.go) to matchusers_*.go, and reworkedscimGroupsHandler/scimGroupsServiceto delegate to the same sharedresponse.gohelpers as the users handler (previously groups and users had near-duplicate but subtly different response/error-mapping code).users_handler.gointoscim_filter.go, since filtering is a cross-resource concern (used by bothGET /UsersandPOST /Users/.search).scim_validator.gointo clearly-sectioned Users vs. Groups validation (folding in the removedgroup_patch_validator.go), adding a sharedhasSchemaURNhelper that replaces three separate inline "does schemas[] contain URN X" checks with one function.scimService/scimHandlertoscimDiscoveryService/scimDiscoveryHandlerfor naming consistency withdiscovery_*.go, and dropped the unuseduserServicefield fromscimDiscoveryService(dead dependency — the discovery service only ever usedentityTypeService).Bug fixes found during the split
getCredentialKeyserror swallowing (Breaking Changes 3).filtererrors bypassing the standard SCIM error pipeline (Breaking Changes 4)./MeGET/PUT ignoring attribute projection query params (Breaking Changes 6).mapUserServiceErrorToSCIMswitched from magic string error codes ("USR-1003","USR-1014", etc.) to referencinguser.ErrorUserNotFound.Codeand friends directly.isCanonicalAddrSubAttr(core_attr_mapper.go) rewritten from an O(n) linear scan overcoreAttrRulesper call to a precomputed map built once at package init.Other included changes
api/scim.yaml: regenerated OpenAPI spec reflecting the above.backend/internal/system/i18n/core/defaults.go: added the two i18n keys backingSCIM-1033.Related Issues
Related PRs
Checklist
breaking changelabel added.Security checks