• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nats-io / nats-server / 24949216239

24 Apr 2026 08:34AM UTC coverage: 80.645% (-2.4%) from 83.05%
24949216239

push

github

web-flow
(2.14) [ADDED] `RemoteLeafOpts.IgnoreDiscoveredServers` option (#8067)

For a given leafnode remote, if this is set to true, this remote will
ignore any server leafnode URLs returned by the hub, allowing the user
to fully manage the servers this remote can connect to.

Resolves #8002

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>

74685 of 92610 relevant lines covered (80.64%)

632737.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.81
/server/auth.go
1
// Copyright 2012-2025 The NATS Authors
2
// Licensed under the Apache License, Version 2.0 (the "License");
3
// you may not use this file except in compliance with the License.
4
// You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software
9
// distributed under the License is distributed on an "AS IS" BASIS,
10
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
// See the License for the specific language governing permissions and
12
// limitations under the License.
13

14
package server
15

16
import (
17
        "crypto/sha256"
18
        "crypto/subtle"
19
        "crypto/tls"
20
        "crypto/x509/pkix"
21
        "encoding/asn1"
22
        "encoding/base64"
23
        "encoding/hex"
24
        "fmt"
25
        "net"
26
        "net/url"
27
        "regexp"
28
        "slices"
29
        "strings"
30
        "sync/atomic"
31
        "time"
32

33
        "github.com/nats-io/jwt/v2"
34
        "github.com/nats-io/nats-server/v2/internal/ldap"
35
        "github.com/nats-io/nkeys"
36
        "golang.org/x/crypto/bcrypt"
37
)
38

39
// Authentication is an interface for implementing authentication
40
type Authentication interface {
41
        // Check if a client is authorized to connect
42
        Check(c ClientAuthentication) bool
43
}
44

45
// ClientAuthentication is an interface for client authentication
46
type ClientAuthentication interface {
47
        // GetOpts gets options associated with a client
48
        GetOpts() *ClientOpts
49
        // GetTLSConnectionState if TLS is enabled, TLS ConnectionState, nil otherwise
50
        GetTLSConnectionState() *tls.ConnectionState
51
        // RegisterUser optionally map a user after auth.
52
        RegisterUser(*User)
53
        // RemoteAddress expose the connection information of the client
54
        RemoteAddress() net.Addr
55
        // GetNonce is the nonce presented to the user in the INFO line
56
        GetNonce() []byte
57
        // Kind indicates what type of connection this is matching defined constants like CLIENT, ROUTER, GATEWAY, LEAF etc
58
        Kind() int
59
}
60

61
// NkeyUser is for multiple nkey based users
62
type NkeyUser struct {
63
        Nkey                   string              `json:"user"`
64
        Issued                 int64               `json:"issued,omitempty"` // this is a copy of the issued at (iat) field in the jwt
65
        Permissions            *Permissions        `json:"permissions,omitempty"`
66
        Account                *Account            `json:"account,omitempty"`
67
        SigningKey             string              `json:"signing_key,omitempty"`
68
        AllowedConnectionTypes map[string]struct{} `json:"connection_types,omitempty"`
69
        ProxyRequired          bool                `json:"proxy_required,omitempty"`
70
}
71

72
// User is for multiple accounts/users.
73
type User struct {
74
        Username               string              `json:"user"`
75
        Password               string              `json:"password"`
76
        Permissions            *Permissions        `json:"permissions,omitempty"`
77
        Account                *Account            `json:"account,omitempty"`
78
        ConnectionDeadline     time.Time           `json:"connection_deadline,omitempty"`
79
        AllowedConnectionTypes map[string]struct{} `json:"connection_types,omitempty"`
80
        ProxyRequired          bool                `json:"proxy_required,omitempty"`
81
}
82

83
// clone performs a deep copy of the User struct, returning a new clone with
84
// all values copied.
85
func (u *User) clone() *User {
11,580✔
86
        if u == nil {
11,581✔
87
                return nil
1✔
88
        }
1✔
89
        clone := &User{}
11,579✔
90
        *clone = *u
11,579✔
91
        // Account is not cloned because it is always by reference to an existing struct.
11,579✔
92
        clone.Permissions = u.Permissions.clone()
11,579✔
93

11,579✔
94
        if u.AllowedConnectionTypes != nil {
11,592✔
95
                clone.AllowedConnectionTypes = make(map[string]struct{})
13✔
96
                for k, v := range u.AllowedConnectionTypes {
31✔
97
                        clone.AllowedConnectionTypes[k] = v
18✔
98
                }
18✔
99
        }
100

101
        return clone
11,579✔
102
}
103

104
// clone performs a deep copy of the NkeyUser struct, returning a new clone with
105
// all values copied.
106
func (n *NkeyUser) clone() *NkeyUser {
12✔
107
        if n == nil {
12✔
108
                return nil
×
109
        }
×
110
        clone := &NkeyUser{}
12✔
111
        *clone = *n
12✔
112
        // Account is not cloned because it is always by reference to an existing struct.
12✔
113
        clone.Permissions = n.Permissions.clone()
12✔
114

12✔
115
        if n.AllowedConnectionTypes != nil {
13✔
116
                clone.AllowedConnectionTypes = make(map[string]struct{})
1✔
117
                for k, v := range n.AllowedConnectionTypes {
2✔
118
                        clone.AllowedConnectionTypes[k] = v
1✔
119
                }
1✔
120
        }
121

122
        return clone
12✔
123
}
124

125
// SubjectPermission is an individual allow and deny struct for publish
126
// and subscribe authorizations.
127
type SubjectPermission struct {
128
        Allow []string `json:"allow,omitempty"`
129
        Deny  []string `json:"deny,omitempty"`
130
}
131

132
// ResponsePermission can be used to allow responses to any reply subject
133
// that is received on a valid subscription.
134
type ResponsePermission struct {
135
        MaxMsgs int           `json:"max"`
136
        Expires time.Duration `json:"ttl"`
137
}
138

139
// Permissions are the allowed subjects on a per
140
// publish or subscribe basis.
141
type Permissions struct {
142
        Publish   *SubjectPermission  `json:"publish"`
143
        Subscribe *SubjectPermission  `json:"subscribe"`
144
        Response  *ResponsePermission `json:"responses,omitempty"`
145
}
146

147
// RoutePermissions are similar to user permissions
148
// but describe what a server can import/export from and to
149
// another server.
150
type RoutePermissions struct {
151
        Import *SubjectPermission `json:"import"`
152
        Export *SubjectPermission `json:"export"`
153
}
154

155
// clone will clone an individual subject permission.
156
func (p *SubjectPermission) clone() *SubjectPermission {
1,108✔
157
        if p == nil {
1,108✔
158
                return nil
×
159
        }
×
160
        clone := &SubjectPermission{}
1,108✔
161
        if p.Allow != nil {
1,209✔
162
                clone.Allow = make([]string, len(p.Allow))
101✔
163
                copy(clone.Allow, p.Allow)
101✔
164
        }
101✔
165
        if p.Deny != nil {
2,127✔
166
                clone.Deny = make([]string, len(p.Deny))
1,019✔
167
                copy(clone.Deny, p.Deny)
1,019✔
168
        }
1,019✔
169
        return clone
1,108✔
170
}
171

172
// clone performs a deep copy of the Permissions struct, returning a new clone
173
// with all values copied.
174
func (p *Permissions) clone() *Permissions {
12,591✔
175
        if p == nil {
24,112✔
176
                return nil
11,521✔
177
        }
11,521✔
178
        clone := &Permissions{}
1,070✔
179
        if p.Publish != nil {
1,122✔
180
                clone.Publish = p.Publish.clone()
52✔
181
        }
52✔
182
        if p.Subscribe != nil {
2,126✔
183
                clone.Subscribe = p.Subscribe.clone()
1,056✔
184
        }
1,056✔
185
        if p.Response != nil {
1,084✔
186
                clone.Response = &ResponsePermission{
14✔
187
                        MaxMsgs: p.Response.MaxMsgs,
14✔
188
                        Expires: p.Response.Expires,
14✔
189
                }
14✔
190
        }
14✔
191
        return clone
1,070✔
192
}
193

194
// checkAuthforWarnings will look for insecure settings and log concerns.
195
// Lock is assumed held.
196
func (s *Server) checkAuthforWarnings() {
6,575✔
197
        warn := false
6,575✔
198
        opts := s.getOpts()
6,575✔
199
        if opts.Password != _EMPTY_ && !isBcrypt(opts.Password) {
6,598✔
200
                warn = true
23✔
201
        }
23✔
202
        for _, u := range s.users {
10,885✔
203
                // Skip warn if using TLS certs based auth
4,310✔
204
                // unless a password has been left in the config.
4,310✔
205
                if u.Password == _EMPTY_ && opts.TLSMap {
4,350✔
206
                        continue
40✔
207
                }
208
                // Check if this is our internal sys client created on the fly.
209
                if s.sysAccOnlyNoAuthUser != _EMPTY_ && u.Username == s.sysAccOnlyNoAuthUser {
4,705✔
210
                        continue
435✔
211
                }
212
                if !isBcrypt(u.Password) {
7,652✔
213
                        warn = true
3,817✔
214
                        break
3,817✔
215
                }
216
        }
217
        if warn {
10,415✔
218
                // Warning about using plaintext passwords.
3,840✔
219
                s.Warnf("Plaintext passwords detected, use nkeys or bcrypt")
3,840✔
220
        }
3,840✔
221
}
222

223
// If Users or Nkeys options have definitions without an account defined,
224
// assign them to the default global account.
225
// Lock should be held.
226
func (s *Server) assignGlobalAccountToOrphanUsers(nkeys map[string]*NkeyUser, users map[string]*User) {
5,005✔
227
        for _, u := range users {
16,580✔
228
                if u.Account == nil {
11,686✔
229
                        u.Account = s.gacc
111✔
230
                }
111✔
231
        }
232
        for _, u := range nkeys {
5,017✔
233
                if u.Account == nil {
18✔
234
                        u.Account = s.gacc
6✔
235
                }
6✔
236
        }
237
}
238

239
// If the given permissions has a ResponsePermission
240
// set, ensure that defaults are set (if values are 0)
241
// and that a Publish permission is set, and Allow
242
// is disabled if not explicitly set.
243
func validateResponsePermissions(p *Permissions) {
73✔
244
        if p == nil || p.Response == nil {
127✔
245
                return
54✔
246
        }
54✔
247
        if p.Publish == nil {
26✔
248
                p.Publish = &SubjectPermission{}
7✔
249
        }
7✔
250
        if p.Publish.Allow == nil {
27✔
251
                // We turn off the blanket allow statement.
8✔
252
                p.Publish.Allow = []string{}
8✔
253
        }
8✔
254
        // If there is a response permission, ensure
255
        // that if value is 0, we set the default value.
256
        if p.Response.MaxMsgs == 0 {
20✔
257
                p.Response.MaxMsgs = DEFAULT_ALLOW_RESPONSE_MAX_MSGS
1✔
258
        }
1✔
259
        if p.Response.Expires == 0 {
20✔
260
                p.Response.Expires = DEFAULT_ALLOW_RESPONSE_EXPIRATION
1✔
261
        }
1✔
262
}
263

264
// configureAuthorization will do any setup needed for authorization.
265
// Lock is assumed held.
266
func (s *Server) configureAuthorization() {
7,820✔
267
        opts := s.getOpts()
7,820✔
268
        if opts == nil {
7,820✔
269
                return
×
270
        }
×
271

272
        // Check for multiple users first
273
        // This just checks and sets up the user map if we have multiple users.
274
        if opts.CustomClientAuthentication != nil {
7,821✔
275
                s.info.AuthRequired = true
1✔
276
        } else if s.trustedKeys != nil {
8,231✔
277
                s.info.AuthRequired = true
411✔
278
        } else if opts.Nkeys != nil || opts.Users != nil {
12,824✔
279
                s.nkeys, s.users = s.buildNkeysAndUsersFromOptions(opts.Nkeys, opts.Users)
5,005✔
280
                s.info.AuthRequired = true
5,005✔
281
        } else if opts.Username != _EMPTY_ || opts.Authorization != _EMPTY_ {
7,453✔
282
                s.info.AuthRequired = true
45✔
283
        } else {
2,403✔
284
                s.users = nil
2,358✔
285
                s.nkeys = nil
2,358✔
286
                s.info.AuthRequired = false
2,358✔
287
        }
2,358✔
288

289
        // Do similar for websocket config
290
        s.wsConfigAuth(&opts.Websocket)
7,820✔
291
        // And for mqtt config
7,820✔
292
        s.mqttConfigAuth(&opts.MQTT)
7,820✔
293

7,820✔
294
        // Check for server configured auth callouts.
7,820✔
295
        if opts.AuthCallout != nil {
7,845✔
296
                s.mu.Unlock()
25✔
297
                // Give operator log entries if not valid account and auth_users.
25✔
298
                _, err := s.lookupAccount(opts.AuthCallout.Account)
25✔
299
                s.mu.Lock()
25✔
300
                if err != nil {
25✔
301
                        s.Errorf("Authorization callout account %q not valid", opts.AuthCallout.Account)
×
302
                }
×
303
                for _, u := range opts.AuthCallout.AuthUsers {
51✔
304
                        // Check for user in users and nkeys since this is server config.
26✔
305
                        var found bool
26✔
306
                        if len(s.users) > 0 {
52✔
307
                                _, found = s.users[u]
26✔
308
                        }
26✔
309
                        if !found && len(s.nkeys) > 0 {
26✔
310
                                _, found = s.nkeys[u]
×
311
                        }
×
312
                        if !found {
26✔
313
                                s.Errorf("Authorization callout user %q not valid: %v", u, err)
×
314
                        }
×
315
                }
316
        }
317
}
318

319
// Takes the given slices of NkeyUser and User options and build
320
// corresponding maps used by the server. The users are cloned
321
// so that server does not reference options.
322
// The global account is assigned to users that don't have an
323
// existing account.
324
// Server lock is held on entry.
325
func (s *Server) buildNkeysAndUsersFromOptions(nko []*NkeyUser, uo []*User) (map[string]*NkeyUser, map[string]*User) {
5,005✔
326
        var nkeys map[string]*NkeyUser
5,005✔
327
        var users map[string]*User
5,005✔
328

5,005✔
329
        if nko != nil {
5,014✔
330
                nkeys = make(map[string]*NkeyUser, len(nko))
9✔
331
                for _, u := range nko {
21✔
332
                        copy := u.clone()
12✔
333
                        if u.Account != nil {
18✔
334
                                if v, ok := s.accounts.Load(u.Account.Name); ok {
12✔
335
                                        copy.Account = v.(*Account)
6✔
336
                                }
6✔
337
                        }
338
                        if copy.Permissions != nil {
12✔
339
                                validateResponsePermissions(copy.Permissions)
×
340
                        }
×
341
                        nkeys[u.Nkey] = copy
12✔
342
                }
343
        }
344
        if uo != nil {
10,007✔
345
                users = make(map[string]*User, len(uo))
5,002✔
346
                for _, u := range uo {
16,577✔
347
                        copy := u.clone()
11,575✔
348
                        if u.Account != nil {
23,039✔
349
                                if v, ok := s.accounts.Load(u.Account.Name); ok {
22,928✔
350
                                        copy.Account = v.(*Account)
11,464✔
351
                                }
11,464✔
352
                        }
353
                        if copy.Permissions != nil {
11,643✔
354
                                validateResponsePermissions(copy.Permissions)
68✔
355
                        }
68✔
356
                        users[u.Username] = copy
11,575✔
357
                }
358
        }
359
        s.assignGlobalAccountToOrphanUsers(nkeys, users)
5,005✔
360
        return nkeys, users
5,005✔
361
}
362

363
// checkAuthentication will check based on client type and
364
// return boolean indicating if client is authorized.
365
func (s *Server) checkAuthentication(c *client) bool {
43,296✔
366
        switch c.kind {
43,296✔
367
        case CLIENT:
9,459✔
368
                return s.isClientAuthorized(c)
9,459✔
369
        case ROUTER:
31,363✔
370
                return s.isRouterAuthorized(c)
31,363✔
371
        case GATEWAY:
1,752✔
372
                return s.isGatewayAuthorized(c)
1,752✔
373
        case LEAF:
722✔
374
                return s.isLeafNodeAuthorized(c)
722✔
375
        default:
×
376
                return false
×
377
        }
378
}
379

380
// isClientAuthorized will check the client against the proper authorization method and data.
381
// This could be nkey, token, or username/password based.
382
func (s *Server) isClientAuthorized(c *client) bool {
12,739✔
383
        opts := s.getOpts()
12,739✔
384

12,739✔
385
        // Check custom auth first, then jwts, then nkeys, then
12,739✔
386
        // multiple users with TLS map if enabled, then token,
12,739✔
387
        // then single user/pass.
12,739✔
388
        if opts.CustomClientAuthentication != nil && !opts.CustomClientAuthentication.Check(c) {
12,739✔
389
                return false
×
390
        }
×
391

392
        if opts.CustomClientAuthentication == nil && !s.processClientOrLeafAuthentication(c, opts) {
12,912✔
393
                return false
173✔
394
        }
173✔
395

396
        if c.kind == CLIENT || c.kind == LEAF {
25,132✔
397
                // Generate an event if we have a system account.
12,566✔
398
                s.accountConnectEvent(c)
12,566✔
399
        }
12,566✔
400

401
        return true
12,566✔
402
}
403

404
// returns false if the client needs to be disconnected
405
func (c *client) matchesPinnedCert(tlsPinnedCerts PinnedCertSet) bool {
1,144✔
406
        if tlsPinnedCerts == nil {
2,281✔
407
                return true
1,137✔
408
        }
1,137✔
409
        tlsState := c.GetTLSConnectionState()
7✔
410
        if tlsState == nil || len(tlsState.PeerCertificates) == 0 || tlsState.PeerCertificates[0] == nil {
7✔
411
                c.Debugf("Failed pinned cert test as client did not provide a certificate")
×
412
                return false
×
413
        }
×
414
        sha := sha256.Sum256(tlsState.PeerCertificates[0].RawSubjectPublicKeyInfo)
7✔
415
        keyId := hex.EncodeToString(sha[:])
7✔
416
        if _, ok := tlsPinnedCerts[keyId]; !ok {
11✔
417
                c.Debugf("Failed pinned cert test for key id: %s", keyId)
4✔
418
                return false
4✔
419
        }
4✔
420
        return true
3✔
421
}
422

423
var (
424
        mustacheRE                             = regexp.MustCompile(`{{2}([^}]+)}{2}`)
425
        maxPermTemplateSubjectExpansions       = 4096
426
        errPermTemplateExpansionLimit    error = fmt.Errorf("template expansion exceeds limit")
427
)
428

429
func processUserPermissionsTemplate(lim jwt.UserPermissionLimits, ujwt *jwt.UserClaims, acc *Account) (jwt.UserPermissionLimits, error) {
24✔
430
        nArrayCartesianProduct := func(a ...[]string) [][]string {
31✔
431
                c := 1
7✔
432
                for _, a := range a {
18✔
433
                        c *= len(a)
11✔
434
                }
11✔
435
                if c == 0 {
7✔
436
                        return nil
×
437
                }
×
438
                p := make([][]string, c)
7✔
439
                b := make([]string, c*len(a))
7✔
440
                n := make([]int, len(a))
7✔
441
                s := 0
7✔
442
                for i := range p {
30✔
443
                        e := s + len(a)
23✔
444
                        pi := b[s:e]
23✔
445
                        p[i] = pi
23✔
446
                        s = e
23✔
447
                        for j, n := range n {
66✔
448
                                pi[j] = a[j][n]
43✔
449
                        }
43✔
450
                        for j := len(n) - 1; j >= 0; j-- {
54✔
451
                                n[j]++
31✔
452
                                if n[j] < len(a[j]) {
47✔
453
                                        break
16✔
454
                                }
455
                                n[j] = 0
15✔
456
                        }
457
                }
458
                return p
7✔
459
        }
460
        isTag := func(op string) []string {
56✔
461
                if len(op) >= 4 && strings.EqualFold("tag(", op[:4]) && strings.HasSuffix(op, ")") {
58✔
462
                        v := strings.TrimPrefix(op, "tag(")
26✔
463
                        v = strings.TrimSuffix(v, ")")
26✔
464
                        return []string{"tag", v}
26✔
465
                } else if len(op) >= 12 && strings.EqualFold("account-tag(", op[:12]) && strings.HasSuffix(op, ")") {
36✔
466
                        v := strings.TrimPrefix(op, "account-tag(")
4✔
467
                        v = strings.TrimSuffix(v, ")")
4✔
468
                        return []string{"account-tag", v}
4✔
469
                }
4✔
470
                return nil
2✔
471
        }
472
        applyTemplate := func(list jwt.StringList, failOnBadSubject bool) (jwt.StringList, error) {
116✔
473
                found := false
92✔
474
        FOR_FIND:
92✔
475
                for i := 0; i < len(list); i++ {
137✔
476
                        // check if templates are present
45✔
477
                        if mustacheRE.MatchString(list[i]) {
62✔
478
                                found = true
17✔
479
                                break FOR_FIND
17✔
480
                        }
481
                }
482
                if !found {
167✔
483
                        return list, nil
75✔
484
                }
75✔
485
                // process the templates
486
                emittedList := make([]string, 0, len(list))
17✔
487
                for i := 0; i < len(list); i++ {
35✔
488
                        // find all the templates {{}} in this acl
18✔
489
                        tokens := mustacheRE.FindAllString(list[i], -1)
18✔
490
                        srcs := make([]string, len(tokens))
18✔
491
                        values := make([][]string, len(tokens))
18✔
492
                        hasTags := false
18✔
493
                        for tokenNum, tk := range tokens {
47✔
494
                                srcs[tokenNum] = tk
29✔
495
                                op := strings.TrimSpace(strings.TrimSuffix(strings.TrimPrefix(tk, "{{"), "}}"))
29✔
496
                                if strings.EqualFold("name()", op) {
35✔
497
                                        values[tokenNum] = []string{ujwt.Name}
6✔
498
                                } else if strings.EqualFold("subject()", op) {
31✔
499
                                        values[tokenNum] = []string{ujwt.Subject}
2✔
500
                                } else if strings.EqualFold("account-name()", op) {
25✔
501
                                        acc.mu.RLock()
2✔
502
                                        values[tokenNum] = []string{acc.nameTag}
2✔
503
                                        acc.mu.RUnlock()
2✔
504
                                } else if strings.EqualFold("account-subject()", op) {
23✔
505
                                        // this always has an issuer account since this is a scoped signer
2✔
506
                                        values[tokenNum] = []string{ujwt.IssuerAccount}
2✔
507
                                } else if isTag(op) != nil {
34✔
508
                                        hasTags = true
15✔
509
                                        match := isTag(op)
15✔
510
                                        var tags jwt.TagList
15✔
511
                                        if match[0] == "account-tag" {
17✔
512
                                                acc.mu.RLock()
2✔
513
                                                tags = acc.tags
2✔
514
                                                acc.mu.RUnlock()
2✔
515
                                        } else {
15✔
516
                                                tags = ujwt.Tags
13✔
517
                                        }
13✔
518
                                        tagPrefix := fmt.Sprintf("%s:", strings.ToLower(match[1]))
15✔
519
                                        var valueList []string
15✔
520
                                        for _, tag := range tags {
578✔
521
                                                if strings.HasPrefix(tag, tagPrefix) {
838✔
522
                                                        tagValue := strings.TrimPrefix(tag, tagPrefix)
275✔
523
                                                        valueList = append(valueList, tagValue)
275✔
524
                                                }
275✔
525
                                        }
526
                                        if len(valueList) != 0 {
26✔
527
                                                values[tokenNum] = valueList
11✔
528
                                        } else if failOnBadSubject {
17✔
529
                                                return nil, fmt.Errorf("generated invalid subject %q: %q is not defined", list[i], match[1])
2✔
530
                                        } else {
4✔
531
                                                // generate an invalid subject?
2✔
532
                                                values[tokenNum] = []string{" "}
2✔
533
                                        }
2✔
534
                                } else {
2✔
535
                                        return nil, fmt.Errorf("template operation in %q: %q is not defined", list[i], op)
2✔
536
                                }
2✔
537
                        }
538
                        if !hasTags {
20✔
539
                                subj := list[i]
6✔
540
                                for idx, m := range srcs {
18✔
541
                                        subj = strings.Replace(subj, m, values[idx][0], -1)
12✔
542
                                }
12✔
543
                                if IsValidSubject(subj) {
12✔
544
                                        emittedList = append(emittedList, subj)
6✔
545
                                } else if failOnBadSubject {
6✔
546
                                        return nil, fmt.Errorf("generated invalid subject")
×
547
                                }
×
548
                        } else {
8✔
549
                                expCount := 1
8✔
550
                                for _, v := range values {
21✔
551
                                        if len(v) == 0 {
13✔
552
                                                expCount = 0
×
553
                                                break
×
554
                                        }
555
                                        if expCount > maxPermTemplateSubjectExpansions/len(v) {
14✔
556
                                                return nil, fmt.Errorf("%w: %d", errPermTemplateExpansionLimit, maxPermTemplateSubjectExpansions)
1✔
557
                                        }
1✔
558
                                        expCount *= len(v)
12✔
559
                                }
560
                                if len(emittedList) > maxPermTemplateSubjectExpansions-expCount {
7✔
561
                                        return nil, fmt.Errorf("%w: %d", errPermTemplateExpansionLimit, maxPermTemplateSubjectExpansions)
×
562
                                }
×
563
                                a := nArrayCartesianProduct(values...)
7✔
564
                                for _, aa := range a {
30✔
565
                                        subj := list[i]
23✔
566
                                        for j := 0; j < len(srcs); j++ {
66✔
567
                                                subj = strings.Replace(subj, srcs[j], aa[j], -1)
43✔
568
                                        }
43✔
569
                                        if IsValidSubject(subj) {
44✔
570
                                                emittedList = append(emittedList, subj)
21✔
571
                                        } else if failOnBadSubject {
23✔
572
                                                return nil, fmt.Errorf("generated invalid subject")
×
573
                                        }
×
574
                                }
575
                        }
576
                }
577
                return emittedList, nil
12✔
578
        }
579

580
        subAllowWasNotEmpty := len(lim.Permissions.Sub.Allow) > 0
24✔
581
        pubAllowWasNotEmpty := len(lim.Permissions.Pub.Allow) > 0
24✔
582

24✔
583
        var err error
24✔
584
        if lim.Permissions.Sub.Allow, err = applyTemplate(lim.Permissions.Sub.Allow, false); err != nil {
24✔
585
                return jwt.UserPermissionLimits{}, err
×
586
        } else if lim.Permissions.Sub.Deny, err = applyTemplate(lim.Permissions.Sub.Deny, true); err != nil {
25✔
587
                return jwt.UserPermissionLimits{}, err
1✔
588
        } else if lim.Permissions.Pub.Allow, err = applyTemplate(lim.Permissions.Pub.Allow, false); err != nil {
26✔
589
                return jwt.UserPermissionLimits{}, err
2✔
590
        } else if lim.Permissions.Pub.Deny, err = applyTemplate(lim.Permissions.Pub.Deny, true); err != nil {
25✔
591
                return jwt.UserPermissionLimits{}, err
2✔
592
        }
2✔
593

594
        // if pub/sub allow were not empty, but are empty post template processing, add in a "deny >" to compensate
595
        if subAllowWasNotEmpty && len(lim.Permissions.Sub.Allow) == 0 {
20✔
596
                lim.Permissions.Sub.Deny.Add(">")
1✔
597
        }
1✔
598
        if pubAllowWasNotEmpty && len(lim.Permissions.Pub.Allow) == 0 {
19✔
599
                lim.Permissions.Pub.Deny.Add(">")
×
600
        }
×
601
        return lim, nil
19✔
602
}
603

604
func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) (authorized bool) {
12,738✔
605
        var (
12,738✔
606
                nkey *NkeyUser
12,738✔
607
                ujwt string
12,738✔
608
                juc  *jwt.UserClaims
12,738✔
609
                acc  *Account
12,738✔
610
                user *User
12,738✔
611
                ok   bool
12,738✔
612
                err  error
12,738✔
613
                ao   bool // auth override
12,738✔
614
        )
12,738✔
615

12,738✔
616
        // Little helper that will log the error as a debug statement, set the auth error in
12,738✔
617
        // the connection and return false to indicate authentication failure.
12,738✔
618
        setProxyAuthError := func(err error) bool {
12,756✔
619
                c.Debugf(err.Error())
18✔
620
                c.setAuthError(err)
18✔
621
                return false
18✔
622
        }
18✔
623

624
        // Indicate if this connection came from a trusted proxy. Note that if
625
        // trustedProxy could be false even if the connection is proxied, but it
626
        // means that there was no trusted proxy configured.
627
        trustedProxy, ok := s.proxyCheck(c, opts)
12,738✔
628
        if trustedProxy && !ok {
12,744✔
629
                return setProxyAuthError(ErrAuthProxyNotTrusted)
6✔
630
        }
6✔
631

632
        var proxyRequired bool
12,732✔
633
        // Check if we have auth callouts enabled at the server level or in the bound account.
12,732✔
634
        defer func() {
25,464✔
635
                authErr := c.getAuthError()
12,732✔
636
                if authErr == nil {
25,452✔
637
                        authErr = ErrAuthentication
12,720✔
638
                }
12,720✔
639
                reason := getAuthErrClosedState(authErr).String()
12,732✔
640
                // No-op
12,732✔
641
                if juc == nil && opts.AuthCallout == nil {
22,928✔
642
                        if !authorized {
10,247✔
643
                                s.sendAccountAuthErrorEvent(c, c.acc, reason)
51✔
644
                        }
51✔
645
                        return
10,196✔
646
                }
647
                // We have a juc, check if externally managed, i.e. should be delegated
648
                // to the auth callout service.
649
                if juc != nil && !acc.hasExternalAuth() {
4,964✔
650
                        if !authorized {
2,517✔
651
                                s.sendAccountAuthErrorEvent(c, c.acc, reason)
89✔
652
                        }
89✔
653
                        return
2,428✔
654
                }
655
                // Check config-mode. The global account is a condition since users that
656
                // are not found in the config are implicitly bound to the global account.
657
                // This means those users should be implicitly delegated to auth callout
658
                // if configured. Exclude LEAF connections from this check.
659
                if c.kind != LEAF && juc == nil && opts.AuthCallout != nil && c.acc.Name != globalAccountName {
127✔
660
                        // If no allowed accounts are defined, then all accounts are in scope.
19✔
661
                        // Otherwise see if the account is in the list.
19✔
662
                        delegated := len(opts.AuthCallout.AllowedAccounts) == 0
19✔
663
                        if !delegated {
22✔
664
                                for _, n := range opts.AuthCallout.AllowedAccounts {
6✔
665
                                        if n == c.acc.Name {
3✔
666
                                                delegated = true
×
667
                                                break
×
668
                                        }
669
                                }
670
                        }
671

672
                        // Not delegated, so return with previous authorized result.
673
                        if !delegated {
22✔
674
                                if !authorized {
3✔
675
                                        s.sendAccountAuthErrorEvent(c, c.acc, reason)
×
676
                                }
×
677
                                return
3✔
678
                        }
679
                }
680

681
                // We have auth callout set here.
682
                var skip bool
105✔
683
                // Check if we are on the list of auth_users.
105✔
684
                userID := c.getRawAuthUser()
105✔
685
                if juc != nil {
144✔
686
                        skip = acc.isExternalAuthUser(userID)
39✔
687
                } else {
105✔
688
                        for _, u := range opts.AuthCallout.AuthUsers {
135✔
689
                                if userID == u {
95✔
690
                                        skip = true
26✔
691
                                        break
26✔
692
                                }
693
                        }
694
                }
695

696
                // If we are here we have an auth callout defined and we have failed auth so far
697
                // so we will callout to our auth backend for processing.
698
                if !skip {
173✔
699
                        authorized, reason = s.processClientOrLeafCallout(c, opts, proxyRequired, trustedProxy, ujwt)
68✔
700
                }
68✔
701
                // Check if we are authorized and in the auth callout account, and if so add in deny publish permissions for the auth subject.
702
                if authorized {
183✔
703
                        var authAccountName string
78✔
704
                        if juc == nil && opts.AuthCallout != nil {
127✔
705
                                authAccountName = opts.AuthCallout.Account
49✔
706
                        } else if juc != nil {
107✔
707
                                authAccountName = acc.Name
29✔
708
                        }
29✔
709
                        c.mu.Lock()
78✔
710
                        if c.acc != nil && c.acc.Name == authAccountName {
122✔
711
                                c.mergeDenyPermissions(pub, []string{AuthCalloutSubject})
44✔
712
                        }
44✔
713
                        c.mu.Unlock()
78✔
714
                } else {
27✔
715
                        // If we are here we failed external authorization.
27✔
716
                        // Send an account scoped event. Server config mode acc will be nil,
27✔
717
                        // so lookup the auth callout assigned account, that is where this will be sent.
27✔
718
                        if acc == nil {
44✔
719
                                acc, _ = s.lookupAccount(opts.AuthCallout.Account)
17✔
720
                        }
17✔
721
                        s.sendAccountAuthErrorEvent(c, acc, reason)
27✔
722
                }
723
        }()
724

725
        s.mu.Lock()
12,732✔
726
        authRequired := s.info.AuthRequired
12,732✔
727
        if !authRequired {
15,706✔
728
                // If no auth required for regular clients, then check if
2,974✔
729
                // we have an override for MQTT or Websocket clients.
2,974✔
730
                switch c.clientType() {
2,974✔
731
                case MQTT:
410✔
732
                        authRequired = s.mqtt.authOverride
410✔
733
                case WS:
×
734
                        authRequired = s.websocket.authOverride
×
735
                }
736
        }
737
        if !authRequired {
15,701✔
738
                // TODO(dlc) - If they send us credentials should we fail?
2,969✔
739
                s.mu.Unlock()
2,969✔
740
                if c.kind == LEAF {
3,164✔
741
                        // Auth is not required, register the leaf node with the selected account.
195✔
742
                        // Otherwise, auth needs to match client auth.
195✔
743
                        return s.registerLeafWithAccount(c, opts.LeafNode.Account)
195✔
744
                }
195✔
745
                return true
2,774✔
746
        }
747
        var (
9,763✔
748
                username      string
9,763✔
749
                password      string
9,763✔
750
                token         string
9,763✔
751
                noAuthUser    string
9,763✔
752
                pinnedAcounts map[string]struct{}
9,763✔
753
        )
9,763✔
754
        tlsMap := opts.TLSMap
9,763✔
755
        if c.kind == CLIENT {
19,034✔
756
                switch c.clientType() {
9,271✔
757
                case MQTT:
97✔
758
                        mo := &opts.MQTT
97✔
759
                        // Always override TLSMap.
97✔
760
                        tlsMap = mo.TLSMap
97✔
761
                        // The rest depends on if there was any auth override in
97✔
762
                        // the mqtt's config.
97✔
763
                        if s.mqtt.authOverride {
108✔
764
                                noAuthUser = mo.NoAuthUser
11✔
765
                                username = mo.Username
11✔
766
                                password = mo.Password
11✔
767
                                token = mo.Token
11✔
768
                                ao = true
11✔
769
                        }
11✔
770
                case WS:
3✔
771
                        wo := &opts.Websocket
3✔
772
                        // Always override TLSMap.
3✔
773
                        tlsMap = wo.TLSMap
3✔
774
                        // The rest depends on if there was any auth override in
3✔
775
                        // the websocket's config.
3✔
776
                        if s.websocket.authOverride {
3✔
777
                                noAuthUser = wo.NoAuthUser
×
778
                                username = wo.Username
×
779
                                password = wo.Password
×
780
                                token = wo.Token
×
781
                                ao = true
×
782
                        }
×
783
                }
784
        } else {
492✔
785
                tlsMap = opts.LeafNode.TLSMap
492✔
786
        }
492✔
787

788
        if !ao {
19,515✔
789
                noAuthUser = opts.NoAuthUser
9,752✔
790
                // If a leaf connects using websocket, and websocket{} block has a no_auth_user
9,752✔
791
                // use that one instead.
9,752✔
792
                if c.kind == LEAF && c.isWebsocket() && opts.Websocket.NoAuthUser != _EMPTY_ {
9,753✔
793
                        noAuthUser = opts.Websocket.NoAuthUser
1✔
794
                }
1✔
795
                username = opts.Username
9,752✔
796
                password = opts.Password
9,752✔
797
                token = opts.Authorization
9,752✔
798
        }
799

800
        // MQTT can carry JWTs in the password field. Reconstruct it here for auth
801
        // processing and auth callout, but do not populate c.opts.JWT yet or it would
802
        // be exposed through monitoring and advisory paths even when the password is
803
        // not actually a JWT.
804
        if ujwt == _EMPTY_ && c.isMqtt() && c.opts.JWT == _EMPTY_ {
9,860✔
805
                // Don't set juc here, leave that to the next s.trustedKeys != nil block,
97✔
806
                // so that we don't try to trust a JWT when we aren't in operator mode. We
97✔
807
                // will allow it to be passed through auth callout though.
97✔
808
                if _, err := jwt.DecodeUserClaims(c.opts.Password); err == nil {
102✔
809
                        ujwt = c.opts.Password
5✔
810
                }
5✔
811
        }
812

813
        // Check if we have trustedKeys defined in the server. If so we require a user jwt.
814
        if s.trustedKeys != nil {
12,237✔
815
                if ujwt == _EMPTY_ {
4,944✔
816
                        // Need to be sure that it's a NATS JWT, otherwise we will not correctly
2,470✔
817
                        // attempt the default sentinel below.
2,470✔
818
                        if _, err = jwt.DecodeUserClaims(c.opts.JWT); err == nil {
4,929✔
819
                                ujwt = c.opts.JWT
2,459✔
820
                        }
2,459✔
821
                }
822
                if ujwt == _EMPTY_ {
2,485✔
823
                        // Didn't fall through with a valid NATS JWT, so try the default sentinel
11✔
824
                        // if configured.
11✔
825
                        if opts.DefaultSentinel != _EMPTY_ {
15✔
826
                                c.opts.JWT = opts.DefaultSentinel
4✔
827
                                ujwt = c.opts.JWT
4✔
828
                        }
4✔
829
                }
830
                if ujwt == _EMPTY_ {
2,481✔
831
                        s.mu.Unlock()
7✔
832
                        c.Debugf("Authentication requires a user JWT")
7✔
833
                        return false
7✔
834
                }
7✔
835
                if juc, err = jwt.DecodeUserClaims(ujwt); err != nil {
2,467✔
836
                        s.mu.Unlock()
×
837
                        c.Debugf("User JWT not valid: %v", err)
×
838
                        return false
×
839
                }
×
840
                if proxyRequired = juc.ProxyRequired; proxyRequired && !trustedProxy {
2,473✔
841
                        s.mu.Unlock()
6✔
842
                        return setProxyAuthError(ErrAuthProxyRequired)
6✔
843
                }
6✔
844
                vr := jwt.CreateValidationResults()
2,461✔
845
                juc.Validate(vr)
2,461✔
846
                if vr.IsBlocking(true) {
2,462✔
847
                        s.mu.Unlock()
1✔
848
                        c.Debugf("User JWT no longer valid: %+v", vr)
1✔
849
                        return false
1✔
850
                }
1✔
851
                pinnedAcounts = opts.resolverPinnedAccounts
2,460✔
852
        }
853

854
        // Check if we have nkeys or users for client.
855
        hasNkeys := len(s.nkeys) > 0
9,749✔
856
        hasUsers := len(s.users) > 0
9,749✔
857
        if hasNkeys {
9,771✔
858
                if (c.kind == CLIENT || c.kind == LEAF) && noAuthUser != _EMPTY_ &&
22✔
859
                        c.opts.Username == _EMPTY_ && c.opts.Password == _EMPTY_ && c.opts.Token == _EMPTY_ && c.opts.Nkey == _EMPTY_ {
23✔
860
                        if _, exists := s.nkeys[noAuthUser]; exists {
2✔
861
                                c.mu.Lock()
1✔
862
                                c.opts.Nkey = noAuthUser
1✔
863
                                c.mu.Unlock()
1✔
864
                        }
1✔
865
                }
866
                if c.opts.Nkey != _EMPTY_ {
33✔
867
                        nkey, ok = s.nkeys[c.opts.Nkey]
11✔
868
                        if !ok || !c.connectionTypeAllowed(nkey.AllowedConnectionTypes) {
11✔
869
                                s.mu.Unlock()
×
870
                                return false
×
871
                        }
×
872
                }
873
        }
874
        if hasUsers && nkey == nil {
16,985✔
875
                // Check if we are tls verify and are mapping users from the client_certificate.
7,236✔
876
                if tlsMap {
7,271✔
877
                        authorized := checkClientTLSCertSubject(c, func(u string, certDN *ldap.DN, _ bool) (string, bool) {
173✔
878
                                // First do literal lookup using the resulting string representation
138✔
879
                                // of RDNSequence as implemented by the pkix package from Go.
138✔
880
                                if u != _EMPTY_ {
248✔
881
                                        usr, ok := s.users[u]
110✔
882
                                        if !ok || !c.connectionTypeAllowed(usr.AllowedConnectionTypes) {
212✔
883
                                                return _EMPTY_, false
102✔
884
                                        }
102✔
885
                                        user = usr
8✔
886
                                        return usr.Username, true
8✔
887
                                }
888

889
                                if certDN == nil {
28✔
890
                                        return _EMPTY_, false
×
891
                                }
×
892

893
                                // Look through the accounts for a DN that is equal to the one
894
                                // presented by the certificate.
895
                                dns := make(map[*User]*ldap.DN)
28✔
896
                                for _, usr := range s.users {
67✔
897
                                        if !c.connectionTypeAllowed(usr.AllowedConnectionTypes) {
40✔
898
                                                continue
1✔
899
                                        }
900
                                        // TODO: Use this utility to make a full validation pass
901
                                        // on start in case tlsmap feature is being used.
902
                                        inputDN, err := ldap.ParseDN(usr.Username)
38✔
903
                                        if err != nil {
41✔
904
                                                continue
3✔
905
                                        }
906
                                        if inputDN.Equal(certDN) {
51✔
907
                                                user = usr
16✔
908
                                                return usr.Username, true
16✔
909
                                        }
16✔
910

911
                                        // In case it did not match exactly, then collect the DNs
912
                                        // and try to match later in case the DN was reordered.
913
                                        dns[usr] = inputDN
19✔
914
                                }
915

916
                                // Check in case the DN was reordered.
917
                                for usr, inputDN := range dns {
27✔
918
                                        if inputDN.RDNsMatch(certDN) {
20✔
919
                                                user = usr
5✔
920
                                                return usr.Username, true
5✔
921
                                        }
5✔
922
                                }
923
                                return _EMPTY_, false
7✔
924
                        })
925
                        if !authorized {
41✔
926
                                s.mu.Unlock()
6✔
927
                                return false
6✔
928
                        }
6✔
929
                        if c.opts.Username != _EMPTY_ {
29✔
930
                                s.Warnf("User %q found in connect proto, but user required from cert", c.opts.Username)
×
931
                        }
×
932
                        // Already checked that the client didn't send a user in connect
933
                        // but we set it here to be able to identify it in the logs.
934
                        c.opts.Username = user.Username
29✔
935
                } else {
7,201✔
936
                        if (c.kind == CLIENT || c.kind == LEAF) && noAuthUser != _EMPTY_ &&
7,201✔
937
                                c.opts.Username == _EMPTY_ && c.opts.Password == _EMPTY_ && c.opts.Token == _EMPTY_ {
8,815✔
938
                                if u, exists := s.users[noAuthUser]; exists {
3,228✔
939
                                        c.mu.Lock()
1,614✔
940
                                        c.opts.Username = u.Username
1,614✔
941
                                        c.opts.Password = u.Password
1,614✔
942
                                        c.mu.Unlock()
1,614✔
943
                                }
1,614✔
944
                        }
945
                        if c.opts.Username != _EMPTY_ {
14,391✔
946
                                user, ok = s.users[c.opts.Username]
7,190✔
947
                                if !ok || !c.connectionTypeAllowed(user.AllowedConnectionTypes) {
7,228✔
948
                                        s.mu.Unlock()
38✔
949
                                        return false
38✔
950
                                }
38✔
951
                        }
952
                }
953
        }
954
        s.mu.Unlock()
9,705✔
955

9,705✔
956
        // If we have a jwt and a userClaim, make sure we have the Account, etc associated.
9,705✔
957
        // We need to look up the account. This will use an account resolver if one is present.
9,705✔
958
        if juc != nil {
12,165✔
959
                issuer := juc.Issuer
2,460✔
960
                if juc.IssuerAccount != _EMPTY_ {
2,495✔
961
                        issuer = juc.IssuerAccount
35✔
962
                }
35✔
963
                if pinnedAcounts != nil {
2,472✔
964
                        if _, ok := pinnedAcounts[issuer]; !ok {
15✔
965
                                c.Debugf("Account %s not listed as operator pinned account", issuer)
3✔
966
                                atomic.AddUint64(&s.pinnedAccFail, 1)
3✔
967
                                return false
3✔
968
                        }
3✔
969
                }
970
                if acc, err = s.LookupAccount(issuer); acc == nil {
2,479✔
971
                        c.Debugf("Account JWT lookup error: %v", err)
22✔
972
                        return false
22✔
973
                }
22✔
974
                acc.mu.RLock()
2,435✔
975
                aissuer := acc.Issuer
2,435✔
976
                acc.mu.RUnlock()
2,435✔
977
                if !s.isTrustedIssuer(aissuer) {
2,435✔
978
                        c.Debugf("Account JWT not signed by trusted operator")
×
979
                        return false
×
980
                }
×
981
                if scope, ok := acc.hasIssuer(juc.Issuer); !ok {
2,438✔
982
                        c.Debugf("User JWT issuer is not known")
3✔
983
                        return false
3✔
984
                } else if scope != nil {
2,450✔
985
                        if err := scope.ValidateScopedSigner(juc); err != nil {
16✔
986
                                c.Debugf("User JWT is not valid: %v", err)
1✔
987
                                return false
1✔
988
                        } else if uSc, ok := scope.(*jwt.UserScope); !ok {
15✔
989
                                c.Debugf("User JWT is not valid")
×
990
                                return false
×
991
                        } else if juc.UserPermissionLimits, err = processUserPermissionsTemplate(uSc.Template, juc, acc); err != nil {
14✔
992
                                c.Debugf("User JWT generated invalid permissions")
×
993
                                return false
×
994
                        }
×
995
                }
996
                if acc.IsExpired() {
2,435✔
997
                        c.Debugf("Account JWT has expired")
4✔
998
                        return false
4✔
999
                }
4✔
1000
                if juc.BearerToken && acc.failBearer() {
2,428✔
1001
                        c.Debugf("Account does not allow bearer tokens")
1✔
1002
                        return false
1✔
1003
                }
1✔
1004
                // We check the allowed connection types, but only after processing
1005
                // of scoped signer (so that it updates `juc` with what is defined
1006
                // in the account.
1007
                allowedConnTypes, err := convertAllowedConnectionTypes(juc.AllowedConnectionTypes)
2,426✔
1008
                if err != nil {
2,428✔
1009
                        // We got an error, which means some connection types were unknown. As long as
2✔
1010
                        // a valid one is returned, we proceed with auth. If not, we have to reject.
2✔
1011
                        // In other words, suppose that JWT allows "WEBSOCKET" in the array. No error
2✔
1012
                        // is returned and allowedConnTypes will contain "WEBSOCKET" only.
2✔
1013
                        // Client will be rejected if not a websocket client, or proceed with rest of
2✔
1014
                        // auth if it is.
2✔
1015
                        // Now suppose JWT allows "WEBSOCKET, MQTT" and say MQTT is not known by this
2✔
1016
                        // server. In this case, allowedConnTypes would contain "WEBSOCKET" and we
2✔
1017
                        // would get `err` indicating that "MQTT" is an unknown connection type.
2✔
1018
                        // If a websocket client connects, it should still be allowed, since after all
2✔
1019
                        // the admin wanted to allow websocket and mqtt connection types.
2✔
1020
                        // However, say that the JWT only allows "MQTT" (and again suppose this server
2✔
1021
                        // does not know about MQTT connection type), then since the allowedConnTypes
2✔
1022
                        // map would be empty (no valid types found), and since empty means allow-all,
2✔
1023
                        // then we should reject because the intent was to allow connections for this
2✔
1024
                        // user only as an MQTT client.
2✔
1025
                        c.Debugf("%v", err)
2✔
1026
                        if len(allowedConnTypes) == 0 {
3✔
1027
                                return false
1✔
1028
                        }
1✔
1029
                }
1030
                if !c.connectionTypeAllowed(allowedConnTypes) {
2,429✔
1031
                        c.Debugf("Connection type not allowed")
4✔
1032
                        return false
4✔
1033
                }
4✔
1034
                // Skip validation of nonce when presented with a bearer token.
1035
                // While support for bearer tokens was added for WebSockets, there is no
1036
                // security benefit in restricting their use to that client protocol: the
1037
                // client can just go use the other protocol.
1038
                if !juc.BearerToken {
4,833✔
1039
                        // Verify the signature against the nonce.
2,412✔
1040
                        if c.opts.Sig == _EMPTY_ {
2,412✔
1041
                                c.Debugf("Signature missing")
×
1042
                                return false
×
1043
                        }
×
1044
                        sig, err := base64.RawURLEncoding.DecodeString(c.opts.Sig)
2,412✔
1045
                        if err != nil {
2,412✔
1046
                                // Allow fallback to normal base64.
×
1047
                                sig, err = base64.StdEncoding.DecodeString(c.opts.Sig)
×
1048
                                if err != nil {
×
1049
                                        c.Debugf("Signature not valid base64")
×
1050
                                        return false
×
1051
                                }
×
1052
                        }
1053
                        pub, err := nkeys.FromPublicKey(juc.Subject)
2,412✔
1054
                        if err != nil {
2,412✔
1055
                                c.Debugf("User nkey not valid: %v", err)
×
1056
                                return false
×
1057
                        }
×
1058
                        if err := pub.Verify(c.nonce, sig); err != nil {
2,414✔
1059
                                c.Debugf("Signature not verified")
2✔
1060
                                return false
2✔
1061
                        }
2✔
1062
                }
1063
                if acc.checkUserRevoked(juc.Subject, juc.IssuedAt) {
2,422✔
1064
                        c.Debugf("User authentication revoked")
3✔
1065
                        return false
3✔
1066
                }
3✔
1067
                if !validateSrc(juc, c.host) {
2,418✔
1068
                        c.Errorf("Bad src Ip %s", c.host)
2✔
1069
                        return false
2✔
1070
                }
2✔
1071
                allowNow, validFor := validateTimes(juc)
2,414✔
1072
                if !allowNow {
2,418✔
1073
                        c.Errorf("Outside connect times")
4✔
1074
                        return false
4✔
1075
                }
4✔
1076

1077
                nkey = buildInternalNkeyUser(juc, allowedConnTypes, acc)
2,410✔
1078
                if err := c.RegisterNkeyUser(nkey); err != nil {
2,444✔
1079
                        return false
34✔
1080
                }
34✔
1081

1082
                // Warn about JetStream restrictions
1083
                if c.perms != nil {
4,023✔
1084
                        deniedPub := []string{}
1,647✔
1085
                        deniedSub := []string{}
1,647✔
1086
                        for _, sub := range denyAllJs {
9,882✔
1087
                                if c.perms.pub.deny != nil {
8,380✔
1088
                                        if c.perms.pub.deny.HasInterest(sub) {
255✔
1089
                                                deniedPub = append(deniedPub, sub)
110✔
1090
                                        }
110✔
1091
                                }
1092
                                if c.perms.sub.deny != nil {
13,370✔
1093
                                        if c.perms.sub.deny.HasInterest(sub) {
5,245✔
1094
                                                deniedSub = append(deniedSub, sub)
110✔
1095
                                        }
110✔
1096
                                }
1097
                        }
1098
                        if len(deniedPub) > 0 || len(deniedSub) > 0 {
1,669✔
1099
                                c.Noticef("Connected %s has JetStream denied on pub: %v sub: %v", c.kindString(), deniedPub, deniedSub)
22✔
1100
                        }
22✔
1101
                }
1102

1103
                // Hold onto the user's public key.
1104
                c.mu.Lock()
2,376✔
1105
                c.pubKey = juc.Subject
2,376✔
1106
                // If this is a MQTT client, we purposefully didn't populate the JWT as it could contain
2,376✔
1107
                // a password or token. Now we know it's a valid JWT, we can populate it.
2,376✔
1108
                if c.isMqtt() {
2,379✔
1109
                        c.opts.JWT = ujwt
3✔
1110
                }
3✔
1111
                c.tags = juc.Tags
2,376✔
1112
                c.nameTag = juc.Name
2,376✔
1113
                c.mu.Unlock()
2,376✔
1114

2,376✔
1115
                // Check if we need to set an auth timer if the user jwt expires.
2,376✔
1116
                c.setExpiration(juc.Claims(), validFor)
2,376✔
1117

2,376✔
1118
                acc.mu.RLock()
2,376✔
1119
                c.Debugf("Authenticated JWT: %s %q (claim-name: %q, claim-tags: %q) "+
2,376✔
1120
                        "signed with %q by Account %q (claim-name: %q, claim-tags: %q) signed with %q has mappings %t accused %p",
2,376✔
1121
                        c.kindString(), juc.Subject, juc.Name, juc.Tags, juc.Issuer, issuer, acc.nameTag, acc.tags, acc.Issuer, acc.hasMappings(), acc)
2,376✔
1122
                acc.mu.RUnlock()
2,376✔
1123
                return true
2,376✔
1124
        }
1125

1126
        if nkey != nil {
7,256✔
1127
                if proxyRequired = nkey.ProxyRequired; proxyRequired && !trustedProxy {
13✔
1128
                        return setProxyAuthError(ErrAuthProxyRequired)
2✔
1129
                }
2✔
1130
                // If we did not match noAuthUser check signature which is required.
1131
                if nkey.Nkey != noAuthUser {
17✔
1132
                        if c.opts.Sig == _EMPTY_ {
8✔
1133
                                c.Debugf("Signature missing")
×
1134
                                return false
×
1135
                        }
×
1136
                        sig, err := base64.RawURLEncoding.DecodeString(c.opts.Sig)
8✔
1137
                        if err != nil {
8✔
1138
                                // Allow fallback to normal base64.
×
1139
                                sig, err = base64.StdEncoding.DecodeString(c.opts.Sig)
×
1140
                                if err != nil {
×
1141
                                        c.Debugf("Signature not valid base64")
×
1142
                                        return false
×
1143
                                }
×
1144
                        }
1145
                        pub, err := nkeys.FromPublicKey(c.opts.Nkey)
8✔
1146
                        if err != nil {
8✔
1147
                                c.Debugf("User nkey not valid: %v", err)
×
1148
                                return false
×
1149
                        }
×
1150
                        if err := pub.Verify(c.nonce, sig); err != nil {
8✔
1151
                                c.Debugf("Signature not verified")
×
1152
                                return false
×
1153
                        }
×
1154
                }
1155
                if err := c.RegisterNkeyUser(nkey); err != nil {
9✔
1156
                        return false
×
1157
                }
×
1158
                return true
9✔
1159
        }
1160
        if user != nil {
14,415✔
1161
                if proxyRequired = user.ProxyRequired; proxyRequired && !trustedProxy {
7,184✔
1162
                        return setProxyAuthError(ErrAuthProxyRequired)
3✔
1163
                }
3✔
1164
                ok = comparePasswords(user.Password, c.opts.Password)
7,178✔
1165
                // If we are authorized, register the user which will properly setup any permissions
7,178✔
1166
                // for pub/sub authorizations.
7,178✔
1167
                if ok {
14,350✔
1168
                        c.RegisterUser(user)
7,172✔
1169
                }
7,172✔
1170
                return ok
7,178✔
1171
        }
1172

1173
        // Check for the use of simple auth.
1174
        if c.kind == CLIENT || c.kind == LEAF {
106✔
1175
                if proxyRequired = opts.ProxyRequired; proxyRequired && !trustedProxy {
54✔
1176
                        return setProxyAuthError(ErrAuthProxyRequired)
1✔
1177
                }
1✔
1178
                if token != _EMPTY_ {
68✔
1179
                        return comparePasswords(token, c.opts.Token)
16✔
1180
                } else if username != _EMPTY_ {
77✔
1181
                        if username != c.opts.Username {
31✔
1182
                                return false
6✔
1183
                        }
6✔
1184
                        return comparePasswords(password, c.opts.Password)
19✔
1185
                }
1186
        }
1187
        return false
11✔
1188
}
1189

