mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-16 19:14:41 -07:00
[added] jwt/issuerkey/nametag/tags to monitoring and event endpoints (#1830)
Also added a trace on jwt authentication Signed-off-by: Matthias Hanel <mh@synadia.com>
This commit is contained in:
@@ -82,6 +82,8 @@ type Account struct {
|
||||
eventIds *nuid.NUID
|
||||
eventIdsMu sync.Mutex
|
||||
defaultPerms *Permissions
|
||||
tags jwt.TagList
|
||||
nameTag string
|
||||
}
|
||||
|
||||
// Account based limits.
|
||||
@@ -2813,6 +2815,10 @@ func (s *Server) updateAccountClaimsWithRefresh(a *Account, ac *jwt.AccountClaim
|
||||
// Clone to update, only select certain fields.
|
||||
old := &Account{Name: a.Name, exports: a.exports, limits: a.limits, signingKeys: a.signingKeys}
|
||||
|
||||
// overwrite claim meta data
|
||||
a.nameTag = ac.Name
|
||||
a.tags = ac.Tags
|
||||
|
||||
// Reset exports and imports here.
|
||||
|
||||
// Exports is creating a whole new map.
|
||||
|
||||
@@ -627,13 +627,23 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) boo
|
||||
return false
|
||||
}
|
||||
// Hold onto the user's public key.
|
||||
c.mu.Lock()
|
||||
c.pubKey = juc.Subject
|
||||
c.tags = juc.Tags
|
||||
c.nameTag = juc.Name
|
||||
c.mu.Unlock()
|
||||
|
||||
// Generate an event if we have a system account.
|
||||
s.accountConnectEvent(c)
|
||||
|
||||
// Check if we need to set an auth timer if the user jwt expires.
|
||||
c.setExpiration(juc.Claims(), validFor)
|
||||
|
||||
acc.mu.RLock()
|
||||
c.Debugf("Authenticated JWT: %s %q (claim-name: %q, claim-tags: %q) "+
|
||||
"signed with %q by Account %q (claim-name: %q, claim-tags: %q) signed with %q",
|
||||
c.typeString(), juc.Subject, juc.Name, juc.Tags, juc.Issuer, issuer, acc.nameTag, acc.tags, acc.Issuer)
|
||||
acc.mu.RUnlock()
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +263,9 @@ type client struct {
|
||||
|
||||
trace bool
|
||||
echo bool
|
||||
|
||||
tags jwt.TagList
|
||||
nameTag string
|
||||
}
|
||||
|
||||
type rrTracking struct {
|
||||
@@ -4662,6 +4665,10 @@ func (c *client) getClientInfo(detailed bool) *ClientInfo {
|
||||
ci.Lang = c.opts.Lang
|
||||
ci.Version = c.opts.Version
|
||||
ci.Server = sn
|
||||
ci.Jwt = c.opts.JWT
|
||||
ci.IssuerKey = issuerForClient(c)
|
||||
ci.NameTag = c.nameTag
|
||||
ci.Tags = c.tags
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return &ci
|
||||
|
||||
106
server/events.go
106
server/events.go
@@ -163,17 +163,21 @@ type ServerInfo struct {
|
||||
|
||||
// ClientInfo is detailed information about the client forming a connection.
|
||||
type ClientInfo struct {
|
||||
Start *time.Time `json:"start,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
Account string `json:"acc"`
|
||||
User string `json:"user,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
Version string `json:"ver,omitempty"`
|
||||
RTT time.Duration `json:"rtt,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
Stop *time.Time `json:"stop,omitempty"`
|
||||
Start *time.Time `json:"start,omitempty"`
|
||||
Host string `json:"host,omitempty"`
|
||||
ID uint64 `json:"id,omitempty"`
|
||||
Account string `json:"acc"`
|
||||
User string `json:"user,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Lang string `json:"lang,omitempty"`
|
||||
Version string `json:"ver,omitempty"`
|
||||
RTT time.Duration `json:"rtt,omitempty"`
|
||||
Server string `json:"server,omitempty"`
|
||||
Stop *time.Time `json:"stop,omitempty"`
|
||||
Jwt string `json:"jwt,omitempty"`
|
||||
IssuerKey string `json:"issuer_key,omitempty"`
|
||||
NameTag string `json:"name_tag,omitempty"`
|
||||
Tags jwt.TagList `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// ServerStats hold various statistics that we will periodically send out.
|
||||
@@ -1277,14 +1281,18 @@ func (s *Server) accountConnectEvent(c *client) {
|
||||
Time: time.Now().UTC(),
|
||||
},
|
||||
Client: ClientInfo{
|
||||
Start: &c.start,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
Start: &c.start,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
Jwt: c.opts.JWT,
|
||||
IssuerKey: issuerForClient(c),
|
||||
Tags: c.tags,
|
||||
NameTag: c.nameTag,
|
||||
},
|
||||
}
|
||||
c.mu.Unlock()
|
||||
@@ -1320,16 +1328,20 @@ func (s *Server) accountDisconnectEvent(c *client, now time.Time, reason string)
|
||||
Time: now.UTC(),
|
||||
},
|
||||
Client: ClientInfo{
|
||||
Start: &c.start,
|
||||
Stop: &now,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
RTT: c.getRTT(),
|
||||
Start: &c.start,
|
||||
Stop: &now,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
RTT: c.getRTT(),
|
||||
Jwt: c.opts.JWT,
|
||||
IssuerKey: issuerForClient(c),
|
||||
Tags: c.tags,
|
||||
NameTag: c.nameTag,
|
||||
},
|
||||
Sent: DataStats{
|
||||
Msgs: atomic.LoadInt64(&c.inMsgs),
|
||||
@@ -1365,16 +1377,20 @@ func (s *Server) sendAuthErrorEvent(c *client) {
|
||||
Time: now.UTC(),
|
||||
},
|
||||
Client: ClientInfo{
|
||||
Start: &c.start,
|
||||
Stop: &now,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
RTT: c.getRTT(),
|
||||
Start: &c.start,
|
||||
Stop: &now,
|
||||
Host: c.host,
|
||||
ID: c.cid,
|
||||
Account: accForClient(c),
|
||||
User: c.getRawAuthUser(),
|
||||
Name: c.opts.Name,
|
||||
Lang: c.opts.Lang,
|
||||
Version: c.opts.Version,
|
||||
RTT: c.getRTT(),
|
||||
Jwt: c.opts.JWT,
|
||||
IssuerKey: issuerForClient(c),
|
||||
Tags: c.tags,
|
||||
NameTag: c.nameTag,
|
||||
},
|
||||
Sent: DataStats{
|
||||
Msgs: c.inMsgs,
|
||||
@@ -1760,6 +1776,18 @@ func accForClient(c *client) string {
|
||||
return "N/A"
|
||||
}
|
||||
|
||||
// Helper to grab issuer for a client.
|
||||
func issuerForClient(c *client) (issuerKey string) {
|
||||
if c == nil || c.user == nil {
|
||||
return
|
||||
}
|
||||
issuerKey = c.user.SigningKey
|
||||
if issuerKey == "" && c.user.Account != nil {
|
||||
issuerKey = c.user.Account.Name
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Helper to clear timers.
|
||||
func clearTimer(tp **time.Timer) {
|
||||
if t := *tp; t != nil {
|
||||
|
||||
@@ -4431,6 +4431,11 @@ func TestJWTUserRevocation(t *testing.T) {
|
||||
defer srv.Shutdown()
|
||||
updateJwt(t, srv.ClientURL(), sysCreds, sysjwt, 1) // update system account jwt
|
||||
updateJwt(t, srv.ClientURL(), sysCreds, ajwt1, 1) // set account jwt without revocation
|
||||
ncSys := natsConnect(t, srv.ClientURL(), nats.UserCredentials(sysCreds), nats.Name("conn name"))
|
||||
defer ncSys.Close()
|
||||
ncChan := make(chan *nats.Msg, 10)
|
||||
defer close(ncChan)
|
||||
ncSys.ChanSubscribe(fmt.Sprintf(disconnectEventSubj, apub), ncChan) // observe disconnect message
|
||||
// use credentials that will be revoked ans assure that the connection will be disconnected
|
||||
nc := natsConnect(t, srv.ClientURL(), nats.UserCredentials(aCreds1),
|
||||
nats.DisconnectErrHandler(func(conn *nats.Conn, err error) {
|
||||
@@ -4440,7 +4445,7 @@ func TestJWTUserRevocation(t *testing.T) {
|
||||
}))
|
||||
defer nc.Close()
|
||||
// update account jwt to contain revocation
|
||||
if passCnt := updateJwt(t, srv.ClientURL(), sysCreds, ajwt2, 1); passCnt != 1 {
|
||||
if updateJwt(t, srv.ClientURL(), sysCreds, ajwt2, 1) != 1 {
|
||||
t.Fatalf("Expected jwt update to pass")
|
||||
}
|
||||
// assure that nc got disconnected due to the revocation
|
||||
@@ -4449,6 +4454,9 @@ func TestJWTUserRevocation(t *testing.T) {
|
||||
case <-time.After(time.Second):
|
||||
t.Fatalf("Expected connection to have failed")
|
||||
}
|
||||
m := <-ncChan
|
||||
require_Len(t, strings.Count(string(m.Data), apub), 2)
|
||||
require_True(t, strings.Contains(string(m.Data), `"jwt": "eyJ0`))
|
||||
// try again with old credentials. Expected to fail
|
||||
if nc1, err := nats.Connect(srv.ClientURL(), nats.UserCredentials(aCreds1)); err == nil {
|
||||
nc1.Close()
|
||||
|
||||
@@ -127,6 +127,10 @@ type ConnInfo struct {
|
||||
Account string `json:"account,omitempty"`
|
||||
Subs []string `json:"subscriptions_list,omitempty"`
|
||||
SubsDetail []SubDetail `json:"subscriptions_list_detail,omitempty"`
|
||||
JWT string `json:"jwt,omitempty"`
|
||||
IssuerKey string `json:"issuer_key,omitempty"`
|
||||
NameTag string `json:"name_tag,omitempty"`
|
||||
Tags jwt.TagList `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// DefaultConnListSize is the default size of the connection list.
|
||||
@@ -334,6 +338,10 @@ func (s *Server) Connz(opts *ConnzOptions) (*Connz, error) {
|
||||
if client.acc != nil && (client.acc.Name != globalAccountName) {
|
||||
ci.Account = client.acc.Name
|
||||
}
|
||||
ci.JWT = client.opts.JWT
|
||||
ci.IssuerKey = issuerForClient(client)
|
||||
ci.Tags = client.tags
|
||||
ci.NameTag = client.nameTag
|
||||
}
|
||||
client.mu.Unlock()
|
||||
pconns[i] = ci
|
||||
@@ -1976,6 +1984,9 @@ type AccountInfo struct {
|
||||
Exports []ExtExport `json:"exports,omitempty"`
|
||||
Imports []ExtImport `json:"imports,omitempty"`
|
||||
Jwt string `json:"jwt,omitempty"`
|
||||
IssuerKey string `json:"issuer_key,omitempty"`
|
||||
NameTag string `json:"name_tag,omitempty"`
|
||||
Tags jwt.TagList `json:"tags,omitempty"`
|
||||
Claim *jwt.AccountClaims `json:"decoded_jwt,omitempty"`
|
||||
Vr []ExtVrIssues `json:"validation_result_jwt,omitempty"`
|
||||
RevokedUser map[string]time.Time `json:"revoked_user,omitempty"`
|
||||
@@ -2174,6 +2185,9 @@ func (s *Server) accountInfo(accName string) (*AccountInfo, error) {
|
||||
exports,
|
||||
imports,
|
||||
a.claimJWT,
|
||||
a.Issuer,
|
||||
a.nameTag,
|
||||
a.tags,
|
||||
claim,
|
||||
vrIssues,
|
||||
collectRevocations(a.usersRevoked),
|
||||
|
||||
@@ -2343,6 +2343,10 @@ func (s *Server) saveClosedClient(c *client, nc net.Conn, reason ClosedState) {
|
||||
if c.acc != nil && c.acc.Name != globalAccountName {
|
||||
cc.acc = c.acc.Name
|
||||
}
|
||||
cc.JWT = c.opts.JWT
|
||||
cc.IssuerKey = issuerForClient(c)
|
||||
cc.Tags = c.tags
|
||||
cc.NameTag = c.nameTag
|
||||
c.mu.Unlock()
|
||||
|
||||
// Place in the ring buffer
|
||||
|
||||
Reference in New Issue
Block a user