Skip to content

Secure Notes Platform is a full-stack, security-focused demonstration system that showcases modern secure software development practices across a complete client–server architecture.

Notifications You must be signed in to change notification settings

CurtisSlone/secure-notes-platform

Repository files navigation

Secure Notes API

A security-focused REST API built with Spring Boot that demonstrates enterprise-grade authentication and authorization patterns. This application implements a defense-in-depth security model combining mutual TLS (mTLS), JSON Web Tokens (JWT), and Role-Based Access Control (RBAC).

Overview

Secure Notes API is a note-taking service that allows users to create, read, update, and delete personal notes. The application prioritizes security at every layer, making it an excellent reference for implementing secure APIs in enterprise environments.

Key Features

  • Mutual TLS (mTLS): Transport-layer security requiring both client and server certificate authentication
  • JWT Authentication: Stateless application-layer authentication with signed tokens
  • Role-Based Access Control: Fine-grained authorization with USER and ADMIN roles
  • Audit Logging: Comprehensive logging of all security-relevant events
  • Input Validation: Request validation using Bean Validation annotations

Security Architecture

The application implements a three-layer security model:

┌─────────────────────────────────────────────────────────────┐
│                     Client Request                          │
└─────────────────────────────┬───────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Layer 1: mTLS                            │
│                                                             │
│  • Server presents certificate to client                    │
│  • Client must present valid certificate to server          │
│  • Connection rejected at TLS handshake if invalid          │
│  • Provides transport encryption and client identity        │
└─────────────────────────────┬───────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 Layer 2: JWT Authentication                 │
│                                                             │
│  • Client sends JWT in Authorization header                 │
│  • Server validates signature, expiration, and claims       │
│  • Extracts user identity and roles from token              │
│  • Rejects requests with invalid or expired tokens          │
└─────────────────────────────┬───────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                 Layer 3: RBAC Authorization                 │
│                                                             │
│  • Checks user role against endpoint requirements           │
│  • Enforces resource ownership rules                        │
│  • ADMIN role has elevated privileges                       │
│  • USER role restricted to own resources                    │
└─────────────────────────────┬───────────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                   Application Logic                         │
│                                                             │
│  • Process request                                          │
│  • Log audit event                                          │
│  • Return response                                          │
└─────────────────────────────────────────────────────────────┘

Layer 1: Mutual TLS (mTLS)

Traditional TLS only authenticates the server to the client. Mutual TLS extends this by also requiring the client to present a valid certificate, providing two-way authentication at the transport layer.

Implementation Details:

  • Server certificate stored in PKCS12 keystore (keystore.p12)
  • Trusted client certificates stored in truststore (truststore.p12)
  • Configured via application.yml with client-auth: need
  • Connections without valid client certificates are rejected during TLS handshake

Benefits:

  • Prevents unauthorized network access before reaching application code
  • Provides cryptographic proof of client identity
  • Enables zero-trust network architecture

Layer 2: JWT Authentication

JSON Web Tokens provide stateless authentication at the application layer. After successful login, clients receive a signed token containing their identity and roles.

Token Structure:

{
  "sub": "alice",
  "roles": "USER",
  "iat": 1702312800,
  "exp": 1702399200
}

Implementation Details:

  • Tokens signed using HMAC-SHA384 algorithm
  • Configurable secret key via environment variable
  • 24-hour token expiration (configurable)
  • Custom JwtAuthenticationFilter extracts and validates tokens

Security Measures:

  • Signature verification prevents token tampering
  • Expiration checking prevents use of stale tokens
  • No server-side session storage (stateless)

Layer 3: Role-Based Access Control (RBAC)

RBAC restricts system access based on user roles, implementing the principle of least privilege.

Roles:

Role Capabilities
USER Create, read, update, delete own notes
ADMIN All USER capabilities plus access to all notes, audit logs, and admin endpoints

Access Rules:

Endpoint USER ADMIN
GET /notes Own notes only Own notes only
POST /notes
GET /notes/{id} Own notes only Any note
PUT /notes/{id} Own notes only Own notes only
DELETE /notes/{id} Own notes only Any note
GET /admin/notes
GET /admin/audit/logs

Audit Logging

All security-relevant events are logged to the database for compliance and forensic analysis.

Logged Events:

  • LOGIN_SUCCESS / LOGIN_FAILURE: Authentication attempts
  • CREATE_NOTE / UPDATE_NOTE / DELETE_NOTE: Data modifications
  • ADMIN_ACCESS: Administrative endpoint access