1190
// If there are configured trusted proxies and this connection comes
1191
// from a proxy whose signature can be verified by one of the known
1192
// trusted key, this function will return `true, true`. If the signature
1193
// cannot be verified by any, it will return `true, false`.
1194
// If the connectio is not proxied, or there are no configured trusted
1195
// proxies, then this function returns `false, false`.
1196
//
1197
// Server lock MUST NOT be held on entry since this function will grab
1198
// the read lock to extract the list of proxy trusted keys. The signature
1199
// verification process will be done outside of the lock.
1200
func (s *Server) proxyCheck(c *client, opts *Options) (bool, bool) {
12,768✔
1201
        // If there is no signature or no configured trusted proxy, return false.
12,768✔
1202
        psig := c.opts.ProxySig
12,768✔
1203
        if psig == _EMPTY_ || opts.Proxies == nil || len(opts.Proxies.Trusted) == 0 {
25,522✔
1204
                return false, false
12,754✔
1205
        }
12,754✔
1206
        // Decode the signature.
1207
        sig, err := base64.RawURLEncoding.DecodeString(psig)
14✔
1208
        if err != nil {
16✔
1209
                c.Debugf("Proxy signature not valid base64")
2✔
1210
                return true, false
2✔
1211
        }
2✔
1212
        // Go through the trusted keys and verify the signature.
1213
        s.mu.RLock()
12✔
1214
        keys := slices.Clone(s.proxiesKeyPairs)
12✔
1215
        s.mu.RUnlock()
12✔
1216
        for _, kp := range keys {
30✔
1217
                // We stop at the first that is valid.
18✔
1218
                if err := kp.Verify(c.nonce, sig); err == nil {
26✔
1219
                        pub, _ := kp.PublicKey()
8✔
1220
                        // Track which proxy public key is used by this connection.
8✔
1221
                        c.mu.Lock()
8✔
1222
                        c.proxyKey = pub
8✔
1223
                        cid := c.cid
8✔
1224
                        c.mu.Unlock()
8✔
1225
                        // Track this proxied connection so that it can be closed
8✔
1226
                        // if the trusted key is removed on configuration reload.
8✔
1227
                        s.mu.Lock()
8✔
1228
                        if s.proxiedConns == nil {
9✔
1229
                                s.proxiedConns = make(map[string]map[uint64]*client)
1✔
1230
                        }
1✔
1231
                        clients := s.proxiedConns[pub]
8✔
1232
                        if clients == nil {
15✔
1233
                                clients = make(map[uint64]*client)
7✔
1234
                        }
7✔
1235
                        clients[cid] = c
8✔
1236
                        s.proxiedConns[pub] = clients
8✔
1237
                        s.mu.Unlock()
8✔
1238
                        return true, true
8✔
1239
                }
1240
        }
1241
        // We could not verify the signature, so indicate failure.
1242
        return true, false
4✔
1243
}
1244

