mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
Add in user info requests to have connected users get info for bound account and permissions.
Signed-off-by: Derek Collison <derek@nats.io>
This commit is contained in:
@@ -62,6 +62,10 @@ const (
|
||||
remoteLatencyEventSubj = "$SYS.LATENCY.M2.%s"
|
||||
inboxRespSubj = "$SYS._INBOX.%s.%s"
|
||||
|
||||
// Used to return information to a user on bound account and user permissions.
|
||||
userDirectInfoSubj = "$SYS.REQ.USER.INFO"
|
||||
userDirectReqSubj = "$SYS.REQ.USER.%s.INFO"
|
||||
|
||||
// FIXME(dlc) - Should account scope, even with wc for now, but later on
|
||||
// we can then shard as needed.
|
||||
accNumSubsReqSubj = "$SYS.REQ.ACCOUNT.NSUBS"
|
||||
@@ -1030,6 +1034,13 @@ func (s *Server) initEventTracking() {
|
||||
}
|
||||
}
|
||||
|
||||
// User info.
|
||||
// TODO(dlc) - Can be internal and not forwarded since bound server for the client connection
|
||||
// is only one that will answer. This breaks tests since we still forward on remote server connect.
|
||||
if _, err := s.sysSubscribe(fmt.Sprintf(userDirectReqSubj, "*"), s.userInfoReq); err != nil {
|
||||
s.Errorf("Error setting up internal tracking: %v", err)
|
||||
}
|
||||
|
||||
// For now only the STATZ subject has an account specific ping equivalent.
|
||||
if _, err := s.sysSubscribe(fmt.Sprintf(accPingReqSubj, "STATZ"),
|
||||
func(sub *subscription, c *client, _ *Account, subject, reply string, msg []byte) {
|
||||
@@ -1064,6 +1075,38 @@ func (s *Server) initEventTracking() {
|
||||
}
|
||||
}
|
||||
|
||||
// UserInfo returns basic information to a user about bound account and user permissions.
|
||||
// For account information they will need to ping that separately, and this allows security
|
||||
// controls on each subsystem if desired, e.g. account info, jetstream account info, etc.
|
||||
type UserInfo struct {
|
||||
UserID string `json:"user"`
|
||||
Account string `json:"account"`
|
||||
Permissions *Permissions `json:"permissions,omitempty"`
|
||||
}
|
||||
|
||||
// Process a user info request.
|
||||
func (s *Server) userInfoReq(sub *subscription, c *client, _ *Account, subject, reply string, msg []byte) {
|
||||
if !s.EventsEnabled() || reply == _EMPTY_ {
|
||||
return
|
||||
}
|
||||
|
||||
response := &ServerAPIResponse{Server: &ServerInfo{}}
|
||||
|
||||
ci, _, _, _, err := s.getRequestInfo(c, msg)
|
||||
if err != nil {
|
||||
response.Error = &ApiError{Code: http.StatusBadRequest}
|
||||
s.sendInternalResponse(reply, response)
|
||||
return
|
||||
}
|
||||
|
||||
response.Data = &UserInfo{
|
||||
UserID: ci.User,
|
||||
Account: ci.Account,
|
||||
Permissions: c.publicPermissions(),
|
||||
}
|
||||
s.sendInternalResponse(reply, response)
|
||||
}
|
||||
|
||||
// register existing accounts with any system exports.
|
||||
func (s *Server) registerSystemImportsForExisting() {
|
||||
var accounts []*Account
|
||||
@@ -1117,6 +1160,20 @@ func (s *Server) addSystemAccountExports(sacc *Account) {
|
||||
}
|
||||
}
|
||||
|
||||
// User info export.
|
||||
userInfoSubj := fmt.Sprintf(userDirectReqSubj, "*")
|
||||
if !sacc.hasServiceExportMatching(userInfoSubj) {
|
||||
if err := sacc.AddServiceExport(userInfoSubj, nil); err != nil {
|
||||
s.Errorf("Error adding system service export for %q: %v", userInfoSubj, err)
|
||||
}
|
||||
mappedSubj := fmt.Sprintf(userDirectReqSubj, sacc.GetName())
|
||||
if err := sacc.AddServiceImport(sacc, userDirectInfoSubj, mappedSubj); err != nil {
|
||||
s.Errorf("Error setting up system service import %s: %v", mappedSubj, err)
|
||||
}
|
||||
// Make sure to share details.
|
||||
sacc.setServiceImportSharing(sacc, mappedSubj, false, true)
|
||||
}
|
||||
|
||||
// Register any accounts that existed prior.
|
||||
s.registerSystemImportsForExisting()
|
||||
|
||||
@@ -1721,6 +1778,12 @@ func (s *Server) registerSystemImports(a *Account) {
|
||||
importSrvc(fmt.Sprintf(accPingReqSubj, "CONNZ"), mappedConnzSubj)
|
||||
importSrvc(fmt.Sprintf(serverPingReqSubj, "CONNZ"), mappedConnzSubj)
|
||||
importSrvc(fmt.Sprintf(accPingReqSubj, "STATZ"), fmt.Sprintf(accDirectReqSubj, a.Name, "STATZ"))
|
||||
|
||||
// This is for user's looking up their own info.
|
||||
mappedSubject := fmt.Sprintf(userDirectReqSubj, a.Name)
|
||||
importSrvc(userDirectInfoSubj, mappedSubject)
|
||||
// Make sure to share details.
|
||||
a.setServiceImportSharing(sacc, mappedSubject, false, true)
|
||||
}
|
||||
|
||||
// Setup tracking for this account. This allows us to track global account activity.
|
||||
|
||||
Reference in New Issue
Block a user