diff --git a/learn/developers/harper-applications-in-depth.mdx b/learn/developers/harper-applications-in-depth.mdx index 089f63e1f..10bde8a51 100644 --- a/learn/developers/harper-applications-in-depth.mdx +++ b/learn/developers/harper-applications-in-depth.mdx @@ -100,7 +100,7 @@ In the first guide, we introduced you to the `/health` endpoint. This is provide The **Operations API** provides a full set of capabilities for configuring, deploying, administering, and controlling Harper. It is configured on port `9925` by default, and primarily functions through JSON-based, POST requests to the root path `/`. It has some additional functionalities too such as the `/health` endpoint and an OpenAPI endpoint `/api/openapi/rest`. -The operations API root path POST requests must be authenticated. Harper provides an `authentication.authorizeLocal` configuration option for automatically authorizing any requests from the loopback IP address as the superuser (the one created during Harper installation). This option is enabled automatically when Harper is installed using the `dev` default config (as was instructed in the getting started guide). Thus, local installation users may make unauthenticated requests. Container based installation users must use `--network host` when running the container in order to make use of this option. Fabric or any other remote host installations generally must authenticate all requests. +The operations API root path POST requests must be authenticated. Harper provides an `authentication.authorizeLocal` configuration option for automatically authorizing any requests from the loopback IP address as a super user. From v5.4.0, these requests run as the built-in [`local` user](/reference/v5/security/configuration#local-request-identity); earlier versions used a stored user whose role was named `super_user`. This option is enabled automatically when Harper is installed using the `dev` default config (as was instructed in the getting started guide). Thus, local installation users may make unauthenticated requests. Container based installation users must use `--network host` when running the container in order to make use of this option. Fabric or any other remote host installations generally must authenticate all requests. :::note The `authentication.authorizeLocal` option should be disabled for any Harper servers that may be accessed by untrusted users from the same instance. For example, it should be disabled if you are using a local proxy, or for general server hardening. diff --git a/reference/cli/authentication.md b/reference/cli/authentication.md index ee766b94d..0f4734251 100644 --- a/reference/cli/authentication.md +++ b/reference/cli/authentication.md @@ -13,7 +13,7 @@ The Harper CLI handles authentication differently for local and remote operation Available since: v4.1.0 -For local operations (operations executed on the same machine where Harper is installed), the CLI communicates with Harper via Unix domain sockets instead of HTTP. Domain socket requests are automatically authenticated as the superuser, so no additional authentication parameters are required. +For local operations (operations executed on the same machine where Harper is installed), the CLI communicates with Harper via Unix domain sockets instead of HTTP. Domain socket requests are automatically authorized as a super user, so no additional authentication parameters are required. From v5.4.0, these requests run as the built-in [`local` user](../security/configuration.md#local-request-identity), independently of stored users. **Example**: diff --git a/reference/configuration/options.md b/reference/configuration/options.md index 005e5ecac..4b696ab12 100644 --- a/reference/configuration/options.md +++ b/reference/configuration/options.md @@ -139,7 +139,7 @@ authentication: refreshTokenTimeout: 30d ``` -- `authorizeLocal` — Auto-authorize loopback requests as superuser; _Default_: `true` +- `authorizeLocal` — Auto-authorize loopback requests as superuser; _Default_: `true`. From v5.4.0, these requests run as the built-in [`local` user](../security/configuration.md#local-request-identity). - `cacheTTL` — Session cache duration (ms); _Default_: `30000` - `enableSessions` — Cookie-based sessions; _Default_: `true` - `operationTokenTimeout` — Access token lifetime; _Default_: `1d` diff --git a/reference/mqtt/configuration.md b/reference/mqtt/configuration.md index 57e2d0a81..d6bdbbd9c 100644 --- a/reference/mqtt/configuration.md +++ b/reference/mqtt/configuration.md @@ -65,7 +65,7 @@ Type: `boolean` Default: `true` -Controls whether credentials are required to establish an MQTT connection. When `true`, clients must authenticate with either a username/password or a valid mTLS client certificate. +Controls whether credentials are required to establish an MQTT connection. When `true`, clients must authenticate with either a username/password or a valid mTLS client certificate, except that [`authentication.authorizeLocal`](../security/configuration.md#authorizelocal) permits raw-TCP loopback connections without CONNECT credentials. From v5.4.0, that transport trust uses the built-in [`local` super user](../security/configuration.md#local-request-identity). When set to `false`, unauthenticated connections are allowed. Unauthenticated clients are still subject to authorization on each publish and subscribe operation — by default, tables and resources do not grant access to unauthenticated users, but this can be configured at the resource level. diff --git a/reference/mqtt/overview.md b/reference/mqtt/overview.md index 7eec70b80..b48a736fc 100644 --- a/reference/mqtt/overview.md +++ b/reference/mqtt/overview.md @@ -123,7 +123,9 @@ MQTT connections support two authentication methods: - **Credential-based** — Standard MQTT username/password in the CONNECT packet. - **mTLS** — Added in v4.3.0. Mutual TLS authentication using client certificates. The `CN` (common name) from the client certificate subject is used as the Harper username by default. -Authentication is required by default (`requireAuthentication: true`). See [MQTT Configuration](./configuration) for details on disabling authentication or configuring mTLS options. +On raw-TCP loopback connections, [`authentication.authorizeLocal`](../security/configuration.md#authorizelocal) also permits access without CONNECT credentials, even when `requireAuthentication` is `true`. From v5.4.0, these locally trusted connections run as the built-in [`local` super user](../security/configuration.md#local-request-identity). + +Authentication is otherwise required by default (`requireAuthentication: true`). See [MQTT Configuration](./configuration) for details on disabling authentication or configuring mTLS options. ## Server Events API diff --git a/reference/operations-api/operations.md b/reference/operations-api/operations.md index d4d711688..d1ebc7f0f 100644 --- a/reference/operations-api/operations.md +++ b/reference/operations-api/operations.md @@ -552,7 +552,7 @@ Returns all users. ### `user_info` -Returns data for the currently authenticated user. +Returns data for the currently authenticated user. From v5.4.0, [locally trusted requests](../security/configuration.md#local-request-identity) report `username: "local"` for the built-in super user. ```json { "operation": "user_info" } @@ -625,6 +625,12 @@ Does not require prior authentication when called with `username`/`password`. Re } ``` + + +When both `username` and `password` are omitted from a [locally trusted request](../security/configuration.md#local-request-identity), Harper issues tokens for the first active stored user, in username order, whose role has the `super_user` permission. The role need not be named `super_user`. The operation and refresh tokens carry that stored user's normal claims, and the mint replaces that user's stored refresh token, as before. No token is issued for the built-in `local` identity. + +If no such stored user exists, the operation fails with HTTP 409: `no user to mint a token for; create a user first`. For ordinary tokens, supplying a `username` still requires its `password`, even on a local connection. + With `role` as an inline role object, instead mints a single **scoped token** whose bearer is limited to the embedded permissions — requires an authenticated `super_user` caller, and refuses one authenticated by a component's [Bearer validator](../http/api.md#serverregisterbearervalidatorvalidator-options); `username` is attribution only and must not name an existing user (defaults to `scoped:`); no refresh token is issued and the token cannot be revoked before expiry. See [JWT Authentication / Scoped Tokens](../security/jwt-authentication.md#scoped-tokens-inline-role). ```json diff --git a/reference/security/configuration.md b/reference/security/configuration.md index 4beb51e3e..dad245463 100644 --- a/reference/security/configuration.md +++ b/reference/security/configuration.md @@ -23,7 +23,7 @@ authentication: _Type: boolean — Default: `true`_ -Automatically authorizes requests from the loopback IP address (`127.0.0.1` or `::1`) as the superuser, without requiring credentials. Disable this for any Harper server that may be accessed by untrusted users from the same instance — for example, when using a local proxy or for general server hardening. +Automatically authorizes requests from a loopback IP address (such as `127.0.0.1` or `::1`) as a super user, without requiring credentials. This also applies to raw-TCP MQTT connections from loopback when no credentials are supplied. Disable this for any Harper server that may be accessed by untrusted users from the same instance — for example, when using a local proxy or for general server hardening. Three things to know before relying on either setting: @@ -33,6 +33,16 @@ Three things to know before relying on either setting: For why this matters to a CI pipeline whose token has expired, see [Token credentials for CI/CD](../cli/authentication.md#token-credentials-for-cicd). +#### Local request identity + + + +Requests trusted by `authorizeLocal` or the operations API domain socket run as a built-in super user named `local`, with no record in `system.hdb_user`. Previously, they ran as the first stored user whose role was named `super_user`. Local socket and CLI access now work even when no users exist or the administrator's role has another name. Explicit credentials still authenticate as the supplied user. + +For these requests, `user_info` returns `username: "local"`, and audit-log entries, job owners, and other user attribution read `local`. [Creating authentication tokens](../operations-api/operations.md#create_authentication_tokens) selects a stored user instead. + +Local trust is never saved as session authentication: a cookie created during a locally trusted request does not authenticate anyone when used from elsewhere. Logging in with real credentials over a local connection still creates a normal session for that user. + ### `cacheTTL` _Type: number — Default: `30000`_ @@ -47,6 +57,8 @@ _Type: boolean — Default: `true`_ Enables cookie-based sessions to maintain an authenticated session across requests. This is the preferred authentication mechanism for web browsers: cookies hold the token securely without exposing it to JavaScript, reducing XSS vulnerability risk. +See [Local request identity](#local-request-identity) for why transport trust does not authenticate a session. + ### `operationTokenTimeout` _Type: string — Default: `1d`_ diff --git a/reference/security/jwt-authentication.md b/reference/security/jwt-authentication.md index 1fcef008b..5dc2c98f7 100644 --- a/reference/security/jwt-authentication.md +++ b/reference/security/jwt-authentication.md @@ -18,7 +18,9 @@ JWT authentication uses two token types: ## Create Authentication Tokens -Call `create_authentication_tokens` with your Harper credentials. When the request carries a `username` and `password` in the body, no `Authorization` header is required — the operation authenticates from the body. Other shapes of this operation do need an authenticated caller: sending no credentials at all mints tokens for the user the request is already authenticated as, and [minting a scoped token](#scoped-tokens-inline-role) requires an authenticated `super_user`. A request authenticated by a component's [Bearer validator](../http/api.md#serverregisterbearervalidatorvalidator-options) can do neither: it must send a `username` and `password` to mint ordinary tokens, and cannot mint a scoped token. +Call `create_authentication_tokens` with your Harper credentials. When the request carries a `username` and `password` in the body, no `Authorization` header is required — the operation authenticates from the body. Other shapes of this operation do need an authenticated caller: sending no credentials at all normally mints tokens for the user the request is already authenticated as, and [minting a scoped token](#scoped-tokens-inline-role) requires an authenticated `super_user`. A request authenticated by a component's [Bearer validator](../http/api.md#serverregisterbearervalidatorvalidator-options) can do neither: it must send a `username` and `password` to mint ordinary tokens, and cannot mint a scoped token. + +From v5.4.0, omitting both `username` and `password` from a request trusted by [`authorizeLocal` or the operations API domain socket](./configuration.md#local-request-identity) instead mints ordinary tokens for an active stored super user, never the built-in `local` identity. See [`create_authentication_tokens`](../operations-api/operations.md#create_authentication_tokens) for user selection, refresh-token replacement, and the error when no eligible user exists. ```json { diff --git a/reference/users-and-roles/operations.md b/reference/users-and-roles/operations.md index c0c763d39..abfd6e733 100644 --- a/reference/users-and-roles/operations.md +++ b/reference/users-and-roles/operations.md @@ -116,6 +116,8 @@ _Restricted to `super_user` roles._ Returns user data for the currently authenticated user. Available to all roles. +From v5.4.0, requests trusted by [`authorizeLocal` or the operations API domain socket](../security/configuration.md#local-request-identity) return `username: "local"` for the built-in super user. + ```json { "operation": "user_info" @@ -141,6 +143,12 @@ _Restricted to `super_user` roles._ } ``` + + +The username `local` is reserved for [requests trusted by their transport](../security/configuration.md#local-request-identity). `add_user` rejects it with HTTP 400: `'local' is a reserved username: it identifies requests trusted by their transport (authorizeLocal, the operations domain socket)`. + +A stored user named `local` created before this change still authenticates as an ordinary stored user and can be altered or dropped. To avoid confusing it with the built-in identity, create a replacement under another name, update clients to use it, then drop the old user. Usernames cannot be changed in place. + ### Alter User _Restricted to `super_user` roles._ diff --git a/release-notes/v5-lincoln/5.4.md b/release-notes/v5-lincoln/5.4.md index b64b22c0f..95754bf45 100644 --- a/release-notes/v5-lincoln/5.4.md +++ b/release-notes/v5-lincoln/5.4.md @@ -224,6 +224,10 @@ Standard Node.js builds are unchanged. See [Native Addons on Pointer-Compression ## Authentication +### Local Requests Use a Built-in User + +Requests trusted by `authorizeLocal`, the operations API domain socket (including the local CLI), or raw-TCP MQTT loopback under `authorizeLocal` now run as a built-in super user named `local`, independently of stored users. Attribution such as audit entries and job owners now reads `local`. New users cannot be named `local`; an existing stored user with that name keeps working. Credential-free token minting still issues tokens for a stored super user and fails with HTTP 409 if none is eligible. Local trust is not saved in sessions. See [Local request identity](/reference/v5/security/configuration#local-request-identity), [`add_user`](/reference/v5/users-and-roles/operations#add-user), and [`create_authentication_tokens`](/reference/v5/operations-api/operations#create_authentication_tokens) ([harper#3755](https://github.com/HarperFast/harper/pull/3755)). + ### Component Bearer Validators `server.registerBearerValidator()` lets a component accept `Authorization: Bearer` tokens Harper did not issue, such as access tokens from its own OAuth authorization server. A validator maps a token to a Harper username; Harper resolves that user through `server.getUser()` and applies its role on every Harper route on the application port, including REST, GraphQL, WebSocket, MQTT over WebSocket and MCP. See [`server.registerBearerValidator()`](/reference/v5/http/api#serverregisterbearervalidatorvalidator-options).