1245
func getTLSAuthDCs(rdns *pkix.RDNSequence) string {
49✔
1246
        dcOID := asn1.ObjectIdentifier{0, 9, 2342, 19200300, 100, 1, 25}
49✔
1247
        dcs := []string{}
49✔
1248
        for _, rdn := range *rdns {
175✔
1249
                if len(rdn) == 0 {
126✔
1250
                        continue
×
1251
                }
1252
                for _, atv := range rdn {
255✔
1253
                        value, ok := atv.Value.(string)
129✔
1254
                        if !ok {
129✔
1255
                                continue
×
1256
                        }
1257
                        if atv.Type.Equal(dcOID) {
144✔
1258
                                dcs = append(dcs, "DC="+value)
15✔
1259
                        }
15✔
1260
                }
1261
        }
1262
        return strings.Join(dcs, ",")
49✔
1263
}
1264

1265
type tlsMapAuthFn func(string, *ldap.DN, bool) (string, bool)
1266

1267
func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool {
80✔
1268
        tlsState := c.GetTLSConnectionState()
80✔
1269
        if tlsState == nil {
80✔
1270
                c.Debugf("User required in cert, no TLS connection state")
×
1271
                return false
×
1272
        }
×
1273
        if len(tlsState.PeerCertificates) == 0 {
80✔
1274
                c.Debugf("User required in cert, no peer certificates found")
×
1275
                return false
×
1276
        }
×
1277
        cert := tlsState.PeerCertificates[0]
80✔
1278
        if len(tlsState.PeerCertificates) > 1 {
80✔
1279
                c.Debugf("Multiple peer certificates found, selecting first")
×
1280
        }
×
1281

1282
        hasSANs := len(cert.DNSNames) > 0
80✔
1283
        hasEmailAddresses := len(cert.EmailAddresses) > 0
80✔
1284
        hasSubject := len(cert.Subject.String()) > 0
80✔
1285
        hasURIs := len(cert.URIs) > 0
80✔
1286
        if !hasEmailAddresses && !hasSubject && !hasURIs {
80✔
1287
                c.Debugf("User required in cert, none found")
×
1288
                return false
×
1289
        }
×
1290

1291
        switch {
80✔
1292
        case hasEmailAddresses:
3✔
1293
                for _, u := range cert.EmailAddresses {
7✔
1294
                        if match, ok := fn(u, nil, false); ok {
6✔
1295
                                c.Debugf("Using email found in cert for auth [%q]", match)
2✔
1296
                                return true
2✔
1297
                        }
2✔
1298
                }
1299
                fallthrough
1✔
1300
        case hasSANs:
78✔
1301
                for _, u := range cert.DNSNames {
294✔
1302
                        if match, ok := fn(u, nil, true); ok {
222✔
1303
                                c.Debugf("Using SAN found in cert for auth [%q]", match)
6✔
1304
                                return true
6✔
1305
                        }
6✔
1306
                }
1307
                fallthrough
72✔
1308
        case hasURIs:
72✔
1309
                for _, u := range cert.URIs {
76✔
1310
                        if match, ok := fn(u.String(), nil, false); ok {
6✔
1311
                                c.Debugf("Using URI found in cert for auth [%q]", match)
2✔
1312
                                return true
2✔
1313
                        }
2✔
1314
                }
1315
        }
1316

1317
        // Use the string representation of the full RDN Sequence including
1318
        // the domain components in case there are any.
1319
        rdn := cert.Subject.ToRDNSequence().String()
70✔
1320

70✔
1321
        // Match using the raw subject to avoid ignoring attributes.
70✔
1322
        // https://github.com/golang/go/issues/12342
70✔
1323
        dn, err := ldap.FromRawCertSubject(cert.RawSubject)
70✔
1324
        if err == nil {
140✔
1325
                if match, ok := fn(_EMPTY_, dn, false); ok {
91✔
1326
                        c.Debugf("Using DistinguishedNameMatch for auth [%q]", match)
21✔
1327
                        return true
21✔
1328
                }
21✔
1329
                c.Debugf("DistinguishedNameMatch could not be used for auth [%q]", rdn)
49✔
1330
        }
1331

1332
        var rdns pkix.RDNSequence
49✔
1333
        if _, err := asn1.Unmarshal(cert.RawSubject, &rdns); err == nil {
98✔
1334
                // If found domain components then include roughly following
49✔
1335
                // the order from https://tools.ietf.org/html/rfc2253
49✔
1336
                //
49✔
1337
                // NOTE: The original sequence from string representation by ToRDNSequence does not follow
49✔
1338
                // the correct ordering, so this addition ofdomainComponents would likely be deprecated in
49✔
1339
                // another release in favor of using the correct ordered as parsed by the go-ldap library.
49✔
1340
                //
49✔
1341
                dcs := getTLSAuthDCs(&rdns)
49✔
1342
                if len(dcs) > 0 {
55✔
1343
                        u := strings.Join([]string{rdn, dcs}, ",")
6✔
1344
                        if match, ok := fn(u, nil, false); ok {
6✔
1345
                                c.Debugf("Using RDNSequence for auth [%q]", match)
×
1346
                                return true
×
1347
                        }
×
1348
                        c.Debugf("RDNSequence could not be used for auth [%q]", u)
6✔
1349
                }
1350
        }
1351

1352
        // If no match, then use the string representation of the RDNSequence
1353
        // from the subject without the domainComponents.
1354
        if match, ok := fn(rdn, nil, false); ok {
54✔
1355
                c.Debugf("Using certificate subject for auth [%q]", match)
5✔
1356
                return true
5✔
1357
        }
5✔
1358

1359
        c.Debugf("User in cert [%q], not found", rdn)
44✔
1360
        return false
44✔
1361
}
1362

