- 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> |
||
|---|---|---|
| cmake | ||
| docs | ||
| include/oatpp-authkit | ||
| test | ||
| .gitignore | ||
| CMakeLists.txt | ||
| README.md | ||
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.2 —
AuthInterceptor+requireAdminported 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.