One should not access s.opts directly but instead use s.getOpts().
Also, server lock needs to be released when performing an account
lookup (since this may result in server lock being acquired).
A function was calling s.LookupAccount under the client lock, which
technically creates a lock inversion situation.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
New configuration fields:
```
cluster {
...
pool_size: 5
accounts: ["A", "B"]
}
```
The configuration `pool_size` in the example above means that this
server will create 5 routes to a remote server, assuming that that
server has the same `pool_size` setting.
Accounts (which are not part of the `accounts[]` configuration)
are assigned a specific route in this pool, and this will be the
same route on all servers in the cluster.
Accounts that are defined in the `accounts` field will each have
a dedicated route connection. This will allow suppression of the
account name in some of the route protocols, reducing bytes transmitted
which may increase performance.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This adds the ability to augment or override the NATS auth system.
A server will send a signed request to $SYS.REQ.USER.AUTH on the specified account. The request will contain client information, all client options sent to the server, and optionally TLS information and client certificates.
The external auth service will respond with an empty message if not authorized, or a signed User JWT that the user will bind to.
The response can change the account the client will be bound to.
Signed-off-by: Derek Collison <derek@nats.io>
This will be used mainly by CustomClientAuthentication implementations
to indicate that the user connection should be disconnected at some
point in future - like when a certificate or token expires
Signed-off-by: R.I.Pienaar <rip@devco.net>
If the `no_auth_user` is set in the `websocket{}` block and a
server creates a leafnode connection using the websocket port,
and does not provide credentials, that no_auth_user should be
used, but was not.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
Scoped signing keys allow for optional values in allow rules
If an allow rule therefore gets removed because a tag is not present,
the removal needs to be compensated by adding in a deny >
Signed-off-by: Matthias Hanel <mh@synadia.com>
ordering of templates got messed up by a map (now removed)
Also improved error message when template generation fails
Signed-off-by: Matthias Hanel <mh@synadia.com>
For security reasons we have introduced scoped signing keys to jwt.
They carry user permissions.
Wich is why jwt issued by those keys are not allowed to carry their own permission.
Instead they are copied from the signing key.
If the scoped signing key gets compromised, an attacker can only issue jwt with the permissions of the key.
With a plain signing key, an attacker can create arbitrary user with permissions.
Because user jwt creation is greatly simplified we added a single utility function to go/java/.net which issues user for such keys.
This is function is documented in ADR-14:
```
/**
* signingKey, is a mandatory account nkey pair to sign the generated jwt.
* accountId, is a mandatory public account nkey. Will return error when not set or not account nkey.
* publicUserKey, is a mandatory public user nkey. Will return error when not set or not user nkey.
* name, optional human readable name. When absent, default to publicUserKey.
* expiration, optional but recommended duration, when the generated jwt needs to expire. If not set, JWT will not expire.
* tags, optional list of tags to be included in the JWT.
*
* Returns:
* error, when issues arose.
* string, resulting jwt.
**/
IssueUserJWT(signingKey nkey, accountId string, publicUserKey string, name string, expiration time.Duration, tags []string) (error, string)
```
Currently the only downside of this is that the permissions are static and can't be tailored to the user.
This PR changes that by allowing the user pub/sub permissions to be parameterized with templates.
templates are for entire tokens only and include:
{{name()}} -> username
{{subject()}} -> user subject (nkey)
{{account-name()}} -> users account name
{{account-subject()}} -> user accoutn subject (nkey)
{{tag(arbitrary-prefix)}}
provided the tag "arbitrary-prefix:value" will result in "value"
provided the tags ["arbitrary-prefix:1", "arbitrary-prefix:2"] will result in two subjects "1" & "2"
If the resulting subject is not valid.
Say a tag is not present or name is not set.
This will result in an error for deny subjects
and result in no subject for allow subject.
Signed-off-by: Matthias Hanel <mh@synadia.com>
Signed-off-by: Matthias Hanel <mh@synadia.com>
This is due to a re-entrant RLock(). It works sometimes, but if there
is a go routine requesting the write lock, then the second RLock()
will not be granted which will lead to a deadlock.
In summary: one should never make re-entrant RLock calls.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
Along a leaf node connection, unless the system account is shared AND the JetStream domain name is identical, the default JetStream traffic (without a domain set) will be denied.
As a consequence, all clients that wants to access a domain that is not the one in the server they are connected to, a domain name must be specified.
Affected from this change are setups where: a leaf node had no local JetStream OR the server the leaf node connected to had no local JetStream.
One of the two accounts that are connected via a leaf node remote, must have no JetStream enabled.
The side that does not have JetStream enabled, will loose JetStream access and it's clients must set `nats.Domain` manually.
For workarounds on how to restore the old behavior, look at:
https://github.com/nats-io/nats-server/pull/2693#issuecomment-996212582
New config values added:
`default_js_domain` is a mapping from account to domain, settable when JetStream is not enabled in an account.
`extension_hint` are hints for non clustered server to start in clustered mode (and be usable to extend)
`js_domain` is a way to set the JetStream domain to use for mqtt.
Signed-off-by: Matthias Hanel <mh@synadia.com>
For TLS configuration with `verify_and_map` set to true, if a
connection connects and has a certificate with ID that matches
a user, but that user's `allowed_connection_types` is specified
and does not have the connection type in its list, then the
server will panic.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
Check for a no_auth_user should be done only when no authentication
at all is provided by the user. This was not the case. For instance,
if the user provided a token, the server would still check for
no_auth_user if users are defined. It was not really an issue since
the admin cannot configure users AND token, but it is better for
the application to fail if providing a token that is actually not
being used. If the admin configures a no_auth_user, this should
be used only when no authentication is provided.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This was missing since WEBSOCKET allowed connection type is really
used for client connections.
If one wants to limit a configured user to leafnode connections,
including if the connection is over websocket, but does not
want an application to connect over websocket using this user,
this would have been impossible to configure.
The JWT library has been updated to add LEAFNODE_WS and MQTT_WS for
future work.
Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
option name: resolver_pinned_accounts
Contains a list of public account nkeys.
Connecting user of leaf nodes need to be signed by this.
The system account will always be able to connect.
Signed-off-by: Matthias Hanel <mh@synadia.com>
* [adding] kind and client_type to client info. specifically account connect/disconnect events
Kind is Client/Leafnode but can take the value of Router/Gateway/JetStream/Account/System in the future.
When kind is Client, then client_type is set to mqtt/websocket/nats
This fixes#2291
Signed-off-by: Matthias Hanel <mh@synadia.com>
* [changed] pinned certs to check the server connected to as well
on reload clients with removed pinned certs will be disconnected.
The check happens only on tls handshake now.
Signed-off-by: Matthias Hanel <mh@synadia.com>
* [added] pinned_cert option to tls block hex(sha256(spki))
When read form config, the values are automatically lower cased.
The check when seeing the values programmatically requires
lower case to avoid having to alter the map at this point.
Signed-off-by: Matthias Hanel <mh@synadia.com>
This structure is used in ClientAuthentication, an interface
designed to let 3rd parties extend the authentication mechanisms
of the server
In order to allow those 3rd parties to create unit tests, mocks etc
we need to export this structure so it's accessible externally
Signed-off-by: R.I.Pienaar <rip@devco.net>
we want to auto-suppress JetStream traffic on normal accounts.
We also now track remote accounts so that client info headers can be remapped.
Signed-off-by: Derek Collison <derek@nats.io>
* [fixed] issue where verify_and_map: true in leaf node config was not used
This broke the setup in such a way that any connect relying on this would have failed.
This also fixes an issue where specifying no account did not result in using $G.
Signed-off-by: Matthias Hanel <mh@synadia.com>
This will cause the server to not trust accounts/user signed by an
identity key
The boot strapping system account will assume the account is issued by
the operator.
If this is not desirable, the system account can be provided right away
as resolver_preload.
[fixes] crash when the system account uses signing keys and an update changes that key set.
Signed-off-by: Matthias Hanel <mh@synadia.com>