1363
func dnsAltNameLabels(dnsAltName string) []string {
107✔
1364
        return strings.Split(strings.ToLower(dnsAltName), ".")
107✔
1365
}
107✔
1366

1367
// Check DNS name according to https://tools.ietf.org/html/rfc6125#section-6.4.1
1368
func dnsAltNameMatches(dnsAltNameLabels []string, urls []*url.URL) bool {
176✔
1369
URLS:
176✔
1370
        for _, url := range urls {
364✔
1371
                if url == nil {
188✔
1372
                        continue URLS
×
1373
                }
1374
                hostLabels := strings.Split(strings.ToLower(url.Hostname()), ".")
188✔
1375
                // Following https://tools.ietf.org/html/rfc6125#section-6.4.3, should not => will not, may => will not
188✔
1376
                // The wildcard * never matches multiple label and only matches the left most label.
188✔
1377
                if len(hostLabels) != len(dnsAltNameLabels) {
335✔
1378
                        continue URLS
147✔
1379
                }
1380
                i := 0
41✔
1381
                // only match wildcard on left most label
41✔
1382
                if dnsAltNameLabels[0] == "*" {
49✔
1383
                        i++
8✔
1384
                }
8✔
1385
                for ; i < len(dnsAltNameLabels); i++ {
95✔
1386
                        if dnsAltNameLabels[i] != hostLabels[i] {
72✔
1387
                                continue URLS
18✔
1388
                        }
1389
                }
1390
                return true
23✔
1391
        }
1392
        return false
153✔
1393
}
1394

