Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
52 changes: 48 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,52 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- **Permission Naming Conflict** (#108, Phase 4)
- Fixed missing `role.assign`, `role.read`, `role.revoke` permissions in seeder
- Phase 3 routes (`POST /v1/users/{user}/roles`) require `role.assign` permission
- Seeder was only creating `roles.assign_temporary` (Phase 4 naming)
- Admin role now has both `role.*` (Phase 3) and `roles.*` (Phase 4) permissions
- Enables integration tests that were previously blocked by authorization failures
- Resolves 403 Forbidden errors when admins assign roles to users

### Added

- **Role Management CRUD API** (#108, Phase 4)
- New endpoint: `GET /v1/roles` - List all roles with permission count and user count
- New endpoint: `POST /v1/roles` - Create new role with permissions
- New endpoint: `GET /v1/roles/{id}` - Get role details with assigned permissions
- New endpoint: `PATCH /v1/roles/{id}` - Update role name and/or permissions
- New endpoint: `DELETE /v1/roles/{id}` - Delete role (blocks if assigned to users)
- New controller: `RoleManagementController` - Handles role CRUD operations
- New policy: `RoleManagementPolicy` - Admin-only authorization for all operations
- New form requests: `CreateRoleRequest`, `UpdateRoleRequest` - Validation rules
- Simple role system: All roles equal, no artificial system/custom distinction
- Deletion protection: Cannot delete roles assigned to users (422 response with user count)
- Part of RBAC Phase 4 Epic (#108), completes role management capabilities

- **Predefined Roles Seeder** (#108, Phase 4)
- New seeder: `RolesAndPermissionsSeeder` - Creates 5 predefined roles with permissions
- Predefined roles: Admin, Manager, Guard, Client, Works Council
- Idempotent design: Safe to run multiple times, uses `firstOrCreate`
- Auto-recreation: Deleted predefined roles are recreated on next seeder run
- Permission groups: 52 permissions across 7 resources (employees, shifts, work_instructions, roles, permissions, works_council, reports)
- Wildcard expansion: Supports `resource.*` notation for assigning all resource actions
- Only syncs permissions if role has none (prevents overwriting customizations)
- Part of RBAC Phase 4 Epic (#108), provides production-ready role foundation

- **RBAC Documentation** (#108, Phase 4)
- New guide: `docs/guides/role-management.md` - How to create/manage roles (872 lines)
- New guide: `docs/guides/permission-system.md` - Permission naming conventions and organization (716 lines)
- New guide: `docs/guides/temporal-roles.md` - Temporal role assignment patterns
- New guide: `docs/guides/direct-permissions.md` - When and how to use direct permissions
- New API docs: `docs/api/rbac-endpoints.md` - Complete API reference for all 16 RBAC endpoints (1239 lines)
- Comprehensive examples: Request/response samples for all endpoints
- Authorization diagrams: Visual representation of permission checks
- Best practices: Guidelines for role design and permission management
- Part of RBAC Phase 4 Epic (#108), completes RBAC documentation requirements

- **User Direct Permission Assignment API** (#138)
- New endpoint: `GET /v1/users/{user}/permissions` - List all user permissions (direct + inherited from roles)
- New endpoint: `POST /v1/users/{user}/permissions` - Assign direct permission(s) to user with temporal tracking (audit trail)
Expand Down Expand Up @@ -97,10 +141,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Prevents accidental commits of broken code from merge conflicts
- Colored output shows exact file locations and line numbers
- **RBAC Phase 3: API Endpoints & Authorization** - Role management REST API (#107)
- `POST /api/v1/users/{id}/roles` - Assign role with temporal parameters (valid_from, valid_until, auto_revoke)
- `GET /api/v1/users/{id}/roles` - List user roles with expiry info (is_active, is_expired status)
- `DELETE /api/v1/users/{id}/roles/{role}` - Revoke role assignment
- `PATCH /api/v1/users/{id}/roles/{role}/extend` - Extend role expiration date
- `POST /v1/users/{id}/roles` - Assign role with temporal parameters (valid_from, valid_until, auto_revoke)
- `GET /v1/users/{id}/roles` - List user roles with expiry info (is_active, is_expired status)
- `DELETE /v1/users/{id}/roles/{role}` - Revoke role assignment
- `PATCH /v1/users/{id}/roles/{role}/extend` - Extend role expiration date
- `RoleController` with 3 RESTful methods (`store`, `index`, `destroy`) and 1 custom action (`extend`)
- `AssignRoleRequest` - Validates temporal parameters (valid_from < valid_until, role existence)
- `ExtendRoleRequest` - Validates extension (new date must be after current expiration)
Expand Down
57 changes: 53 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,56 @@ SecPal API is the backend service for the SecPal platform, built with Laravel 12
- **Static Analysis:** PHPStan (Level Max) with Larastan
- **PHP Version:** 8.4+

## Requirements
## Key Features

### πŸ” Role-Based Access Control (RBAC)

Comprehensive RBAC system with temporal role assignments and direct permission management.

**Features:**

- **5 Predefined Roles**: Admin, Manager, Guard, Client, Works Council
- **52 Permissions** across 7 resources (employees, shifts, work_instructions, roles, permissions, works_council, reports)
- **Temporal Role Assignments**: Assign roles with `valid_from`/`valid_until` dates for automatic expiration
- **Direct Permissions**: Assign permissions directly to users, bypassing roles for fine-grained control
- **Permission Inheritance**: User permissions = Role permissions βˆͺ Direct permissions
- **Idempotent Seeder**: Predefined roles auto-recreate if deleted
- **16 REST API Endpoints**: Full CRUD for roles, permissions, assignments, and direct permissions

**API Examples:**

```bash
# List all roles with counts
GET /v1/roles

# Assign role to user with expiration
POST /v1/users/{id}/roles
{
"role": "Manager",
"valid_from": "2025-11-15T00:00:00Z",
"valid_until": "2025-12-31T23:59:59Z"
}

# Assign direct permission (bypass role)
POST /v1/users/{id}/permissions
{
"permissions": ["employees.export", "reports.generate"]
}

# List user's all permissions (role + direct)
GET /v1/users/{id}/permissions
# Returns: { "via_roles": [...], "direct": [...], "all": [...] }
```

**Documentation:**

- [Role Management Guide](docs/guides/role-management.md)
- [Permission System](docs/guides/permission-system.md)
- [Temporal Roles](docs/guides/temporal-roles.md)
- [Direct Permissions](docs/guides/direct-permissions.md)
- [API Reference](docs/api/rbac-endpoints.md)

### πŸ”’ Envelope Encryption

- PHP 8.4 or higher
- Composer 2.x
Expand Down Expand Up @@ -282,14 +331,14 @@ Role and permission assignments are permanent by default. Temporal constraints (
**Assign Permanent Role:**

```bash
POST /api/v1/users/{id}/roles
POST /v1/users/{id}/roles
{"role": "manager"}
```

**Assign Temporal Role:**

```bash
POST /api/v1/users/{id}/roles
POST /v1/users/{id}/roles
{
"role": "manager",
"valid_until": "2025-12-14T23:59:59Z"
Expand All @@ -299,7 +348,7 @@ POST /api/v1/users/{id}/roles
**Assign Direct Permission:**

```bash
POST /api/v1/users/{id}/permissions
POST /v1/users/{id}/permissions
{"permissions": ["employees.export"]}
```

Expand Down
34 changes: 20 additions & 14 deletions database/seeders/RolesAndPermissionsSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,21 +91,26 @@ private function getPermissionDefinitions(): array
'acknowledge',
'view_acknowledgments',
],
'role' => [
'assign', // Phase 3: POST /users/{user}/roles
'read', // Phase 3: GET /users/{user}/roles
'revoke', // Phase 3: DELETE /users/{user}/roles/{role}
],
'roles' => [
'read',
'create',
'update',
'delete',
'assign_temporary',
'extend_expiration',
'read', // Phase 4: GET /roles
'create', // Phase 4: POST /roles
'update', // Phase 4: PATCH /roles/{id}
'delete', // Phase 4: DELETE /roles/{id}
'assign_temporary', // Phase 3: Temporal role assignment
'extend_expiration', // Phase 3: PATCH /users/{user}/roles/{role}/extend
],
'permissions' => [
'read',
'create',
'update',
'delete',
'assign_direct',
'revoke_direct',
'read', // Phase 4: GET /permissions
'create', // Phase 4: POST /permissions
'update', // Phase 4: PATCH /permissions/{id}
'delete', // Phase 4: DELETE /permissions/{id}
'assign_direct', // Phase 4: POST /users/{user}/permissions
'revoke_direct', // Phase 4: DELETE /users/{user}/permissions/{permission}
],
'works_council' => [
'access_employee_files',
Expand All @@ -132,8 +137,9 @@ private function getRoleDefinitions(): array
'employees.*',
'shifts.*',
'work_instructions.*',
'roles.*',
'permissions.*',
'role.*', // Phase 3: Role assignment permissions
'roles.*', // Phase 4: Role management permissions
'permissions.*', // Phase 4: Permission management permissions
'works_council.*',
'reports.*',
],
Expand Down
2 changes: 1 addition & 1 deletion docs/GUARD_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ it('allows manager to read employees', function () {

// Test API endpoint (auth:sanctum middleware)
$response = $this->actingAs($user)
->getJson('/api/v1/employees');
->getJson('/v1/employees');

$response->assertOk(); // βœ… Permission check succeeds
});
Expand Down
36 changes: 18 additions & 18 deletions docs/api/rbac-endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Authorization: Bearer {your_access_token}

Assign a role to a user. Supports both permanent and temporal assignments.

**Endpoint:** `POST /api/v1/users/{user}/roles`
**Endpoint:** `POST /v1/users/{user}/roles`

**Authorization:** Requires `role.assign` permission (Manager or Admin)

Expand Down Expand Up @@ -148,7 +148,7 @@ console.log(data);

Get all roles assigned to a user, including temporal information.

**Endpoint:** `GET /api/v1/users/{user}/roles`
**Endpoint:** `GET /v1/users/{user}/roles`

**Authorization:** Requires `role.read` permission (User can view own, Manager/Admin can view all)

Expand Down Expand Up @@ -201,7 +201,7 @@ curl -X GET https://api.secpal.app/v1/users/123/roles \

Remove a role assignment from a user.

**Endpoint:** `DELETE /api/v1/users/{user}/roles/{role}`
**Endpoint:** `DELETE /v1/users/{user}/roles/{role}`

**Authorization:** Requires `role.revoke` permission (Manager or Admin)

Expand Down Expand Up @@ -247,7 +247,7 @@ curl -X DELETE https://api.secpal.app/v1/users/123/roles/manager \

Extend the expiration date of a temporal role assignment.

**Endpoint:** `PATCH /api/v1/users/{user}/roles/{role}/extend`
**Endpoint:** `PATCH /v1/users/{user}/roles/{role}/extend`

**Authorization:** Requires `role.extend_expiration` permission (Manager or Admin)

Expand Down Expand Up @@ -298,7 +298,7 @@ curl -X PATCH https://api.secpal.app/v1/users/123/roles/manager/extend \

Get a list of all roles in the system (predefined + custom).

**Endpoint:** `GET /api/v1/roles`
**Endpoint:** `GET /v1/roles`

**Authorization:** Requires `role.read` permission

Expand Down Expand Up @@ -366,7 +366,7 @@ curl -X GET "https://api.secpal.app/v1/roles?page=1&per_page=15&sort=name" \

Create a new custom role with assigned permissions.

**Endpoint:** `POST /api/v1/roles`
**Endpoint:** `POST /v1/roles`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -449,7 +449,7 @@ curl -X POST https://api.secpal.app/v1/roles \

Get detailed information about a specific role, including assigned permissions.

**Endpoint:** `GET /api/v1/roles/{id}`
**Endpoint:** `GET /v1/roles/{id}`

**Authorization:** Requires `role.read` permission

Expand Down Expand Up @@ -503,7 +503,7 @@ curl -X GET https://api.secpal.app/v1/roles/2 \

Update a role's name, description, and/or permissions.

**Endpoint:** `PATCH /api/v1/roles/{id}`
**Endpoint:** `PATCH /v1/roles/{id}`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -554,7 +554,7 @@ curl -X PATCH https://api.secpal.app/v1/roles/6 \

Delete a custom role. **Cannot delete roles that are assigned to users.**

**Endpoint:** `DELETE /api/v1/roles/{id}`
**Endpoint:** `DELETE /v1/roles/{id}`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -598,7 +598,7 @@ curl -X DELETE https://api.secpal.app/v1/roles/6 \

Get all permissions grouped by resource.

**Endpoint:** `GET /api/v1/permissions`
**Endpoint:** `GET /v1/permissions`

**Authorization:** Authorized via Laravel Policy. Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -661,7 +661,7 @@ curl -X GET https://api.secpal.app/v1/permissions \

Create a new custom permission.

**Endpoint:** `POST /api/v1/permissions`
**Endpoint:** `POST /v1/permissions`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -726,7 +726,7 @@ curl -X POST https://api.secpal.app/v1/permissions \

Get detailed information about a specific permission.

**Endpoint:** `GET /api/v1/permissions/{id}`
**Endpoint:** `GET /v1/permissions/{id}`

**Authorization:** Authorized via Laravel Policy. Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -772,7 +772,7 @@ curl -X GET https://api.secpal.app/v1/permissions/5 \

Update a permission's description. **Note:** Permission names are immutable for security reasons.

**Endpoint:** `PATCH /api/v1/permissions/{id}`
**Endpoint:** `PATCH /v1/permissions/{id}`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -818,7 +818,7 @@ curl -X PATCH https://api.secpal.app/v1/permissions/5 \

Delete a custom permission. **Cannot delete if assigned to any role or user.**

**Endpoint:** `DELETE /api/v1/permissions/{id}`
**Endpoint:** `DELETE /v1/permissions/{id}`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -864,7 +864,7 @@ curl -X DELETE https://api.secpal.app/v1/permissions/43 \

Get all permissions for a user, showing role-based, direct, and combined permissions.

**Endpoint:** `GET /api/v1/users/{user}/permissions`
**Endpoint:** `GET /v1/users/{user}/permissions`

**Authorization:** User can view own permissions; Admin can view any user's permissions

Expand Down Expand Up @@ -932,7 +932,7 @@ curl -X GET https://api.secpal.app/v1/users/123/permissions \

Assign one or more permissions directly to a user, bypassing roles.

**Endpoint:** `POST /api/v1/users/{user}/permissions`
**Endpoint:** `POST /v1/users/{user}/permissions`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -1006,7 +1006,7 @@ curl -X POST https://api.secpal.app/v1/users/123/permissions \

Remove a direct permission from a user. **Does not affect role-based permissions.**

**Endpoint:** `DELETE /api/v1/users/{user}/permissions/{permission}`
**Endpoint:** `DELETE /v1/users/{user}/permissions/{permission}`

**Authorization:** Authorized via Laravel Policy (Admin role required). Note: Route-level middleware will be added in future release (see Issue #161).

Expand Down Expand Up @@ -1043,7 +1043,7 @@ curl -X DELETE https://api.secpal.app/v1/users/123/permissions/employees.export

Get only the permissions assigned directly to a user (excludes role-based permissions).

**Endpoint:** `GET /api/v1/users/{user}/permissions/direct`
**Endpoint:** `GET /v1/users/{user}/permissions/direct`

**Authorization:** User can view own; Admin can view any

Expand Down
Loading