mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-19 17:31:39 +02:00
Add limited dashboard view (#1738)
This commit is contained in:
parent
68b377a28c
commit
ea2d060f93
@ -85,7 +85,8 @@ type AccountManager interface {
|
|||||||
GetAllPATs(accountID string, initiatorUserID string, targetUserID string) ([]*PersonalAccessToken, error)
|
GetAllPATs(accountID string, initiatorUserID string, targetUserID string) ([]*PersonalAccessToken, error)
|
||||||
UpdatePeerSSHKey(peerID string, sshKey string) error
|
UpdatePeerSSHKey(peerID string, sshKey string) error
|
||||||
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
|
GetUsersFromAccount(accountID, userID string) ([]*UserInfo, error)
|
||||||
GetGroup(accountId, groupID string) (*Group, error)
|
GetGroup(accountId, groupID, userID string) (*Group, error)
|
||||||
|
GetAllGroups(accountID, userID string) ([]*Group, error)
|
||||||
GetGroupByName(groupName, accountID string) (*Group, error)
|
GetGroupByName(groupName, accountID string) (*Group, error)
|
||||||
SaveGroup(accountID, userID string, group *Group) error
|
SaveGroup(accountID, userID string, group *Group) error
|
||||||
DeleteGroup(accountId, userId, groupID string) error
|
DeleteGroup(accountId, userId, groupID string) error
|
||||||
@ -162,6 +163,9 @@ type Settings struct {
|
|||||||
// Applies to all peers that have Peer.LoginExpirationEnabled set to true.
|
// Applies to all peers that have Peer.LoginExpirationEnabled set to true.
|
||||||
PeerLoginExpiration time.Duration
|
PeerLoginExpiration time.Duration
|
||||||
|
|
||||||
|
// RegularUsersViewBlocked allows to block regular users from viewing even their own peers and some UI elements
|
||||||
|
RegularUsersViewBlocked bool
|
||||||
|
|
||||||
// GroupsPropagationEnabled allows to propagate auto groups from the user to the peer
|
// GroupsPropagationEnabled allows to propagate auto groups from the user to the peer
|
||||||
GroupsPropagationEnabled bool
|
GroupsPropagationEnabled bool
|
||||||
|
|
||||||
@ -188,6 +192,7 @@ func (s *Settings) Copy() *Settings {
|
|||||||
JWTGroupsClaimName: s.JWTGroupsClaimName,
|
JWTGroupsClaimName: s.JWTGroupsClaimName,
|
||||||
GroupsPropagationEnabled: s.GroupsPropagationEnabled,
|
GroupsPropagationEnabled: s.GroupsPropagationEnabled,
|
||||||
JWTAllowGroups: s.JWTAllowGroups,
|
JWTAllowGroups: s.JWTAllowGroups,
|
||||||
|
RegularUsersViewBlocked: s.RegularUsersViewBlocked,
|
||||||
}
|
}
|
||||||
if s.Extra != nil {
|
if s.Extra != nil {
|
||||||
settings.Extra = s.Extra.Copy()
|
settings.Extra = s.Extra.Copy()
|
||||||
@ -226,6 +231,10 @@ type Account struct {
|
|||||||
Settings *Settings `gorm:"embedded;embeddedPrefix:settings_"`
|
Settings *Settings `gorm:"embedded;embeddedPrefix:settings_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserPermissions struct {
|
||||||
|
DashboardView string `json:"dashboard_view"`
|
||||||
|
}
|
||||||
|
|
||||||
type UserInfo struct {
|
type UserInfo struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
@ -239,6 +248,7 @@ type UserInfo struct {
|
|||||||
LastLogin time.Time `json:"last_login"`
|
LastLogin time.Time `json:"last_login"`
|
||||||
Issued string `json:"issued"`
|
Issued string `json:"issued"`
|
||||||
IntegrationReference IntegrationReference `json:"-"`
|
IntegrationReference IntegrationReference `json:"-"`
|
||||||
|
Permissions UserPermissions `json:"permissions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRoutesToSync returns the enabled routes for the peer ID and the routes
|
// getRoutesToSync returns the enabled routes for the peer ID and the routes
|
||||||
@ -1885,6 +1895,7 @@ func newAccountWithId(accountID, userID, domain string) *Account {
|
|||||||
PeerLoginExpirationEnabled: true,
|
PeerLoginExpirationEnabled: true,
|
||||||
PeerLoginExpiration: DefaultPeerLoginExpiration,
|
PeerLoginExpiration: DefaultPeerLoginExpiration,
|
||||||
GroupsPropagationEnabled: true,
|
GroupsPropagationEnabled: true,
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ func (g *Group) Copy() *Group {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetGroup object of the peers
|
// GetGroup object of the peers
|
||||||
func (am *DefaultAccountManager) GetGroup(accountID, groupID string) (*Group, error) {
|
func (am *DefaultAccountManager) GetGroup(accountID, groupID, userID string) (*Group, error) {
|
||||||
unlock := am.Store.AcquireAccountLock(accountID)
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
@ -72,6 +72,15 @@ func (am *DefaultAccountManager) GetGroup(accountID, groupID string) (*Group, er
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user, err := account.FindUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser && account.Settings.RegularUsersViewBlocked {
|
||||||
|
return nil, status.Errorf(status.PermissionDenied, "groups are blocked for users")
|
||||||
|
}
|
||||||
|
|
||||||
group, ok := account.Groups[groupID]
|
group, ok := account.Groups[groupID]
|
||||||
if ok {
|
if ok {
|
||||||
return group, nil
|
return group, nil
|
||||||
@ -80,6 +89,33 @@ func (am *DefaultAccountManager) GetGroup(accountID, groupID string) (*Group, er
|
|||||||
return nil, status.Errorf(status.NotFound, "group with ID %s not found", groupID)
|
return nil, status.Errorf(status.NotFound, "group with ID %s not found", groupID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllGroups returns all groups in an account
|
||||||
|
func (am *DefaultAccountManager) GetAllGroups(accountID string, userID string) ([]*Group, error) {
|
||||||
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
|
defer unlock()
|
||||||
|
|
||||||
|
account, err := am.Store.GetAccount(accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := account.FindUser(userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser && account.Settings.RegularUsersViewBlocked {
|
||||||
|
return nil, status.Errorf(status.PermissionDenied, "groups are blocked for users")
|
||||||
|
}
|
||||||
|
|
||||||
|
groups := make([]*Group, 0, len(account.Groups))
|
||||||
|
for _, item := range account.Groups {
|
||||||
|
groups = append(groups, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetGroupByName filters all groups in an account by name and returns the one with the most peers
|
// GetGroupByName filters all groups in an account by name and returns the one with the most peers
|
||||||
func (am *DefaultAccountManager) GetGroupByName(groupName, accountID string) (*Group, error) {
|
func (am *DefaultAccountManager) GetGroupByName(groupName, accountID string) (*Group, error) {
|
||||||
unlock := am.Store.AcquireAccountLock(accountID)
|
unlock := am.Store.AcquireAccountLock(accountID)
|
||||||
|
@ -76,6 +76,7 @@ func (h *AccountsHandler) UpdateAccount(w http.ResponseWriter, r *http.Request)
|
|||||||
settings := &server.Settings{
|
settings := &server.Settings{
|
||||||
PeerLoginExpirationEnabled: req.Settings.PeerLoginExpirationEnabled,
|
PeerLoginExpirationEnabled: req.Settings.PeerLoginExpirationEnabled,
|
||||||
PeerLoginExpiration: time.Duration(float64(time.Second.Nanoseconds()) * float64(req.Settings.PeerLoginExpiration)),
|
PeerLoginExpiration: time.Duration(float64(time.Second.Nanoseconds()) * float64(req.Settings.PeerLoginExpiration)),
|
||||||
|
RegularUsersViewBlocked: req.Settings.RegularUsersViewBlocked,
|
||||||
}
|
}
|
||||||
|
|
||||||
if req.Settings.Extra != nil {
|
if req.Settings.Extra != nil {
|
||||||
@ -143,6 +144,7 @@ func toAccountResponse(account *server.Account) *api.Account {
|
|||||||
JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled,
|
JwtGroupsEnabled: &account.Settings.JWTGroupsEnabled,
|
||||||
JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName,
|
JwtGroupsClaimName: &account.Settings.JWTGroupsClaimName,
|
||||||
JwtAllowGroups: &jwtAllowGroups,
|
JwtAllowGroups: &jwtAllowGroups,
|
||||||
|
RegularUsersViewBlocked: account.Settings.RegularUsersViewBlocked,
|
||||||
}
|
}
|
||||||
|
|
||||||
if account.Settings.Extra != nil {
|
if account.Settings.Extra != nil {
|
||||||
|
@ -69,6 +69,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
Settings: &server.Settings{
|
Settings: &server.Settings{
|
||||||
PeerLoginExpirationEnabled: false,
|
PeerLoginExpirationEnabled: false,
|
||||||
PeerLoginExpiration: time.Hour,
|
PeerLoginExpiration: time.Hour,
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
},
|
},
|
||||||
}, adminUser)
|
}, adminUser)
|
||||||
|
|
||||||
@ -96,6 +97,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
JwtGroupsClaimName: sr(""),
|
JwtGroupsClaimName: sr(""),
|
||||||
JwtGroupsEnabled: br(false),
|
JwtGroupsEnabled: br(false),
|
||||||
JwtAllowGroups: &[]string{},
|
JwtAllowGroups: &[]string{},
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
},
|
},
|
||||||
expectedArray: true,
|
expectedArray: true,
|
||||||
expectedID: accountID,
|
expectedID: accountID,
|
||||||
@ -114,6 +116,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
JwtGroupsClaimName: sr(""),
|
JwtGroupsClaimName: sr(""),
|
||||||
JwtGroupsEnabled: br(false),
|
JwtGroupsEnabled: br(false),
|
||||||
JwtAllowGroups: &[]string{},
|
JwtAllowGroups: &[]string{},
|
||||||
|
RegularUsersViewBlocked: false,
|
||||||
},
|
},
|
||||||
expectedArray: false,
|
expectedArray: false,
|
||||||
expectedID: accountID,
|
expectedID: accountID,
|
||||||
@ -123,7 +126,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
expectedBody: true,
|
expectedBody: true,
|
||||||
requestType: http.MethodPut,
|
requestType: http.MethodPut,
|
||||||
requestPath: "/api/accounts/" + accountID,
|
requestPath: "/api/accounts/" + accountID,
|
||||||
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": false,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"roles\",\"jwt_allow_groups\":[\"test\"]}}"),
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 15552000,\"peer_login_expiration_enabled\": false,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"roles\",\"jwt_allow_groups\":[\"test\"],\"regular_users_view_blocked\":true}}"),
|
||||||
expectedStatus: http.StatusOK,
|
expectedStatus: http.StatusOK,
|
||||||
expectedSettings: api.AccountSettings{
|
expectedSettings: api.AccountSettings{
|
||||||
PeerLoginExpiration: 15552000,
|
PeerLoginExpiration: 15552000,
|
||||||
@ -132,6 +135,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
JwtGroupsClaimName: sr("roles"),
|
JwtGroupsClaimName: sr("roles"),
|
||||||
JwtGroupsEnabled: br(true),
|
JwtGroupsEnabled: br(true),
|
||||||
JwtAllowGroups: &[]string{"test"},
|
JwtAllowGroups: &[]string{"test"},
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
},
|
},
|
||||||
expectedArray: false,
|
expectedArray: false,
|
||||||
expectedID: accountID,
|
expectedID: accountID,
|
||||||
@ -141,7 +145,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
expectedBody: true,
|
expectedBody: true,
|
||||||
requestType: http.MethodPut,
|
requestType: http.MethodPut,
|
||||||
requestPath: "/api/accounts/" + accountID,
|
requestPath: "/api/accounts/" + accountID,
|
||||||
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 554400,\"peer_login_expiration_enabled\": true,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"groups\",\"groups_propagation_enabled\":true}}"),
|
requestBody: bytes.NewBufferString("{\"settings\": {\"peer_login_expiration\": 554400,\"peer_login_expiration_enabled\": true,\"jwt_groups_enabled\":true,\"jwt_groups_claim_name\":\"groups\",\"groups_propagation_enabled\":true,\"regular_users_view_blocked\":true}}"),
|
||||||
expectedStatus: http.StatusOK,
|
expectedStatus: http.StatusOK,
|
||||||
expectedSettings: api.AccountSettings{
|
expectedSettings: api.AccountSettings{
|
||||||
PeerLoginExpiration: 554400,
|
PeerLoginExpiration: 554400,
|
||||||
@ -150,6 +154,7 @@ func TestAccounts_AccountsHandler(t *testing.T) {
|
|||||||
JwtGroupsClaimName: sr("groups"),
|
JwtGroupsClaimName: sr("groups"),
|
||||||
JwtGroupsEnabled: br(true),
|
JwtGroupsEnabled: br(true),
|
||||||
JwtAllowGroups: &[]string{},
|
JwtAllowGroups: &[]string{},
|
||||||
|
RegularUsersViewBlocked: true,
|
||||||
},
|
},
|
||||||
expectedArray: false,
|
expectedArray: false,
|
||||||
expectedID: accountID,
|
expectedID: accountID,
|
||||||
|
@ -54,6 +54,10 @@ components:
|
|||||||
description: Period of time after which peer login expires (seconds).
|
description: Period of time after which peer login expires (seconds).
|
||||||
type: integer
|
type: integer
|
||||||
example: 43200
|
example: 43200
|
||||||
|
regular_users_view_blocked:
|
||||||
|
description: Allows blocking regular users from viewing parts of the system.
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
groups_propagation_enabled:
|
groups_propagation_enabled:
|
||||||
description: Allows propagate the new user auto groups to peers that belongs to the user
|
description: Allows propagate the new user auto groups to peers that belongs to the user
|
||||||
type: boolean
|
type: boolean
|
||||||
@ -77,6 +81,7 @@ components:
|
|||||||
required:
|
required:
|
||||||
- peer_login_expiration_enabled
|
- peer_login_expiration_enabled
|
||||||
- peer_login_expiration
|
- peer_login_expiration
|
||||||
|
- regular_users_view_blocked
|
||||||
AccountExtraSettings:
|
AccountExtraSettings:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -144,6 +149,8 @@ components:
|
|||||||
description: How user was issued by API or Integration
|
description: How user was issued by API or Integration
|
||||||
type: string
|
type: string
|
||||||
example: api
|
example: api
|
||||||
|
permissions:
|
||||||
|
$ref: '#/components/schemas/UserPermissions'
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- email
|
- email
|
||||||
@ -152,6 +159,14 @@ components:
|
|||||||
- auto_groups
|
- auto_groups
|
||||||
- status
|
- status
|
||||||
- is_blocked
|
- is_blocked
|
||||||
|
UserPermissions:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
dashboard_view:
|
||||||
|
description: User's permission to view the dashboard
|
||||||
|
type: string
|
||||||
|
enum: [ "limited", "blocked", "full" ]
|
||||||
|
example: limited
|
||||||
UserRequest:
|
UserRequest:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -589,8 +604,6 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
enum: ["api", "integration", "jwt"]
|
enum: ["api", "integration", "jwt"]
|
||||||
example: api
|
example: api
|
||||||
type: string
|
|
||||||
example: api
|
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- name
|
- name
|
||||||
|
@ -69,6 +69,20 @@ const (
|
|||||||
GeoLocationCheckActionDeny GeoLocationCheckAction = "deny"
|
GeoLocationCheckActionDeny GeoLocationCheckAction = "deny"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for GroupIssued.
|
||||||
|
const (
|
||||||
|
GroupIssuedApi GroupIssued = "api"
|
||||||
|
GroupIssuedIntegration GroupIssued = "integration"
|
||||||
|
GroupIssuedJwt GroupIssued = "jwt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for GroupMinimumIssued.
|
||||||
|
const (
|
||||||
|
GroupMinimumIssuedApi GroupMinimumIssued = "api"
|
||||||
|
GroupMinimumIssuedIntegration GroupMinimumIssued = "integration"
|
||||||
|
GroupMinimumIssuedJwt GroupMinimumIssued = "jwt"
|
||||||
|
)
|
||||||
|
|
||||||
// Defines values for NameserverNsType.
|
// Defines values for NameserverNsType.
|
||||||
const (
|
const (
|
||||||
NameserverNsTypeUdp NameserverNsType = "udp"
|
NameserverNsTypeUdp NameserverNsType = "udp"
|
||||||
@ -129,6 +143,13 @@ const (
|
|||||||
UserStatusInvited UserStatus = "invited"
|
UserStatusInvited UserStatus = "invited"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for UserPermissionsDashboardView.
|
||||||
|
const (
|
||||||
|
UserPermissionsDashboardViewBlocked UserPermissionsDashboardView = "blocked"
|
||||||
|
UserPermissionsDashboardViewFull UserPermissionsDashboardView = "full"
|
||||||
|
UserPermissionsDashboardViewLimited UserPermissionsDashboardView = "limited"
|
||||||
|
)
|
||||||
|
|
||||||
// AccessiblePeer defines model for AccessiblePeer.
|
// AccessiblePeer defines model for AccessiblePeer.
|
||||||
type AccessiblePeer struct {
|
type AccessiblePeer struct {
|
||||||
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
// DnsLabel Peer's DNS label is the parsed peer name for domain resolution. It is used to form an FQDN by appending the account's domain to the peer label. e.g. peer-dns-label.netbird.cloud
|
||||||
@ -186,6 +207,9 @@ type AccountSettings struct {
|
|||||||
|
|
||||||
// PeerLoginExpirationEnabled Enables or disables peer login expiration globally. After peer's login has expired the user has to log in (authenticate). Applies only to peers that were added by a user (interactive SSO login).
|
// PeerLoginExpirationEnabled Enables or disables peer login expiration globally. After peer's login has expired the user has to log in (authenticate). Applies only to peers that were added by a user (interactive SSO login).
|
||||||
PeerLoginExpirationEnabled bool `json:"peer_login_expiration_enabled"`
|
PeerLoginExpirationEnabled bool `json:"peer_login_expiration_enabled"`
|
||||||
|
|
||||||
|
// RegularUsersViewBlocked Allows blocking regular users from viewing parts of the system.
|
||||||
|
RegularUsersViewBlocked bool `json:"regular_users_view_blocked"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks List of objects that perform the actual checks
|
// Checks List of objects that perform the actual checks
|
||||||
@ -283,8 +307,8 @@ type Group struct {
|
|||||||
// Id Group ID
|
// Id Group ID
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
|
||||||
// Issued How group was issued by API or from JWT token
|
// Issued How the group was issued (api, integration, jwt)
|
||||||
Issued *string `json:"issued,omitempty"`
|
Issued *GroupIssued `json:"issued,omitempty"`
|
||||||
|
|
||||||
// Name Group Name identifier
|
// Name Group Name identifier
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -296,13 +320,16 @@ type Group struct {
|
|||||||
PeersCount int `json:"peers_count"`
|
PeersCount int `json:"peers_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupIssued How the group was issued (api, integration, jwt)
|
||||||
|
type GroupIssued string
|
||||||
|
|
||||||
// GroupMinimum defines model for GroupMinimum.
|
// GroupMinimum defines model for GroupMinimum.
|
||||||
type GroupMinimum struct {
|
type GroupMinimum struct {
|
||||||
// Id Group ID
|
// Id Group ID
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
|
|
||||||
// Issued How group was issued by API or from JWT token
|
// Issued How the group was issued (api, integration, jwt)
|
||||||
Issued *string `json:"issued,omitempty"`
|
Issued *GroupMinimumIssued `json:"issued,omitempty"`
|
||||||
|
|
||||||
// Name Group Name identifier
|
// Name Group Name identifier
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -311,6 +338,9 @@ type GroupMinimum struct {
|
|||||||
PeersCount int `json:"peers_count"`
|
PeersCount int `json:"peers_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupMinimumIssued How the group was issued (api, integration, jwt)
|
||||||
|
type GroupMinimumIssued string
|
||||||
|
|
||||||
// GroupRequest defines model for GroupRequest.
|
// GroupRequest defines model for GroupRequest.
|
||||||
type GroupRequest struct {
|
type GroupRequest struct {
|
||||||
// Name Group name identifier
|
// Name Group name identifier
|
||||||
@ -1072,7 +1102,8 @@ type User struct {
|
|||||||
LastLogin *time.Time `json:"last_login,omitempty"`
|
LastLogin *time.Time `json:"last_login,omitempty"`
|
||||||
|
|
||||||
// Name User's name from idp provider
|
// Name User's name from idp provider
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Permissions *UserPermissions `json:"permissions,omitempty"`
|
||||||
|
|
||||||
// Role User's NetBird account role
|
// Role User's NetBird account role
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
@ -1102,6 +1133,15 @@ type UserCreateRequest struct {
|
|||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserPermissions defines model for UserPermissions.
|
||||||
|
type UserPermissions struct {
|
||||||
|
// DashboardView User's permission to view the dashboard
|
||||||
|
DashboardView *UserPermissionsDashboardView `json:"dashboard_view,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserPermissionsDashboardView User's permission to view the dashboard
|
||||||
|
type UserPermissionsDashboardView string
|
||||||
|
|
||||||
// UserRequest defines model for UserRequest.
|
// UserRequest defines model for UserRequest.
|
||||||
type UserRequest struct {
|
type UserRequest struct {
|
||||||
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
// AutoGroups Group IDs to auto-assign to peers registered by this user
|
||||||
|
@ -35,19 +35,25 @@ func NewGroupsHandler(accountManager server.AccountManager, authCfg AuthCfg) *Gr
|
|||||||
// GetAllGroups list for the account
|
// GetAllGroups list for the account
|
||||||
func (h *GroupsHandler) GetAllGroups(w http.ResponseWriter, r *http.Request) {
|
func (h *GroupsHandler) GetAllGroups(w http.ResponseWriter, r *http.Request) {
|
||||||
claims := h.claimsExtractor.FromRequestContext(r)
|
claims := h.claimsExtractor.FromRequestContext(r)
|
||||||
account, _, err := h.accountManager.GetAccountFromToken(claims)
|
account, user, err := h.accountManager.GetAccountFromToken(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
http.Redirect(w, r, "/", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var groups []*api.Group
|
groups, err := h.accountManager.GetAllGroups(account.Id, user.Id)
|
||||||
for _, g := range account.Groups {
|
if err != nil {
|
||||||
groups = append(groups, toGroupResponse(account, g))
|
util.WriteError(err, w)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
util.WriteJSONObject(w, groups)
|
groupsResponse := make([]*api.Group, 0, len(groups))
|
||||||
|
for _, group := range groups {
|
||||||
|
groupsResponse = append(groupsResponse, toGroupResponse(account, group))
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(w, groupsResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateGroup handles update to a group identified by a given ID
|
// UpdateGroup handles update to a group identified by a given ID
|
||||||
@ -207,7 +213,7 @@ func (h *GroupsHandler) DeleteGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
// GetGroup returns a group
|
// GetGroup returns a group
|
||||||
func (h *GroupsHandler) GetGroup(w http.ResponseWriter, r *http.Request) {
|
func (h *GroupsHandler) GetGroup(w http.ResponseWriter, r *http.Request) {
|
||||||
claims := h.claimsExtractor.FromRequestContext(r)
|
claims := h.claimsExtractor.FromRequestContext(r)
|
||||||
account, _, err := h.accountManager.GetAccountFromToken(claims)
|
account, user, err := h.accountManager.GetAccountFromToken(claims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(err, w)
|
util.WriteError(err, w)
|
||||||
return
|
return
|
||||||
@ -221,7 +227,7 @@ func (h *GroupsHandler) GetGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
group, err := h.accountManager.GetGroup(account.Id, groupID)
|
group, err := h.accountManager.GetGroup(account.Id, groupID, user.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(err, w)
|
util.WriteError(err, w)
|
||||||
return
|
return
|
||||||
@ -239,7 +245,7 @@ func toGroupResponse(account *server.Account, group *server.Group) *api.Group {
|
|||||||
gr := api.Group{
|
gr := api.Group{
|
||||||
Id: group.ID,
|
Id: group.ID,
|
||||||
Name: group.Name,
|
Name: group.Name,
|
||||||
Issued: &group.Issued,
|
Issued: (*api.GroupIssued)(&group.Issued),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pid := range group.Peers {
|
for _, pid := range group.Peers {
|
||||||
|
@ -37,7 +37,7 @@ func initGroupTestData(user *server.User, groups ...*server.Group) *GroupsHandle
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
GetGroupFunc: func(_, groupID string) (*server.Group, error) {
|
GetGroupFunc: func(_, groupID, _ string) (*server.Group, error) {
|
||||||
if groupID != "idofthegroup" {
|
if groupID != "idofthegroup" {
|
||||||
return nil, status.Errorf(status.NotFound, "not found")
|
return nil, status.Errorf(status.NotFound, "not found")
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ func TestWriteGroup(t *testing.T) {
|
|||||||
expectedGroup: &api.Group{
|
expectedGroup: &api.Group{
|
||||||
Id: "id-was-set",
|
Id: "id-was-set",
|
||||||
Name: "Default POSTed Group",
|
Name: "Default POSTed Group",
|
||||||
Issued: &groupIssuedAPI,
|
Issued: (*api.GroupIssued)(&groupIssuedAPI),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -209,7 +209,7 @@ func TestWriteGroup(t *testing.T) {
|
|||||||
expectedGroup: &api.Group{
|
expectedGroup: &api.Group{
|
||||||
Id: "id-existed",
|
Id: "id-existed",
|
||||||
Name: "Default POSTed Group",
|
Name: "Default POSTed Group",
|
||||||
Issued: &groupIssuedAPI,
|
Issued: (*api.GroupIssued)(&groupIssuedAPI),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -240,7 +240,7 @@ func TestWriteGroup(t *testing.T) {
|
|||||||
expectedGroup: &api.Group{
|
expectedGroup: &api.Group{
|
||||||
Id: "id-jwt-group",
|
Id: "id-jwt-group",
|
||||||
Name: "changed",
|
Name: "changed",
|
||||||
Issued: &groupIssuedJWT,
|
Issued: (*api.GroupIssued)(&groupIssuedJWT),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -288,5 +288,8 @@ func toUserResponse(user *server.UserInfo, currenUserID string) *api.User {
|
|||||||
IsBlocked: user.IsBlocked,
|
IsBlocked: user.IsBlocked,
|
||||||
LastLogin: &user.LastLogin,
|
LastLogin: &user.LastLogin,
|
||||||
Issued: &user.Issued,
|
Issued: &user.Issued,
|
||||||
|
Permissions: &api.UserPermissions{
|
||||||
|
DashboardView: (*api.UserPermissionsDashboardView)(&user.Permissions.DashboardView),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func initUsersTestData() *UsersHandler {
|
|||||||
return nil, status.Errorf(status.NotFound, "user with ID %s does not exists", userID)
|
return nil, status.Errorf(status.NotFound, "user with ID %s does not exists", userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := update.Copy().ToUserInfo(nil)
|
info, err := update.Copy().ToUserInfo(nil, &server.Settings{RegularUsersViewBlocked: false})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ type MockAccountManager struct {
|
|||||||
GetNetworkMapFunc func(peerKey string) (*server.NetworkMap, error)
|
GetNetworkMapFunc func(peerKey string) (*server.NetworkMap, error)
|
||||||
GetPeerNetworkFunc func(peerKey string) (*server.Network, error)
|
GetPeerNetworkFunc func(peerKey string) (*server.Network, error)
|
||||||
AddPeerFunc func(setupKey string, userId string, peer *nbpeer.Peer) (*nbpeer.Peer, *server.NetworkMap, error)
|
AddPeerFunc func(setupKey string, userId string, peer *nbpeer.Peer) (*nbpeer.Peer, *server.NetworkMap, error)
|
||||||
GetGroupFunc func(accountID, groupID string) (*server.Group, error)
|
GetGroupFunc func(accountID, groupID, userID string) (*server.Group, error)
|
||||||
|
GetAllGroupsFunc func(accountID, userID string) ([]*server.Group, error)
|
||||||
GetGroupByNameFunc func(accountID, groupName string) (*server.Group, error)
|
GetGroupByNameFunc func(accountID, groupName string) (*server.Group, error)
|
||||||
SaveGroupFunc func(accountID, userID string, group *server.Group) error
|
SaveGroupFunc func(accountID, userID string, group *server.Group) error
|
||||||
DeleteGroupFunc func(accountID, userId, groupID string) error
|
DeleteGroupFunc func(accountID, userId, groupID string) error
|
||||||
@ -92,6 +93,22 @@ type MockAccountManager struct {
|
|||||||
GetIdpManagerFunc func() idp.Manager
|
GetIdpManagerFunc func() idp.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetGroup mock implementation of GetGroup from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) GetGroup(accountId, groupID, userID string) (*server.Group, error) {
|
||||||
|
if am.GetGroupFunc != nil {
|
||||||
|
return am.GetGroupFunc(accountId, groupID, userID)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetGroup is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllGroups mock implementation of GetAllGroups from server.AccountManager interface
|
||||||
|
func (am *MockAccountManager) GetAllGroups(accountID, userID string) ([]*server.Group, error) {
|
||||||
|
if am.GetAllGroupsFunc != nil {
|
||||||
|
return am.GetAllGroupsFunc(accountID, userID)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetAllGroups is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
|
// GetUsersFromAccount mock implementation of GetUsersFromAccount from server.AccountManager interface
|
||||||
func (am *MockAccountManager) GetUsersFromAccount(accountID string, userID string) ([]*server.UserInfo, error) {
|
func (am *MockAccountManager) GetUsersFromAccount(accountID string, userID string) ([]*server.UserInfo, error) {
|
||||||
if am.GetUsersFromAccountFunc != nil {
|
if am.GetUsersFromAccountFunc != nil {
|
||||||
@ -243,14 +260,6 @@ func (am *MockAccountManager) AddPeer(
|
|||||||
return nil, nil, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
|
return nil, nil, status.Errorf(codes.Unimplemented, "method AddPeer is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroup mock implementation of GetGroup from server.AccountManager interface
|
|
||||||
func (am *MockAccountManager) GetGroup(accountID, groupID string) (*server.Group, error) {
|
|
||||||
if am.GetGroupFunc != nil {
|
|
||||||
return am.GetGroupFunc(accountID, groupID)
|
|
||||||
}
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetGroup is not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGroupByName mock implementation of GetGroupByName from server.AccountManager interface
|
// GetGroupByName mock implementation of GetGroupByName from server.AccountManager interface
|
||||||
func (am *MockAccountManager) GetGroupByName(accountID, groupName string) (*server.Group, error) {
|
func (am *MockAccountManager) GetGroupByName(accountID, groupName string) (*server.Group, error) {
|
||||||
if am.GetGroupFunc != nil {
|
if am.GetGroupFunc != nil {
|
||||||
|
@ -54,6 +54,11 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.P
|
|||||||
|
|
||||||
peers := make([]*nbpeer.Peer, 0)
|
peers := make([]*nbpeer.Peer, 0)
|
||||||
peersMap := make(map[string]*nbpeer.Peer)
|
peersMap := make(map[string]*nbpeer.Peer)
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser && account.Settings.RegularUsersViewBlocked {
|
||||||
|
return peers, nil
|
||||||
|
}
|
||||||
|
|
||||||
for _, peer := range account.Peers {
|
for _, peer := range account.Peers {
|
||||||
if !(user.HasAdminPower() || user.IsServiceUser) && user.Id != peer.UserID {
|
if !(user.HasAdminPower() || user.IsServiceUser) && user.Id != peer.UserID {
|
||||||
// only display peers that belong to the current user if the current user is not an admin
|
// only display peers that belong to the current user if the current user is not an admin
|
||||||
@ -738,6 +743,10 @@ func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*nbp
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser && account.Settings.RegularUsersViewBlocked {
|
||||||
|
return nil, status.Errorf(status.Internal, "user %s has no access to his own peer %s under account %s", userID, peerID, accountID)
|
||||||
|
}
|
||||||
|
|
||||||
peer := account.GetPeer(peerID)
|
peer := account.GetPeer(peerID)
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
return nil, status.Errorf(status.NotFound, "peer with %s not found under account %s", peerID, accountID)
|
return nil, status.Errorf(status.NotFound, "peer with %s not found under account %s", peerID, accountID)
|
||||||
|
@ -4,9 +4,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
@ -392,6 +391,8 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) {
|
|||||||
Id: someUser,
|
Id: someUser,
|
||||||
Role: UserRoleUser,
|
Role: UserRoleUser,
|
||||||
}
|
}
|
||||||
|
account.Settings.RegularUsersViewBlocked = false
|
||||||
|
|
||||||
err = manager.Store.SaveAccount(account)
|
err = manager.Store.SaveAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -480,3 +481,153 @@ func TestDefaultAccountManager_GetPeer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.NotNil(t, peer)
|
assert.NotNil(t, peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultAccountManager_GetPeers(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
role UserRole
|
||||||
|
limitedViewSettings bool
|
||||||
|
isServiceUser bool
|
||||||
|
expectedPeerCount int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user, no limited view settings, not a service user",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service user, no limited view settings",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
isServiceUser: true,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular user, limited view settings",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service user, limited view settings",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: true,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin, no limited view settings, not a service user",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin service user, no limited view settings",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
isServiceUser: true,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin, limited view settings",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin Service user, limited view settings",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: true,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner, no limited view settings",
|
||||||
|
role: UserRoleOwner,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner, limited view settings",
|
||||||
|
role: UserRoleOwner,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
isServiceUser: false,
|
||||||
|
expectedPeerCount: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
manager, err := createManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// account with an admin and a regular user
|
||||||
|
accountID := "test_account"
|
||||||
|
adminUser := "account_creator"
|
||||||
|
someUser := "some_user"
|
||||||
|
account := newAccountWithId(accountID, adminUser, "")
|
||||||
|
account.Users[someUser] = &User{
|
||||||
|
Id: someUser,
|
||||||
|
Role: testCase.role,
|
||||||
|
IsServiceUser: testCase.isServiceUser,
|
||||||
|
}
|
||||||
|
account.Policies = []*Policy{}
|
||||||
|
account.Settings.RegularUsersViewBlocked = testCase.limitedViewSettings
|
||||||
|
|
||||||
|
err = manager.Store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peerKey1, err := wgtypes.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peerKey2, err := wgtypes.GeneratePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = manager.AddPeer("", someUser, &nbpeer.Peer{
|
||||||
|
Key: peerKey1.PublicKey().String(),
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-1"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expecting peer to be added, got failure %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = manager.AddPeer("", adminUser, &nbpeer.Peer{
|
||||||
|
Key: peerKey2.PublicKey().String(),
|
||||||
|
Meta: nbpeer.PeerSystemMeta{Hostname: "test-peer-2"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expecting peer to be added, got failure %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
peers, err := manager.GetPeers(accountID, someUser)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.NotNil(t, peers)
|
||||||
|
|
||||||
|
assert.Len(t, peers, testCase.expectedPeerCount)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -339,6 +339,10 @@ func (am *DefaultAccountManager) ListSetupKeys(accountID, userID string) ([]*Set
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser {
|
||||||
|
return nil, status.Errorf(status.Unauthorized, "only users with admin power can view policies")
|
||||||
|
}
|
||||||
|
|
||||||
keys := make([]*SetupKey, 0, len(account.SetupKeys))
|
keys := make([]*SetupKey, 0, len(account.SetupKeys))
|
||||||
for _, key := range account.SetupKeys {
|
for _, key := range account.SetupKeys {
|
||||||
var k *SetupKey
|
var k *SetupKey
|
||||||
@ -368,6 +372,10 @@ func (am *DefaultAccountManager) GetSetupKey(accountID, userID, keyID string) (*
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !user.HasAdminPower() && !user.IsServiceUser {
|
||||||
|
return nil, status.Errorf(status.Unauthorized, "only users with admin power can view policies")
|
||||||
|
}
|
||||||
|
|
||||||
var foundKey *SetupKey
|
var foundKey *SetupKey
|
||||||
for _, key := range account.SetupKeys {
|
for _, key := range account.SetupKeys {
|
||||||
if key.Id == keyID {
|
if key.Id == keyID {
|
||||||
|
@ -166,6 +166,37 @@ func TestDefaultAccountManager_CreateSetupKey(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetSetupKeys(t *testing.T) {
|
||||||
|
manager, err := createManager(t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
userID := "testingUser"
|
||||||
|
account, err := manager.GetOrCreateAccountByUser(userID, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = manager.SaveGroup(account.Id, userID, &Group{
|
||||||
|
ID: "group_1",
|
||||||
|
Name: "group_name_1",
|
||||||
|
Peers: []string{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = manager.SaveGroup(account.Id, userID, &Group{
|
||||||
|
ID: "group_2",
|
||||||
|
Name: "group_name_2",
|
||||||
|
Peers: []string{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGenerateDefaultSetupKey(t *testing.T) {
|
func TestGenerateDefaultSetupKey(t *testing.T) {
|
||||||
expectedName := "Default key"
|
expectedName := "Default key"
|
||||||
expectedRevoke := false
|
expectedRevoke := false
|
||||||
|
@ -113,12 +113,20 @@ func (u *User) HasAdminPower() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToUserInfo converts a User object to a UserInfo object.
|
// ToUserInfo converts a User object to a UserInfo object.
|
||||||
func (u *User) ToUserInfo(userData *idp.UserData) (*UserInfo, error) {
|
func (u *User) ToUserInfo(userData *idp.UserData, settings *Settings) (*UserInfo, error) {
|
||||||
autoGroups := u.AutoGroups
|
autoGroups := u.AutoGroups
|
||||||
if autoGroups == nil {
|
if autoGroups == nil {
|
||||||
autoGroups = []string{}
|
autoGroups = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dashboardViewPermissions := "full"
|
||||||
|
if !u.HasAdminPower() {
|
||||||
|
dashboardViewPermissions = "limited"
|
||||||
|
if settings.RegularUsersViewBlocked {
|
||||||
|
dashboardViewPermissions = "blocked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if userData == nil {
|
if userData == nil {
|
||||||
return &UserInfo{
|
return &UserInfo{
|
||||||
ID: u.Id,
|
ID: u.Id,
|
||||||
@ -131,6 +139,9 @@ func (u *User) ToUserInfo(userData *idp.UserData) (*UserInfo, error) {
|
|||||||
IsBlocked: u.Blocked,
|
IsBlocked: u.Blocked,
|
||||||
LastLogin: u.LastLogin,
|
LastLogin: u.LastLogin,
|
||||||
Issued: u.Issued,
|
Issued: u.Issued,
|
||||||
|
Permissions: UserPermissions{
|
||||||
|
DashboardView: dashboardViewPermissions,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
if userData.ID != u.Id {
|
if userData.ID != u.Id {
|
||||||
@ -153,6 +164,9 @@ func (u *User) ToUserInfo(userData *idp.UserData) (*UserInfo, error) {
|
|||||||
IsBlocked: u.Blocked,
|
IsBlocked: u.Blocked,
|
||||||
LastLogin: u.LastLogin,
|
LastLogin: u.LastLogin,
|
||||||
Issued: u.Issued,
|
Issued: u.Issued,
|
||||||
|
Permissions: UserPermissions{
|
||||||
|
DashboardView: dashboardViewPermissions,
|
||||||
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +372,7 @@ func (am *DefaultAccountManager) inviteNewUser(accountID, userID string, invite
|
|||||||
|
|
||||||
am.StoreEvent(userID, newUser.Id, accountID, activity.UserInvited, nil)
|
am.StoreEvent(userID, newUser.Id, accountID, activity.UserInvited, nil)
|
||||||
|
|
||||||
return newUser.ToUserInfo(idpUser)
|
return newUser.ToUserInfo(idpUser, account.Settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUser looks up a user by provided authorization claims.
|
// GetUser looks up a user by provided authorization claims.
|
||||||
@ -905,9 +919,9 @@ func (am *DefaultAccountManager) SaveOrAddUser(accountID, initiatorUserID string
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newUser.ToUserInfo(userData)
|
return newUser.ToUserInfo(userData, account.Settings)
|
||||||
}
|
}
|
||||||
return newUser.ToUserInfo(nil)
|
return newUser.ToUserInfo(nil, account.Settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrCreateAccountByUser returns an existing account for a given user id or creates a new one if doesn't exist
|
// GetOrCreateAccountByUser returns an existing account for a given user id or creates a new one if doesn't exist
|
||||||
@ -998,7 +1012,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) (
|
|||||||
// if user is not an admin then show only current user and do not show other users
|
// if user is not an admin then show only current user and do not show other users
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info, err := accountUser.ToUserInfo(nil)
|
info, err := accountUser.ToUserInfo(nil, account.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1015,7 +1029,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) (
|
|||||||
|
|
||||||
var info *UserInfo
|
var info *UserInfo
|
||||||
if queriedUser, contains := findUserInIDPUserdata(localUser.Id, queriedUsers); contains {
|
if queriedUser, contains := findUserInIDPUserdata(localUser.Id, queriedUsers); contains {
|
||||||
info, err = localUser.ToUserInfo(queriedUser)
|
info, err = localUser.ToUserInfo(queriedUser, account.Settings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1024,6 +1038,15 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) (
|
|||||||
if localUser.IsServiceUser {
|
if localUser.IsServiceUser {
|
||||||
name = localUser.ServiceUserName
|
name = localUser.ServiceUserName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dashboardViewPermissions := "full"
|
||||||
|
if !localUser.HasAdminPower() {
|
||||||
|
dashboardViewPermissions = "limited"
|
||||||
|
if account.Settings.RegularUsersViewBlocked {
|
||||||
|
dashboardViewPermissions = "blocked"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
info = &UserInfo{
|
info = &UserInfo{
|
||||||
ID: localUser.Id,
|
ID: localUser.Id,
|
||||||
Email: "",
|
Email: "",
|
||||||
@ -1033,6 +1056,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) (
|
|||||||
Status: string(UserStatusActive),
|
Status: string(UserStatusActive),
|
||||||
IsServiceUser: localUser.IsServiceUser,
|
IsServiceUser: localUser.IsServiceUser,
|
||||||
NonDeletable: localUser.NonDeletable,
|
NonDeletable: localUser.NonDeletable,
|
||||||
|
Permissions: UserPermissions{DashboardView: dashboardViewPermissions},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
userInfos = append(userInfos, info)
|
userInfos = append(userInfos, info)
|
||||||
|
@ -709,6 +709,83 @@ func TestDefaultAccountManager_ListUsers(t *testing.T) {
|
|||||||
assert.Equal(t, 2, regular)
|
assert.Equal(t, 2, regular)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDefaultAccountManager_ListUsers_DashboardPermissions(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
role UserRole
|
||||||
|
limitedViewSettings bool
|
||||||
|
expectedDashboardPermissions string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Regular user, no limited view settings",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
expectedDashboardPermissions: "limited",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user, no limited view settings",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
expectedDashboardPermissions: "full",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner, no limited view settings",
|
||||||
|
role: UserRoleOwner,
|
||||||
|
limitedViewSettings: false,
|
||||||
|
expectedDashboardPermissions: "full",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Regular user, limited view settings",
|
||||||
|
role: UserRoleUser,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
expectedDashboardPermissions: "blocked",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Admin user, limited view settings",
|
||||||
|
role: UserRoleAdmin,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
expectedDashboardPermissions: "full",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Owner, limited view settings",
|
||||||
|
role: UserRoleOwner,
|
||||||
|
limitedViewSettings: true,
|
||||||
|
expectedDashboardPermissions: "full",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
store := newStore(t)
|
||||||
|
account := newAccountWithId(mockAccountID, mockUserID, "")
|
||||||
|
account.Users["normal_user1"] = NewUser("normal_user1", testCase.role, false, false, "", []string{}, UserIssuedAPI)
|
||||||
|
account.Settings.RegularUsersViewBlocked = testCase.limitedViewSettings
|
||||||
|
delete(account.Users, mockUserID)
|
||||||
|
|
||||||
|
err := store.SaveAccount(account)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when saving account: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
am := DefaultAccountManager{
|
||||||
|
Store: store,
|
||||||
|
eventStore: &activity.InMemoryEventStore{},
|
||||||
|
}
|
||||||
|
|
||||||
|
users, err := am.ListUsers(mockAccountID)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error when checking user role: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(users))
|
||||||
|
|
||||||
|
userInfo, _ := users[0].ToUserInfo(nil, account.Settings)
|
||||||
|
assert.Equal(t, testCase.expectedDashboardPermissions, userInfo.Permissions.DashboardView)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestDefaultAccountManager_ExternalCache(t *testing.T) {
|
func TestDefaultAccountManager_ExternalCache(t *testing.T) {
|
||||||
store := newStore(t)
|
store := newStore(t)
|
||||||
account := newAccountWithId(mockAccountID, mockUserID, "")
|
account := newAccountWithId(mockAccountID, mockUserID, "")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user