1395
// checkRouterAuth checks optional router authorization which can be nil or username/password.
1396
func (s *Server) isRouterAuthorized(c *client) bool {
31,368✔
1397
        // Snapshot server options.
31,368✔
1398
        opts := s.getOpts()
31,368✔
1399

31,368✔
1400
        // Check custom auth first, then TLS map if enabled
31,368✔
1401
        // then single user/pass.
31,368✔
1402
        if opts.CustomRouterAuthentication != nil {
31,368✔
1403
                return opts.CustomRouterAuthentication.Check(c)
×
1404
        }
×
1405

1406
        if opts.Cluster.TLSMap || opts.Cluster.TLSCheckKnownURLs {
31,381✔
1407
                return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) {
78✔
1408
                        if user == _EMPTY_ {
78✔
1409
                                return _EMPTY_, false
13✔
1410
                        }
13✔
1411
                        if opts.Cluster.TLSCheckKnownURLs && isDNSAltName {
52✔
1412
                                if dnsAltNameMatches(dnsAltNameLabels(user), opts.Routes) {
×
1413
                                        return _EMPTY_, true
×
1414
                                }
×
1415
                        }
1416
                        if opts.Cluster.TLSMap && opts.Cluster.Username == user {
53✔
1417
                                return _EMPTY_, true
1✔
1418
                        }
1✔
1419
                        return _EMPTY_, false
51✔
1420
                })