Log Entry Structure:

Field Description
timestamp When the event occurred
username User who performed the action
action Type of action performed
resourceType Type of resource affected (e.g., NOTE)
resourceId Identifier of affected resource

Technology Stack

Component Technology
Framework Spring Boot 3.2.5
Language Java 17
Build Tool Gradle 8.7
Database PostgreSQL 16
Security Spring Security 6
JWT Library jjwt 0.12.5
Validation Jakarta Bean Validation
Testing JUnit 5, Mockito, Spring Boot Test

Project Structure

src/main/java/com/securenotes/
├── SecureNotesApplication.java      # Application entry point
├── config/
│   ├── DataSeeder.java              # Initial data population
│   └── SecurityConfig.java          # Spring Security configuration
├── controller/
│   ├── AuthController.java          # Authentication endpoints
│   ├── NoteController.java          # Note CRUD endpoints
│   └── AdminController.java         # Administrative endpoints
├── dto/
│   ├── AuthRequest.java             # Login request payload
│   ├── AuthResponse.java            # Login response with token
│   ├── CreateNoteRequest.java       # Note creation payload
│   ├── UpdateNoteRequest.java       # Note update payload
│   └── NoteResponse.java            # Note response payload
├── entity/
│   ├── User.java                    # User entity
│   ├── Note.java                    # Note entity
│   └── AuditLogEntry.java           # Audit log entity
├── repository/
│   ├── UserRepository.java          # User data access
│   ├── NoteRepository.java          # Note data access
│   └── AuditLogEntryRepository.java # Audit log data access
├── security/
│   ├── JwtUtil.java                 # JWT generation and validation
│   └── JwtAuthenticationFilter.java # Request filter for JWT processing
└── service/
    ├── AuthService.java             # Authentication logic
    ├── NoteService.java             # Note business logic
    └── AuditService.java            # Audit logging logic

API Reference

Authentication

Login

POST /auth/login
Content-Type: application/json

{
  "username": "alice",
  "password": "password123"
}

Response (200 OK):

{
  "token": "eyJhbGciOiJIUzM4NCJ9..."
}

Notes

All note endpoints require a valid JWT in the Authorization header:

Authorization: Bearer <token>

List Notes

GET /notes

Returns all notes owned by the authenticated user.

Create Note

POST /notes
Content-Type: application/json

{
  "title": "My Note",
  "content": "Note content here"
}

Get Note

GET /notes/{id}

Returns the note if owned by user or user is ADMIN.

Update Note

PUT /notes/{id}
Content-Type: application/json

{
  "title": "Updated Title",
  "content": "Updated content"
}

Only the note owner can update.

Delete Note

DELETE /notes/{id}

Owner or ADMIN can delete.

Admin Endpoints

Require ADMIN role.

List All Notes

GET /admin/notes

Get Audit Logs

GET /admin/audit/logs

Health Check

GET /actuator/health

Public endpoint for container orchestration.

Getting Started

Prerequisites

  • Docker and Docker Compose
  • VS Code with Dev Containers extension
  • Git

Development Setup

  1. Clone the repository:

    git clone <repository-url>
    cd secure-notes-api
  2. Open in VS Code:

    code .
  3. Start Dev Container:

    • VS Code will prompt: "Reopen in Container"
    • Click "Reopen in Container"
    • Wait for the container to build
  4. Verify the environment:

    java --version    # Java 17
    gradle --version  # Gradle 8.7

Generate Certificates

For mTLS to work, you need to generate certificates:

# Create certificates directory
mkdir -p certs

# Generate server keystore
keytool -genkeypair \
  -alias securenotes \
  -keyalg RSA \
  -keysize 2048 \
  -storetype PKCS12 \
  -keystore certs/keystore.p12 \
  -validity 365 \
  -storepass changeit \
  -dname "CN=localhost, OU=Dev, O=SecureNotes, L=City, ST=State, C=US"

# Generate client certificate
keytool -genkeypair \
  -alias client \
  -keyalg RSA \
  -keysize 2048 \
  -storetype PKCS12 \
  -keystore certs/client.p12 \
  -validity 365 \
  -storepass changeit \
  -dname "CN=client, OU=Dev, O=SecureNotes, L=City, ST=State, C=US"

# Export client certificate
keytool -exportcert \
  -alias client \
  -keystore certs/client.p12 \
  -storepass changeit \
  -file certs/client.crt

