From 6cf04cd6faa80daff7d3db20b140217ad5aba691 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 14:11:22 +0200 Subject: [PATCH 1/8] Expand and restructure `README.md` with improved formatting, refined feature descriptions, security details, ticket lifecycle, role-based access control, and demo setup instructions. --- README.md | 245 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 139 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index fba3a1a..7631dfc 100644 --- a/README.md +++ b/README.md @@ -3,21 +3,45 @@ ALFS is a secure case management system for handling whistleblower reports, built with Spring Boot. ## Features -- Anonymous and authenticated ticket submission -- Ticket assignment, status updates, and comments -- Secure file attachments with MinIO storage -- Role-based access control -- Internal notes for private admin/investigator communication -- Audit logging for all key actions -- Server-side rendered UI with JTE templates -- Demo data for quick local testing - -## Internal Messaging -The system supports internal notes for communication between admins and investigators. -These messages are kept separate from public ticket comments so internal coordination stays private. -This makes it easier to discuss case handling, assignments, and follow-up work without exposing sensitive details. - -## Audit Logging + - Anonymous and authenticated ticket submission + - Ticket lifecycle management (assignment, status, comments) + - Internal comments for private admin/investigator communication + - Audit logging for all key actions + - Demo data available for quick local testing + +## Security +- Secure password hashing with BCrypt +- Role-based access control (RBAC) +- Owner-based access restrictions +- Token-based access for anonymous users +- Server-side rendering with JTE ensures automatic HTML escaping to prevent XSS +- Secure file uploads with MinIO storage + +## Feature Details +### Anonymous Ticket Submission +Anonymous (unauthenticated) users can submit tickets without creating an account. A unique secure token is generated on submission — anyone with the token can view and comment on that specific ticket without logging in. + +### Ticket Lifecycle Management +Tickets follow a structured lifecycle to ensure proper handling from submission to resolution. + +#### Statuses +- **OPEN**: Default state for new submissions. +- **IN_PROGRESS**: The ticket is currently being handled by an investigator. +- **RESOLVED**: The investigation is complete, and a resolution has been reached. +- **CLOSED**: The case is finalized and no further actions are expected. + +#### Assignment Flow +1. **Submission**: A ticket is created in the **OPEN** state. +2. **Triage**: An **ADMIN** reviews the ticket and assigns it to an **INVESTIGATOR**. +3. **Investigation**: The assigned investigator updates the status to **IN_PROGRESS** and interacts with the reporter. +4. **Resolution**: Once finished, the investigator or admin moves the ticket to **RESOLVED** or **CLOSED**. + +#### Communication +The system supports two types of comments: +- **Public Comments**: Visible to everyone with access to the ticket (Reporters, Investigators, Admins). Used for follow-up questions and providing updates. +- **Internal Notes**: Visible only to **INVESTIGATORS** and **ADMINS**. These are kept separate from public comments to ensure internal coordination stays private, making it easier to discuss case handling and assignments without exposing sensitive details. + +### Audit Logging The application keeps an audit trail of important actions so changes can be reviewed later. It records details such as the action type, affected field, previous value, new value, and timestamp. This helps track ticket updates, assignment changes, status changes, comments, and other key workflow events. @@ -35,21 +59,41 @@ This helps track ticket updates, assignment changes, status changes, comments, a - MinIO for file storage - JUnit 5, Mockito, and Spring test support -## How to Run +## Quick start 1. Make sure you have Java 25 and Maven installed. -2. Start the application: +2. Enable demo data by adding the following to your local `src/main/resources/application.properties`: + +```properties +spring.profiles.active=demo +``` + +*Alternatively, run with the profile directly via command line (see step 3).* + +3. Start the application: ```bash + # Using the property file ./mvnw spring-boot:run + + # OR: directly enabling the demo profile via command line + ./mvnw spring-boot:run -Dspring-boot.run.profiles=demo ``` -3. Open the app in your browser at: +4. Open the app in your browser at: ```text http://localhost:8080 ``` +5. Log in at `http://localhost:8080/login` using the default admin credentials: + ```text + username: admin + password: admin + ``` -## Local Development Notes -- Demo data is available for quick local testing. -- H2 console is available for local database inspection. -- MinIO is used for attachment storage in development. +> **Note:** To test file uploads and downloads, you'll need a local MinIO instance running. See the [Local MinIO setup](#local-minio-setup-dev-and-testing-file-upload-download) section below. + +## Typical User Flow +1. **As a Whistleblower (Anonymous)**: Visit `/tickets/create` to submit a report. Save the provided token to follow up later. +2. **As an Authenticated Reporter**: Login at `/login`, then go to `/tickets/my` to see and track your submitted reports. +3. **As an Admin**: Login at `/login` (user: `admin`), then go to `/admin/tickets` to see all reports and assign them to investigators. +4. **As an Investigator**: Login at `/login`, then check `/tickets/assigned` for cases assigned to you. ## Project Structure - `controllers` — web endpoints @@ -59,62 +103,50 @@ This helps track ticket updates, assignment changes, status changes, comments, a - `dto` and `mapper` — request/response mapping - `security` — authentication and JWT handling +## Architecture + +The application follows a layered architecture with server-side rendering: + +```text +Browser (JTE) → Controller → Service → Repository → Database +``` +This layered architecture separates concerns: +- Controllers handle HTTP and validation +- Services enforce business rules and security +- Repositories abstract persistence + +Security is enforced at both controller and service levels to prevent bypassing access rules. + +- **JTE Templates**: Generate the HTML on the server. +- **Controllers**: Handle HTTP requests, form submissions, and redirects. +- **Services**: Implement business logic, security checks, and audit logging. +- **Repositories**: Standard Spring Data JPA repositories for H2. +- **Storage Service**: Abstracts interaction with MinIO/S3 for file attachments. + ## CI/CD The project uses GitHub Actions for: - CI on push and pull requests - CD builds that publish a JAR artifact on `main` -## Local MinIO setup (dev) and testing file upload/download +## Role-Based Access Control (RBAC) -1) Start MinIO locally (Docker) -- Windows PowerShell example: - - Create a data folder (optional): `mkdir C:\minio\data` - - Run MinIO: - ```powershell - docker run --name minio -p 9000:9000 -p 9001:9001 ` - -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin ` - -v C:\minio\data:/data ` - -d quay.io/minio/minio server /data --console-address ":9001" - ``` +The system implements a multi-layered security model to protect whistleblower reports and ensure that only authorized personnel can access sensitive information. -2) Create the bucket -- Open MinIO Console: http://localhost:9001 (user: `minioadmin`, pass: `minioadmin`). -- Go to Buckets → Create bucket → name it: `alfs-attachments`. +### Roles and Permissions -3) Verify application configuration (already set for local dev) -- See `src/main/resources/application.properties`: - - `storage.s3.endpoint=http://localhost:9000` - - `storage.s3.accessKey=minioadmin` - - `storage.s3.secretKey=minioadmin` - - `storage.s3.bucket=alfs-attachments` - - `spring.servlet.multipart.max-file-size=50MB` +| Role | Purpose | Permissions | +| --- | --- | --- | +| **REPORTER** | Standard whistleblower user. | Create tickets, view their own tickets, and add comments. | +| **INVESTIGATOR**| Internal staff handling cases. | View assigned tickets, update ticket status, and add comments (public & internal). | +| **ADMIN** | System administrator. | Full access to all tickets, assign investigators to tickets, and system management. | -4) Test file upload (POST) -- Start the Spring Boot app (default port 8080). -- Use Postman or curl: - ```bash - curl -X POST "http://localhost:8080/api/files/upload" \ - -F ticketId=1 \ - -F file=@"C:/path/to/your/test.pdf" - ``` -- Expected JSON response example: - ```json - { - "id": 42, - "ticketId": 1, - "fileName": "test.pdf", - "s3Key": "/test.pdf", - "uploadedAt": "2026-04-02T12:34:56" - } - ``` -- Check MinIO Console → your bucket → object is present. +### Access Control Mechanisms -5) Test file download (GET) -- Take the `id` from the upload response above and request: - ```bash - curl -v -o downloaded.pdf "http://localhost:8080/api/files/42/download" - ``` -- The file should be downloaded as `downloaded.pdf`. +1. **Endpoint Protection**: Configured in `SecurityConfig.java`, defining which URL patterns are public (e.g., login, signup, anonymous ticket creation) and which require authentication. +2. **Method Security**: Using `@PreAuthorize` annotations on controller methods to enforce role requirements. +3. **Owner-Based Access**: Tickets created by a `REPORTER` are only accessible to that specific user, the assigned `INVESTIGATOR`, and all `ADMIN` users. +4. **Token-Based Access**: For anonymous reports, a unique secure token is generated. Anyone with the token can view and comment on that specific ticket without needing an account. +5. **Role Refresh**: Roles are loaded from the database on every request (via JWT filter) to ensure permission changes take effect immediately. ## Demo Data @@ -148,47 +180,48 @@ The seeder will only run if the admin user does not exist, so it is safe to leav Once running, the H2 database console is available at `/h2-console` using the credentials in `application.properties`. -------- - -## 🔐 Role-Based Access Control (RBAC) - -The system implements a multi-layered security model to protect whistleblower reports and ensure that only authorized personnel can access sensitive information. - -### Roles and Permissions - -| Role | Purpose | Permissions | -| --- | --- | --- | -| **REPORTER** | Standard whistleblower user. | Create tickets, view their own tickets, and add comments. | -| **INVESTIGATOR**| Internal staff handling cases. | View assigned tickets, update ticket status, and add comments. | -| **ADMIN** | System administrator. | Full access to all tickets, assign investigators to tickets, and system management. | - -#### Anonymous Access -Anonymous (unauthenticated) users can submit tickets without an account. A unique secure token is generated on submission — anyone with the token can view and comment on that specific ticket without logging in. - -### Access Control Mechanisms - -1. **Endpoint Protection**: Configured in `SecurityConfig.java`, defining which URL patterns are public (e.g., login, signup, anonymous ticket creation) and which require authentication. -2. **Method Security**: Using `@PreAuthorize` annotations on controller methods to enforce role requirements at the service and controller levels. -3. **Owner-Based Access**: Tickets created by a `REPORTER` are only accessible to that specific user, the assigned `INVESTIGATOR`, and all `ADMIN` users. -4. **Token-Based Access**: For anonymous reports, a unique secure token is generated. Anyone with the token can view and comment on that specific ticket without needing an account. - -### Database Entities - -- **User**: Stores credentials and the assigned `Role`. -- **Role**: An enumeration (`REPORTER`, `INVESTIGATOR`, `ADMIN`) that defines the user's authority level. +## Local MinIO setup (dev) and testing file upload/download -------- +1) Start MinIO locally (Docker) +- Windows PowerShell example: + - Create a data folder (optional): `mkdir C:\minio\data` + - Run MinIO: + ```powershell + docker run --name minio -p 9000:9000 -p 9001:9001 ` + -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin ` + -v C:\minio\data:/data ` + -d quay.io/minio/minio server /data --console-address ":9001" + ``` -## 🏗️ Architecture +2) Create the bucket +- Open MinIO Console: http://localhost:9001 (user: `minioadmin`, pass: `minioadmin`). +- Go to Buckets → Create bucket → name it: `alfs-attachments`. -The application follows a layered architecture: +3) Verify application configuration (already set for local dev) +- See `src/main/resources/application.properties`: + - `storage.s3.endpoint=http://localhost:9000` + - `storage.s3.accessKey=minio` + - `storage.s3.secretKey=minio123` + - `storage.s3.bucket=alfs-attachments` + - `spring.servlet.multipart.max-file-size=50MB` -```text -Controller → Service → Repository → Database -``` +4) Test file upload (POST) +- Start the Spring Boot app (default port 8080). +- Use Postman or curl: + ```bash + curl -X POST "http://localhost:8080/api/files/upload" \ + -F ticketId=1 \ + -F file=@"/path/to/your/test.pdf" + ``` +- Since `AttachmentController` is a `@Controller`, it will return a redirect (302) to the ticket view page. +- Check MinIO Console → your bucket → object is present. -- Controllers handle HTTP requests and responses -- Services contain business logic -- Repositories handle data access +5) Test file download (GET) +- Use the attachment ID (e.g., 1) to download the file: + ```bash + curl -v -o downloaded.pdf "http://localhost:8080/api/files/1/download" + ``` +- The file should be downloaded as `downloaded.pdf`. --------~~ \ No newline at end of file +### Notes +- A ticket with the provided ticketId must exist in the database before uploading. \ No newline at end of file From ff4f09db8dd6e9fb62daa79c4026c034af512bfa Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 14:53:19 +0200 Subject: [PATCH 2/8] Revise `README.md` with enhanced formatting, expanded feature descriptions, improved security details, detailed architecture insights, and demo setup updates. --- README.md | 82 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 7631dfc..dfa182a 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,20 @@ ALFS is a secure case management system for handling whistleblower reports, built with Spring Boot. ## Features - - Anonymous and authenticated ticket submission - - Ticket lifecycle management (assignment, status, comments) - - Internal comments for private admin/investigator communication - - Audit logging for all key actions - - Demo data available for quick local testing +- **Anonymous & Authenticated Reporting**: Submit reports without an account using secure tokens or as a registered user. +- **Ticket Lifecycle Management**: Full workflow support including assignment, status transitions, and public/internal comments. +- **Audit Logging**: Comprehensive trail of all security-sensitive actions and ticket modifications. +- **Server-Side Rendering**: Fast, secure UI built with JTE templates. +- **Secure Storage**: File attachments managed via MinIO/S3 compatible storage. +- **Secure Access Model**: RBAC, ownership validation, and token-based access control. ## Security -- Secure password hashing with BCrypt -- Role-based access control (RBAC) -- Owner-based access restrictions -- Token-based access for anonymous users -- Server-side rendering with JTE ensures automatic HTML escaping to prevent XSS -- Secure file uploads with MinIO storage +- **RBAC**: Multi-layered permissions for Reporters, Investigators, and Admins. +- **Owner-Based Access**: Strict isolation of ticket data based on reporter and assigned investigator. +- **Secure Token Access**: Unique cryptographic tokens for anonymous ticket follow-ups. +- **Data Protection**: Secure password hashing with BCrypt and CSRF protection for all state-changing requests. +- **XSS Prevention**: Automatic HTML escaping via server-side JTE rendering. +- **JWT Authentication**: Supports both browser cookies and API headers with database-backed role verification. ## Feature Details ### Anonymous Ticket Submission @@ -42,9 +43,15 @@ The system supports two types of comments: - **Internal Notes**: Visible only to **INVESTIGATORS** and **ADMINS**. These are kept separate from public comments to ensure internal coordination stays private, making it easier to discuss case handling and assignments without exposing sensitive details. ### Audit Logging -The application keeps an audit trail of important actions so changes can be reviewed later. -It records details such as the action type, affected field, previous value, new value, and timestamp. -This helps track ticket updates, assignment changes, status changes, comments, and other key workflow events. +The application maintains a comprehensive audit trail of security-sensitive actions and ticket modifications. + +**What is logged:** +- Ticket creation and status changes. +- Investigator assignments and reassignments. +- New public comments and internal notes. +- File attachment uploads. + +Each log entry records the action type, affected field, previous and new values, the acting user, and a precise timestamp. This provides accountability and helps meet compliance requirements for whistleblower systems. ## Tech Stack - Java 25 @@ -81,7 +88,9 @@ spring.profiles.active=demo ```text http://localhost:8080 ``` -5. Log in at `http://localhost:8080/login` using the default admin credentials: + *The landing page provides quick links to submit a report or log in.* + +5. Log in at `http://localhost:8080/login` (or via the UI) using the default admin credentials: ```text username: admin password: admin @@ -95,13 +104,20 @@ spring.profiles.active=demo 3. **As an Admin**: Login at `/login` (user: `admin`), then go to `/admin/tickets` to see all reports and assign them to investigators. 4. **As an Investigator**: Login at `/login`, then check `/tickets/assigned` for cases assigned to you. +## Design Decisions + +- Server-side rendering (JTE) was chosen over a SPA approach to reduce complexity + and minimize client-side security concerns (e.g., XSS, token handling). +- Token-based access allows anonymous reporting without account creation +- MinIO enables S3-compatible storage without external dependencies + ## Project Structure -- `controllers` — web endpoints +- `controllers` — web endpoints (UI and API) - `services` — business logic - `repositories` — database access - `entities` — JPA models - `dto` and `mapper` — request/response mapping -- `security` — authentication and JWT handling +- `security` — Spring Security configuration, authentication, and access control ## Architecture @@ -111,17 +127,13 @@ The application follows a layered architecture with server-side rendering: Browser (JTE) → Controller → Service → Repository → Database ``` This layered architecture separates concerns: -- Controllers handle HTTP and validation -- Services enforce business rules and security -- Repositories abstract persistence +- **Controllers**: Handle HTTP requests, input validation, and view redirects. +- **Services**: Orchestrate business logic, enforce security rules, and trigger audit logging. +- **Repositories**: Abstract database persistence using Spring Data JPA. +- **Storage Service**: Encapsulates interaction with MinIO/S3 for attachment handling. +- **Audit Service**: Records a detailed trail of modifications for compliance and tracking. -Security is enforced at both controller and service levels to prevent bypassing access rules. - -- **JTE Templates**: Generate the HTML on the server. -- **Controllers**: Handle HTTP requests, form submissions, and redirects. -- **Services**: Implement business logic, security checks, and audit logging. -- **Repositories**: Standard Spring Data JPA repositories for H2. -- **Storage Service**: Abstracts interaction with MinIO/S3 for file attachments. +Security is enforced at both controller (URL-based) and service levels (method-based) to ensure defense-in-depth. ## CI/CD The project uses GitHub Actions for: @@ -143,10 +155,20 @@ The system implements a multi-layered security model to protect whistleblower re ### Access Control Mechanisms 1. **Endpoint Protection**: Configured in `SecurityConfig.java`, defining which URL patterns are public (e.g., login, signup, anonymous ticket creation) and which require authentication. -2. **Method Security**: Using `@PreAuthorize` annotations on controller methods to enforce role requirements. +2. **Method Security**: Using `@PreAuthorize` annotations on controller methods to enforce role requirements (e.g., restricting status updates to Admins and Investigators). 3. **Owner-Based Access**: Tickets created by a `REPORTER` are only accessible to that specific user, the assigned `INVESTIGATOR`, and all `ADMIN` users. 4. **Token-Based Access**: For anonymous reports, a unique secure token is generated. Anyone with the token can view and comment on that specific ticket without needing an account. -5. **Role Refresh**: Roles are loaded from the database on every request (via JWT filter) to ensure permission changes take effect immediately. + +## JWT Authentication + +The application uses JSON Web Tokens (JWT) for stateless authentication, supporting both browser and API-based interactions. +Even though the UI is server-rendered, the system remains stateless by storing the JWT in a cookie. + +### Key Features +- **Dual-Source Lookup**: The system identifies the user via the `JWT` cookie (for browser/UI) or the `Authorization: Bearer ` header (for API clients). +- **Database-Backed Roles**: Roles are reloaded from the database on every request. This ensures that permission changes (e.g., revoking admin rights) take effect immediately, even if the user has a long-lived token. +- **Security Secret**: Local development uses a secret defined in `application.properties`. In production, this must be provided via the `JWT_SECRET` environment variable. +- **API Endpoints**: RESTful authentication is available at `/auth/login` and `/auth/signup` for JSON-based programmatic access. ## Demo Data @@ -178,7 +200,7 @@ The seeder will only run if the admin user does not exist, so it is safe to leav | reporter1 | reporter1 | REPORTER | | reporter2 | reporter2 | REPORTER | -Once running, the H2 database console is available at `/h2-console` using the credentials in `application.properties`. +Once running, the H2 database console is available at `/h2-console` using the credentials in `application.properties` (JDBC URL: `jdbc:h2:mem:testdb`). ## Local MinIO setup (dev) and testing file upload/download From 25dbca2721e57b1fae6c2f00f44fea582ef7dee7 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 14:57:45 +0200 Subject: [PATCH 3/8] Fix typos and improve clarity in `README.md` --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dfa182a..febfed9 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ spring.profiles.active=demo ## Design Decisions - Server-side rendering (JTE) was chosen over a SPA approach to reduce complexity - and minimize client-side security concerns (e.g., XSS, token handling). + and minimize client-side security concerns (e.g., XSS, token handling) - Token-based access allows anonymous reporting without account creation -- MinIO enables S3-compatible storage without external dependencies +- MinIO enables S3-compatible storage without without requiring a cloud provider ## Project Structure - `controllers` — web endpoints (UI and API) From 5ead9f091ab63f4504b6f5f57f9f8f96a2678deb Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 15:08:05 +0200 Subject: [PATCH 4/8] Fix typos in `README.md` for improved clarity --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index febfed9..a0e8b99 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ ALFS is a secure case management system for handling whistleblower reports, buil - **Ticket Lifecycle Management**: Full workflow support including assignment, status transitions, and public/internal comments. - **Audit Logging**: Comprehensive trail of all security-sensitive actions and ticket modifications. - **Server-Side Rendering**: Fast, secure UI built with JTE templates. -- **Secure Storage**: File attachments managed via MinIO/S3 compatible storage. +- **Secure Storage**: File attachments managed via MinIO/S3-compatible storage. - **Secure Access Model**: RBAC, ownership validation, and token-based access control. ## Security @@ -106,10 +106,10 @@ spring.profiles.active=demo ## Design Decisions -- Server-side rendering (JTE) was chosen over a SPA approach to reduce complexity +- Server-side rendering (JTE) was chosen over an SPA approach to reduce complexity and minimize client-side security concerns (e.g., XSS, token handling) - Token-based access allows anonymous reporting without account creation -- MinIO enables S3-compatible storage without without requiring a cloud provider +- MinIO enables S3-compatible storage without requiring a cloud provider ## Project Structure - `controllers` — web endpoints (UI and API) From 4737243907789386f56d7a6c60b28cf54d3a5521 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 15:10:30 +0200 Subject: [PATCH 5/8] Update S3 credentials in `application.properties` and `README.md` for local development setup --- README.md | 4 ++-- src/main/resources/application.properties | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a0e8b99..0b46448 100644 --- a/README.md +++ b/README.md @@ -222,8 +222,8 @@ Once running, the H2 database console is available at `/h2-console` using the cr 3) Verify application configuration (already set for local dev) - See `src/main/resources/application.properties`: - `storage.s3.endpoint=http://localhost:9000` - - `storage.s3.accessKey=minio` - - `storage.s3.secretKey=minio123` + - `storage.s3.accessKey=minioadmin` + - `storage.s3.secretKey=minioadmin` - `storage.s3.bucket=alfs-attachments` - `spring.servlet.multipart.max-file-size=50MB` diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 76e45ae..2d41565 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,8 +6,8 @@ spring.web.error.whitelabel.enabled=false # Storage (MinIO/S3) ? default local dev values; override via env in andra milj�er storage.s3.endpoint=http://localhost:9000 -storage.s3.accessKey=minio -storage.s3.secretKey=minio123 +storage.s3.accessKey=minioadmin +storage.s3.secretKey=minioadmin storage.s3.bucket=alfs-attachments storage.s3.region=us-east-1 storage.s3.secure=false From e352541928b7bbf1192d91812f975a3d871bc3e5 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 15:39:37 +0200 Subject: [PATCH 6/8] Refine `README.md` formatting and update Swagger UI documentation links --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d27036f..81e6cf2 100644 --- a/README.md +++ b/README.md @@ -170,15 +170,16 @@ Even though the UI is server-rendered, the system remains stateless by storing t - **Security Secret**: Local development uses a secret defined in `application.properties`. In production, this must be provided via the `JWT_SECRET` environment variable. - **API Endpoints**: RESTful authentication is available at `/auth/login` and `/auth/signup` for JSON-based programmatic access. -# 🚀 API Documentation & Testing -## This project uses Swagger UI to provide a visual interface for exploring and testing the API endpoints. +## API Documentation & Testing + +This project uses Swagger UI to provide a visual interface for exploring and testing the API endpoints. ### Accessing Swagger Once the application is running, you can access the interactive documentation at: -Swagger UI: http://localhost:8080/swagger-ui/index.html +- Swagger UI: http://localhost:8080/swagger-ui/index.html +- OpenAPI Spec (JSON): http://localhost:8080/v3/api-docs -OpenAPI Spec (JSON): http://localhost:8080/v3/api-docs ## Demo Data The application includes a demo data seeder that populates the database with realistic test data on startup. From 0dbccf8f3169393e9a8c287cd8ef52270c33a806 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 15:52:33 +0200 Subject: [PATCH 7/8] Update `README.md`: refine notes, adjust MinIO setup section, and improve link formatting --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 81e6cf2..d4bb5a1 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,8 @@ spring.profiles.active=demo *Alternatively, run with the profile directly via command line (see step 3).* +> **Note:** Read more about [demo data](#demo-data) below. + 3. Start the application: ```bash # Using the property file @@ -96,7 +98,7 @@ spring.profiles.active=demo password: admin ``` -> **Note:** To test file uploads and downloads, you'll need a local MinIO instance running. See the [Local MinIO setup](#local-minio-setup-dev-and-testing-file-upload-download) section below. +> **Note:** To test file uploads and downloads, you'll need a local MinIO instance running. See the [Local MinIO setup](#local-minio-setup) section below. ## Typical User Flow 1. **As a Whistleblower (Anonymous)**: Visit `/tickets/create` to submit a report. Save the provided token to follow up later. @@ -212,7 +214,7 @@ The seeder will only run if the admin user does not exist, so it is safe to leav Once running, the H2 database console is available at `/h2-console` using the credentials in `application.properties` (JDBC URL: `jdbc:h2:mem:testdb`). -## Local MinIO setup (dev) and testing file upload/download +## Local MinIO setup 1) Start MinIO locally (Docker) - Windows PowerShell example: From d2d983668d93d8a34b974e543c5b81ede7c03280 Mon Sep 17 00:00:00 2001 From: Simon Forsberg Date: Mon, 27 Apr 2026 20:28:07 +0200 Subject: [PATCH 8/8] Remove `csrf` requirement from `TicketControllerIT` tests and update `README.md` to reflect CSRF protection changes. --- README.md | 2 +- .../alfs/integration/TicketControllerIT.java | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index d4bb5a1..3d2d775 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ALFS is a secure case management system for handling whistleblower reports, buil - **RBAC**: Multi-layered permissions for Reporters, Investigators, and Admins. - **Owner-Based Access**: Strict isolation of ticket data based on reporter and assigned investigator. - **Secure Token Access**: Unique cryptographic tokens for anonymous ticket follow-ups. -- **Data Protection**: Secure password hashing with BCrypt and CSRF protection for all state-changing requests. +- **Data Protection**: Secure password hashing with BCrypt. - **XSS Prevention**: Automatic HTML escaping via server-side JTE rendering. - **JWT Authentication**: Supports both browser cookies and API headers with database-backed role verification. diff --git a/src/test/java/org/example/alfs/integration/TicketControllerIT.java b/src/test/java/org/example/alfs/integration/TicketControllerIT.java index eb77cc4..683195f 100644 --- a/src/test/java/org/example/alfs/integration/TicketControllerIT.java +++ b/src/test/java/org/example/alfs/integration/TicketControllerIT.java @@ -18,7 +18,6 @@ import org.springframework.transaction.annotation.Transactional; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @@ -112,8 +111,7 @@ void anonymousReporter_invalidToken_redirectsToLogin() throws Exception { void anonymousReporter_validPost_redirectsToTicketCreated() throws Exception { mockMvc.perform(post("/tickets/create") .param("title", "Test title") - .param("description", "Test description") - .with(csrf())) + .param("description", "Test description")) .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrlPattern("/tickets/ticket-created?token=*")); } @@ -123,8 +121,7 @@ void anonymousReporter_validPost_redirectsToTicketCreated() throws Exception { void anonymousReporter_blankPost_returnsCreateForm() throws Exception { mockMvc.perform(post("/tickets/create") .param("title", "") - .param("description", "") - .with(csrf())) + .param("description", "")) .andExpect(status().isOk()) .andExpect(view().name("create")) .andExpect(model().attributeHasFieldErrors("ticket", "title", "description")); @@ -184,8 +181,7 @@ void admin_canViewTicketById() throws Exception { @DisplayName("Admin can assign an investigator to a ticket") void admin_canAssignInvestigator() throws Exception { mockMvc.perform(post("/tickets/{id}/assign", ticketId) - .param("investigatorId", investigator.getId().toString()) - .with(csrf())) + .param("investigatorId", investigator.getId().toString())) .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrl("/tickets/" + ticketId)); } @@ -197,8 +193,7 @@ void admin_canUpdateTicketStatus() throws Exception { ticketService.assignInvestigator(ticketId, investigator.getId()); mockMvc.perform(post("/tickets/{id}/status", ticketId) - .param("status", "RESOLVED") - .with(csrf())) + .param("status", "RESOLVED")) .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrl("/tickets/" + ticketId)); } @@ -211,8 +206,7 @@ void admin_cannotPerformInvalidStatusTransition() throws Exception { assertEquals(org.example.alfs.enums.TicketStatus.OPEN, ticket.getStatus()); mockMvc.perform(post("/tickets/{id}/status", ticketId) - .param("status", "RESOLVED") // Transition OPEN -> RESOLVED is invalid - .with(csrf())) + .param("status", "RESOLVED")) // Transition OPEN -> RESOLVED is invalid .andExpect(status().isBadRequest()); } }