1421
        }
1422

1423
        if opts.Cluster.Username == _EMPTY_ {
62,608✔
1424
                return true
31,253✔
1425
        }
31,253✔
1426

1427
        if opts.Cluster.Username != c.opts.Username {
102✔
1428
                return false
×
1429
        }
×
1430
        if !comparePasswords(opts.Cluster.Password, c.opts.Password) {
102✔
1431
                return false
×
1432
        }
×
1433
        return true
102✔
1434
}
1435

1436
// isGatewayAuthorized checks optional gateway authorization which can be nil or username/password.
1437
func (s *Server) isGatewayAuthorized(c *client) bool {
1,752✔
1438
        // Snapshot server options.
1,752✔
1439
        opts := s.getOpts()
1,752✔
1440

1,752✔
1441
        // Check whether TLS map is enabled, otherwise use single user/pass.
1,752✔
1442
        if opts.Gateway.TLSMap || opts.Gateway.TLSCheckKnownURLs {
1,781✔
1443
                return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) {
166✔
1444
                        if user == _EMPTY_ {
164✔
1445
                                return _EMPTY_, false
27✔
1446
                        }
27✔
1447
                        if opts.Gateway.TLSCheckKnownURLs && isDNSAltName {
181✔
1448
                                labels := dnsAltNameLabels(user)
71✔
1449
                                for _, gw := range opts.Gateway.Gateways {
211✔
1450
                                        if gw != nil && dnsAltNameMatches(labels, gw.URLs) {
142✔
1451
                                                return _EMPTY_, true
2✔
1452
                                        }
2✔
1453
                                }
1454
                        }
1455
                        if opts.Gateway.TLSMap && opts.Gateway.Username == user {
110✔
1456
                                return _EMPTY_, true
2✔
1457
                        }
2✔
1458
                        return _EMPTY_, false
106✔
1459
                })