# Create truststore with client certificate
keytool -importcert \
  -alias client \
  -file certs/client.crt \
  -keystore certs/truststore.p12 \
  -storetype PKCS12 \
  -storepass changeit \
  -noprompt

Running the Application

./gradlew bootRun

The application starts on https://localhost:8443.

Test Users

The application seeds two test users on startup:

Username Password Role
alice password123 USER
admin adminpass ADMIN

Testing

Running Tests

# All tests
./gradlew test

# Unit tests only
./gradlew test --tests "com.securenotes.security.*"
./gradlew test --tests "com.securenotes.service.*"

# Integration tests only
./gradlew test --tests "com.securenotes.controller.*"

Test Coverage

Category Tests Description
Unit - JwtUtil 9 Token generation, validation, claim extraction
Unit - JwtAuthenticationFilter 5 Request filtering, authentication setup
Unit - AuthService 6 Login logic, audit logging
Unit - NoteService 8 CRUD operations
Unit - AuditService 3 Audit log creation
Integration - AuthController 5 Login endpoint, validation
Integration - NoteController 16 CRUD, ownership, authorization
Integration - AdminController 7 Admin access, role enforcement
Total 59

Manual Testing with cURL

Without mTLS (will fail)

curl -k https://localhost:8443/actuator/health
# Result: SSL handshake error

With mTLS

# Health check
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  https://localhost:8443/actuator/health

# Login
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  -X POST https://localhost:8443/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "password123"}'

# Save token
TOKEN="<token-from-login-response>"

# Create note
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  -X POST https://localhost:8443/notes \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Test Note", "content": "Hello, World!"}'

# List notes
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  -H "Authorization: Bearer $TOKEN" \
  https://localhost:8443/notes

Testing Authorization

# Login as alice (USER role)
TOKEN_ALICE=$(curl -s -k --cert-type P12 --cert certs/client.p12:changeit \
  -X POST https://localhost:8443/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "alice", "password": "password123"}' | grep -o '"token":"[^"]*"' | cut -d'"' -f4)

# Login as admin (ADMIN role)
TOKEN_ADMIN=$(curl -s -k --cert-type P12 --cert certs/client.p12:changeit \
  -X POST https://localhost:8443/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "adminpass"}' | grep -o '"token":"[^"]*"' | cut -d'"' -f4)

# Alice tries to access admin endpoint (should fail with 403)
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  -H "Authorization: Bearer $TOKEN_ALICE" \
  https://localhost:8443/admin/notes

# Admin accesses admin endpoint (should succeed)
curl -k --cert-type P12 --cert certs/client.p12:changeit \
  -H "Authorization: Bearer $TOKEN_ADMIN" \
  https://localhost:8443/admin/notes

Python CLI Client

A companion Python CLI tool is available in the py-cli/ directory for interacting with the API.

Installation

cd py-cli
python3 -m venv .venv
source .venv/bin/activate
pip install -e .

Usage

# Login
securenotes login -u alice -p password123

# Create a note
securenotes notes create -t "My Note" -c "Content here"

# List notes
securenotes notes list

# Admin commands (requires ADMIN role)
securenotes login -u admin -p adminpass
securenotes admin notes
securenotes admin logs

Configuration

Environment Variables

Variable Description Default
SPRING_DATASOURCE_URL Database JDBC URL jdbc:postgresql://db:5432/securenotes
SPRING_DATASOURCE_USERNAME Database username postgres
SPRING_DATASOURCE_PASSWORD Database password postgres
JWT_SECRET Secret key for signing JWTs (development default)
SSL_KEYSTORE Path to server keystore certs/keystore.p12
SSL_KEYSTORE_PASSWORD Keystore password changeit
SSL_TRUSTSTORE Path to truststore certs/truststore.p12
SSL_TRUSTSTORE_PASSWORD Truststore password changeit

Production Considerations

  • Use strong, unique passwords for all keystores
  • Store secrets in a secrets manager (e.g., Azure Key Vault, HashiCorp Vault)
  • Use certificates signed by a trusted CA
  • Enable database connection encryption
  • Configure appropriate token expiration times
  • Implement rate limiting
  • Set up monitoring and alerting

License

This project is for educational and portfolio purposes.

Author

Built as a demonstration of enterprise security patterns in Spring Boot applications.

About

Secure Notes Platform is a full-stack, security-focused demonstration system that showcases modern secure software development practices across a complete client–server architecture.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published