-
Notifications
You must be signed in to change notification settings - Fork 178
Description
WebAPI Authorization Model Proposal (Spring Security, JDK 21)
Background
As part of the WebAPI 3.0 modernization effort (JDK 21, Spring Boot 3.5), we are redesigning the authorization layer while migrating away from Apache Shiro toward pure Spring Security.
The current Shiro-based model is largely HTTP path–driven, which has resulted in:
- One permission per endpoint
- Tight coupling between REST structure and authorization
- Difficulty expressing business-level functions
- High maintenance overhead as endpoints evolve
This issue proposes a function-centric, capability-based authorization model that better fits WebAPI’s collaboration and security needs.
Goals
- Authorize functions, not endpoints
- Avoid permission explosion
- Support entity ownership and fine-grained sharing
- Scale cleanly in both data size and performance
- Maintain strong referential integrity
- Integrate naturally with Spring Security
- Support both global roles and per-entity access
Core Concepts
Capabilities vs Entity Access
Authorization is separated into two additive mechanisms:
- Global capability permissions
- Entity-specific permissions
Either mechanism can independently grant access.
Wildcard entity permissions such as read:cohort:12 are explicitly avoided.
Global Capability Permissions
Capabilities are stored as Spring Security authorities.
Permission format:
<action>:<scope>
Examples:
- create:cohort
- read:cohort
- write:conceptset
- report:generate
- report:view
- admin:*
Capabilities grant broad authority and do not reference entity IDs.
Entity-Specific Permissions
Entity-level access is stored in entity-specific permission tables, one per entity type.
These permissions allow fine-grained sharing without granting global authority.
Authorization Model (Additive)
Access to an entity is granted if any of the following is true:
- User has the relevant global capability
- User owns the entity
- User has an entity-level permission grant
Capabilities do not gate entity permissions.
Read Authorization Logic
canReadEntity(user, entity) =
has read:<entity>
OR is owner
OR has READ permission
Write Authorization Logic
canWriteEntity(user, entity) =
has write:<entity>
OR is owner
OR has WRITE permission
Actions
- create – create a new entity
- read – read an entity definition
- write – modify or delete an entity
- report:generate – execute analyses that generate results
- report:view – view or fetch generated results
- admin – administrative/system actions
Removed Permission Patterns
The following patterns do not exist:
- read:cohort:12
- write:conceptset:*
- read:*:123
This prevents permission explosion and orphaned permissions.
Entity Access Control Model
Each entity type defines its own permission table.
Example: Cohort Definition Permissions
cohort_definition_permission
- id
- cohort_id (FK -> cohort_definition.id)
- user_id (FK -> sec_user.id)
- permission_type (READ, WRITE)
Example: Concept Set Permissions
concept_set_permission
- id
- concept_set_id (FK -> concept_set.id)
- user_id (FK -> sec_user.id)
- permission_type (READ, WRITE)
Ownership rules:
- Creators receive WRITE
- Owners implicitly have READ
- Ownership is not stored as a permission row
Listing Entities
There is no separate list permission.
List endpoints return only entities the user can read, based on:
- Global read capability
- Ownership
- Entity-level permission
Admin Permissions
admin:* includes:
- Source management
- Cache clearing
- System configuration
- Background task control
- Operational maintenance
Admins may bypass entity-level permission checks where appropriate.
Performance Considerations
- Capability checks are in-memory
- Ownership checks are simple FK comparisons
- Entity permission checks are indexed lookups
- No wildcard parsing
- No polymorphic joins
Why Spring Security
Spring Security provides:
- Active maintenance
- First-class Spring Boot support
- Method-level authorization
- OAuth/JWT integration
- Strong ecosystem alignment
Shiro is endpoint-centric, encourages wildcard permissions, and is poorly aligned with Spring Boot 3.x.
Summary
- Migrate to Spring Security
- Use function-centric capabilities
- Use additive authorization
- Separate global and entity permissions
- Avoid wildcard entity permissions
- Use entity-specific permission tables
- Separate reporting permissions as report:*
Next Steps
- Implement authorization services
- Add Spring Security AuthorizationManagers
- Replace Shiro configuration
- Design migration strategy