1460
        }
1461

1462
        if opts.Gateway.Username == _EMPTY_ {
3,439✔
1463
                return true
1,716✔
1464
        }
1,716✔
1465

1466
        if opts.Gateway.Username != c.opts.Username {
9✔
1467
                return false
2✔
1468
        }
2✔
1469
        return comparePasswords(opts.Gateway.Password, c.opts.Password)
5✔
1470
}
1471

1472
func (s *Server) registerLeafWithAccount(c *client, account string) bool {
210✔
1473
        var err error
210✔
1474
        acc := s.globalAccount()
210✔
1475
        if account != _EMPTY_ {
219✔
1476
                acc, err = s.lookupAccount(account)
9✔
1477
                if err != nil {
9✔
1478
                        s.Errorf("authentication of user %q failed, unable to lookup account %q: %v",
×
1479
                                c.opts.Username, account, err)
×
1480
                        return false
×
1481
                }
×
1482
        }
1483
        if err = c.registerWithAccount(acc); err != nil {
210✔
1484
                return false
×
1485
        }
×
1486
        return true
210✔
1487
}
1488

1489
// isLeafNodeAuthorized will check for auth for an inbound leaf node connection.
1490
func (s *Server) isLeafNodeAuthorized(c *client) bool {
722✔
1491
        opts := s.getOpts()
722✔
1492

722✔
1493
        setProxyAuthError := func(err error) bool {
734✔
1494
                c.Debugf(err.Error())
12✔
1495
                c.setAuthError(err)
12✔
1496
                return false
12✔
1497
        }
12✔
1498

1499
        isAuthorized := func(username, password, account string, proxyRequired bool) bool {
748✔
1500
                trustedProxy, ok := s.proxyCheck(c, opts)
26✔
1501
                if trustedProxy && !ok {
26✔
1502
                        return setProxyAuthError(ErrAuthProxyNotTrusted)
×
1503
                }
×
1504
                // A given user may not be required, but if the boolean is set at the
1505
                // authorization top-level, then override.
1506
                if !proxyRequired && opts.LeafNode.ProxyRequired {
28✔
1507
                        proxyRequired = true
2✔
1508
                }
2✔
1509
                if proxyRequired && !trustedProxy {
35✔
1510
                        return setProxyAuthError(ErrAuthProxyRequired)
9✔
1511
                }
9✔
1512
                if username != c.opts.Username {
19✔
1513
                        return false
2✔
1514
                }
2✔
1515
                if !comparePasswords(password, c.opts.Password) {
16✔
1516
                        return false
1✔
1517
                }
1✔
1518
                return s.registerLeafWithAccount(c, account)
14✔
1519
        }
1520

1521
        // If leafnodes config has an authorization{} stanza, this takes precedence.
1522
        // The user in CONNECT must match. We will bind to the account associated
1523
        // with that user (from the leafnode's authorization{} config).
1524
        if opts.LeafNode.Username != _EMPTY_ {
736✔
1525
                return isAuthorized(opts.LeafNode.Username, opts.LeafNode.Password, opts.LeafNode.Account,
14✔
1526
                        opts.LeafNode.ProxyRequired)
14✔
1527
        } else if opts.LeafNode.Nkey != _EMPTY_ {
726✔
1528
                trustedProxy, ok := s.proxyCheck(c, opts)
4✔
1529
                if trustedProxy && !ok {
4✔
1530
                        return false
×
1531
                }
×
1532
                if opts.LeafNode.ProxyRequired && !trustedProxy {
7✔
1533
                        return setProxyAuthError(ErrAuthProxyRequired)
3✔
1534
                }
3✔
1535
                if c.opts.Nkey != opts.LeafNode.Nkey {
1✔
1536
                        return false
×
1537
                }
×
1538
                if c.opts.Sig == _EMPTY_ {
1✔
1539
                        c.Debugf("Signature missing")
×
1540
                        return false
×
1541
                }
×
1542
                sig, err := base64.RawURLEncoding.DecodeString(c.opts.Sig)
1✔
1543
                if err != nil {
1✔
1544
                        // Allow fallback to normal base64.
×
1545
                        sig, err = base64.StdEncoding.DecodeString(c.opts.Sig)
×
1546
                        if err != nil {
×
1547
                                c.Debugf("Signature not valid base64")
×
1548
                                return false
×
1549
                        }
×
1550
                }
1551
                pub, err := nkeys.FromPublicKey(c.opts.Nkey)
1✔
1552
                if err != nil {
1✔
1553
                        c.Debugf("User nkey not valid: %v", err)
×
1554
                        return false
×
1555
                }
×
1556
                if err := pub.Verify(c.nonce, sig); err != nil {
1✔
1557
                        c.Debugf("Signature not verified")
×
1558
                        return false
×
1559
                }
×
1560
                return s.registerLeafWithAccount(c, opts.LeafNode.Account)
1✔
1561
        } else if len(opts.LeafNode.Users) > 0 {
718✔
1562
                if opts.LeafNode.TLSMap {
17✔
1563
                        var user *User
3✔
1564
                        found := checkClientTLSCertSubject(c, func(u string, _ *ldap.DN, _ bool) (string, bool) {
12✔
1565
                                // This is expected to be a very small array.
9✔
1566
                                for _, usr := range opts.LeafNode.Users {
18✔
1567
                                        if u == usr.Username {
11✔
1568
                                                user = usr
2✔
1569
                                                return u, true
2✔
1570
                                        }
2✔
1571
                                }
1572
                                return _EMPTY_, false
7✔
1573
                        })
1574
                        if !found {
4✔
1575
                                return false
1✔
1576
                        }
1✔
1577
                        if c.opts.Username != _EMPTY_ {
3✔
1578
                                s.Warnf("User %q found in connect proto, but user required from cert", c.opts.Username)
1✔
1579
                        }
1✔
1580
                        c.opts.Username = user.Username
2✔
1581
                        // EMPTY will result in $G
2✔
1582
                        accName := _EMPTY_
2✔
1583
                        if user.Account != nil {
3✔
1584
                                accName = user.Account.GetName()
1✔
1585
                        }
1✔
1586
                        // This will authorize since are using an existing user,
1587
                        // but it will also register with proper account.
1588
                        return isAuthorized(user.Username, user.Password, accName, user.ProxyRequired)
2✔
1589
                }
1590

1591
                // This is expected to be a very small array.
1592
                for _, u := range opts.LeafNode.Users {
30✔
1593
                        if u.Username == c.opts.Username {
29✔
1594
                                var accName string
10✔
1595
                                if u.Account != nil {
13✔
1596
                                        accName = u.Account.Name
3✔
1597
                                }
3✔
1598
                                return isAuthorized(u.Username, u.Password, accName, u.ProxyRequired)
10✔
1599
                        }
1600
                }
1601
                return false
1✔
1602
        }
1603

1604
        // We are here if we accept leafnode connections without any credentials.
1605

1606
        // Still, if the CONNECT has some user info, we will bind to the
1607
        // user's account or to the specified default account (if provided)
1608
        // or to the global account.
1609
        return s.isClientAuthorized(c)
690✔
1610
}
1611

