No description
Find a file
Uwe Schuster f43f5f0633 #6: route ad-hoc JSON through ObjectMapper (Option A — DI everywhere, all-in-one)
- New dto/InternalDto.hpp with JsonErrorDto, WsEntityEventDto,
  WsPresenceUpdateDto, WsClientMsgDto.

- JsonErrorHandler: now takes a shared ObjectMapper (DI). Body built
  via writeToString on JsonErrorDto. Closes the audit's concrete bug
  where status.description was embedded raw — a Status with a `"`/`\\`
  in the description previously emitted invalid JSON.

- AuthInterceptor: takes an optional ObjectMapper ctor arg (defaults to
  a fresh mapper). makeForbidden's `msg` is now serialised via
  JsonErrorDto + ObjectMapper, so a `"` in a forbidden-reason no longer
  breaks the response envelope.

- Hub: process-wide sharedMapper() with optional setObjectMapper()
  override. buildPresenceMsg / notifyBooking / notifyPerson all go
  through ObjectMapper-emitted DTOs. User-supplied IDs / property IDs
  / usernames containing `"`/`\\`/control chars are now escaped.

- Listener: jsonStr/jsonInt regex parsers gone. handleMessage parses
  inbound frames via ObjectMapper::readFromString into WsClientMsgDto.
  Malformed JSON / nested objects / escaped quotes — previously silent
  corruption — now produce a clean drop of the frame.

- test/test_json_serialization.cpp: 4 cases pinning the round-trip
  behaviour (special chars in usernames, IDs, status.description, and
  malformed-input rejection).

Bump to 0.4.0 — ctor signatures changed (additive defaults, but the
behaviour of the JSON envelopes is now governed by ObjectMapper).

Closes #6

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 21:56:05 +02:00
cmake v0.1.0: initial clean-lift from fewo-webapp 2026-04-21 21:42:53 +02:00
docs v0.1.0: initial clean-lift from fewo-webapp 2026-04-21 21:42:53 +02:00
include/oatpp-authkit #6: route ad-hoc JSON through ObjectMapper (Option A — DI everywhere, all-in-one) 2026-04-25 21:56:05 +02:00
test #6: route ad-hoc JSON through ObjectMapper (Option A — DI everywhere, all-in-one) 2026-04-25 21:56:05 +02:00
.gitignore v0.1.0: initial clean-lift from fewo-webapp 2026-04-21 21:42:53 +02:00
CMakeLists.txt #6: route ad-hoc JSON through ObjectMapper (Option A — DI everywhere, all-in-one) 2026-04-25 21:56:05 +02:00
README.md #2: Browser-friendly 401/403 — content-negotiate JSON vs HTML/redirect 2026-04-25 13:23:08 +02:00

oatpp-authkit

Header-only C++ library distilled from fewo-webapp's hardened auth / security stack. Header-only, oatpp 1.3+, C++17.

What's in v0.1 (the clean-lift set)

Header Purpose
interceptor/SecurityHeadersInterceptor.hpp CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. Strict defaults.
interceptor/BodySizeLimitInterceptor.hpp Reject request bodies above a configurable limit with 413 before they hit your handlers.
handler/JsonErrorHandler.hpp Normalises thrown exceptions into {status, message} JSON so controllers never leak raw HTML error pages.
util/RateLimiter.hpp In-memory token-bucket keyed on an arbitrary string (typically the client IP from clientIpTrusted).
util/TokenExtract.hpp extractToken (Cookie/Bearer), isValidIp (IPv4/IPv6 via inet_pton), clientIpTrusted (loopback-gated XFF).
startup/RequireEncryptionKey.hpp requireEncryptionKey(envVarName, encryptionEnabled, allowPlaintext) — refuse startup without a symmetric key unless a dev flag overrides.

Consume via CMake

# FetchContent (pin to a tag):
include(FetchContent)
FetchContent_Declare(oatpp-authkit
    GIT_REPOSITORY https://git.uwe-schuster.info/uwe.admin/oatpp-authkit.git
    GIT_TAG v0.1.0)
FetchContent_MakeAvailable(oatpp-authkit)

target_link_libraries(app PRIVATE oatpp::authkit)

Or after cmake --install:

find_package(oatpp-authkit 0.1 REQUIRED)
target_link_libraries(app PRIVATE oatpp::authkit)

Browser-friendly 401/403

By default AuthInterceptor returns application/json for every rejection, which is correct for /api/* callers but breaks browser navigation: a user following a stale link or an expired password-reset URL sees a raw {"status":"Unauthorized"} instead of a real page.

Override IAuthPolicy::unauthenticatedRedirect(path) to redirect browser navigations to a login or landing page while keeping JSON responses for fetch/axios callers (detected via path prefix /api/, X-Requested-With: XMLHttpRequest, or an Accept header that prefers application/json):

class AppAuthPolicy : public oatpp_authkit::IAuthPolicy {
public:
    std::optional<std::string>
    unauthenticatedRedirect(const std::string& path) override {
        return "/?next=" + oatpp_authkit::AuthInterceptor::urlEncode(path);
    }
};

Returning std::nullopt (the default) preserves the legacy JSON behaviour for all responses.

Tests

cmake -B build -DOATPP_AUTHKIT_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure

Tests are off by default so consumers pulling the library in via FetchContent don't pay the cost.

Roadmap

  • v0.2AuthInterceptor + requireAdmin ported onto three seams (IAuthBackend, IAuthPolicy, IRuntimeConfig) so consumers plug in their own user store, public-path list, and admin role set without forking the interceptor.
  • Later — session cookie helpers, API-key rotation, re-encryption migration.

See docs/security-baseline.md for language-neutral CSP / rate-limit / body-size constants that non-C++ consumers can re-implement directly.