1612
// Support for bcrypt stored passwords and tokens.
1613
var validBcryptPrefix = regexp.MustCompile(`^\$2[abxy]\$\d{2}\$.*`)
1614

1615
// isBcrypt checks whether the given password or token is bcrypted.
1616
func isBcrypt(password string) bool {
11,197✔
1617
        if strings.HasPrefix(password, "$") {
11,234✔
1618
                return validBcryptPrefix.MatchString(password)
37✔
1619
        }
37✔
1620

1621
        return false
11,160✔
1622
}
1623

1624
func comparePasswords(serverPassword, clientPassword string) bool {
7,335✔
1625
        // Check to see if the server password is a bcrypt hash
7,335✔
1626
        if isBcrypt(serverPassword) {
7,350✔
1627
                if err := bcrypt.CompareHashAndPassword([]byte(serverPassword), []byte(clientPassword)); err != nil {
17✔
1628
                        return false
2✔
1629
                }
2✔
1630
        } else {
7,320✔
1631
                // stringToBytes should be constant-time near enough compared to
7,320✔
1632
                // turning a string into []byte normally.
7,320✔
1633
                spass := stringToBytes(serverPassword)
7,320✔
1634
                cpass := stringToBytes(clientPassword)
7,320✔
1635
                if subtle.ConstantTimeCompare(spass, cpass) == 0 {
7,338✔
1636
                        return false
18✔
1637
                }
18✔
1638
        }
1639
        return true
7,315✔
1640
}
1641

1642
func validateAuth(o *Options) error {
7,853✔
1643
        if err := validatePinnedCerts(o.TLSPinnedCerts); err != nil {
7,853✔
1644
                return err
×
1645
        }
×
1646
        for _, u := range o.Users {
16,445✔
1647
                if err := validateAllowedConnectionTypes(u.AllowedConnectionTypes); err != nil {
8,593✔
1648
                        return err
1✔
1649
                }
1✔
1650
        }
1651
        for _, u := range o.Nkeys {
7,865✔
1652
                if err := validateAllowedConnectionTypes(u.AllowedConnectionTypes); err != nil {
14✔
1653
                        return err
1✔
1654
                }
1✔
1655
        }
1656
        return validateNoAuthUser(o, o.NoAuthUser)
7,851✔
1657
}
1658

1659
func validateAllowedConnectionTypes(m map[string]struct{}) error {
8,605✔
1660
        for ct := range m {
8,628✔
1661
                ctuc := strings.ToUpper(ct)
23✔
1662
                switch ctuc {
23✔
1663
                case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket,
1664
                        jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeLeafnodeWS,
1665
                        jwt.ConnectionTypeMqtt, jwt.ConnectionTypeMqttWS,
1666
                        jwt.ConnectionTypeInProcess:
21✔
1667
                default:
2✔
1668
                        return fmt.Errorf("unknown connection type %q", ct)
2✔
1669
                }
1670
                if ctuc != ct {
23✔
1671
                        delete(m, ct)
2✔
1672
                        m[ctuc] = struct{}{}
2✔
1673
                }
2✔
1674
        }
1675
        return nil
8,603✔
1676
}
1677

1678
func validateNoAuthUser(o *Options, noAuthUser string) error {
7,858✔
1679
        if noAuthUser == _EMPTY_ {
15,382✔
1680
                return nil
7,524✔
1681
        }
7,524✔
1682
        if len(o.TrustedOperators) > 0 {
334✔
1683
                return fmt.Errorf("no_auth_user not compatible with Trusted Operator")
×
1684
        }
×
1685

1686
        if o.Nkeys == nil && o.Users == nil {
334✔
1687
                return fmt.Errorf(`no_auth_user: "%s" present, but users/nkeys are not defined`, noAuthUser)
×
1688
        }
×
1689
        for _, u := range o.Users {
862✔
1690
                if u.Username == noAuthUser {
859✔
1691
                        return nil
331✔
1692
                }
331✔
1693
        }
1694
        for _, u := range o.Nkeys {
4✔
1695
                if u.Nkey == noAuthUser {
2✔
1696
                        return nil
1✔
1697
                }
1✔
1698
        }
1699
        return fmt.Errorf(
2✔
1700
                `no_auth_user: "%s" not present as user or nkey in authorization block or account configuration`,
2✔
1701
                noAuthUser)
2✔
1702
}
1703

1704
func validateProxies(o *Options) error {
7,851✔
1705
        if o.Proxies == nil {
15,700✔
1706
                return nil
7,849✔
1707
        }
7,849✔
1708
        for _, p := range o.Proxies.Trusted {
6✔
1709
                if !nkeys.IsValidPublicKey(p.Key) {
4✔
1710
                        return fmt.Errorf("proxy trusted key %q is invalid", p.Key)
×
1711
                }
×
1712
        }
1713
        return nil
2✔
1714
}
1715

1716
// Create a list of nkeys.KeyPair corresponding to the public keys
1717
// of the Proxies.TrustedKeys list.
1718
// Server lock must be held on entry.
1719
func (s *Server) processProxiesTrustedKeys() {
6,706✔
1720
        // We could be here on reload.
6,706✔
1721
        if s.proxiesKeyPairs != nil {
6,707✔
1722
                s.proxiesKeyPairs = s.proxiesKeyPairs[:0]
1✔
1723
        }
1✔
1724
        if opts := s.getOpts(); opts.Proxies == nil {
13,410✔
1725
                return
6,704✔
1726
        }
6,704✔
1727
        for _, p := range s.getOpts().Proxies.Trusted {
6✔
1728
                // Can't fail since we have already checked that it was a valid key.
4✔
1729
                kp, _ := nkeys.FromPublicKey(p.Key)
4✔
1730
                s.proxiesKeyPairs = append(s.proxiesKeyPairs, kp)
4✔
1731
        }
4✔
1732
}
1733

1734
// Returns the connection's `ClosedState` for the given authenication error.
1735
func getAuthErrClosedState(authErr error) ClosedState {
12,979✔
1736
        switch authErr {
12,979✔
1737
        case ErrAuthProxyNotTrusted:
8✔
1738
                return ProxyNotTrusted
8✔
1739
        case ErrAuthProxyRequired:
41✔
1740
                return ProxyRequired
41✔
1741
        default:
12,930✔
1742
                return AuthenticationViolation
12,930✔
1743
        }
1744
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc