Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#209] Improve managed group admin assignment and synchronization #215

Merged
merged 10 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ go.sum
*.sh
docker-compose.env
docker-compose.yml
env.list
*.exe
16 changes: 11 additions & 5 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
},
{
"path": "detect_secrets.filters.heuristic.is_templated_secret"
},
{
"path": "detect_secrets.filters.regex.should_exclude_file",
"pattern": [
"go.sum"
]
}
],
"results": {
Expand Down Expand Up @@ -150,7 +156,7 @@
"filename": "driver/web/auth.go",
"hashed_secret": "45b2e8300605777bea57e3ffe5144279b0dc465a",
"is_verified": false,
"line_number": 294,
"line_number": 292,
"is_secret": false
}
],
Expand All @@ -160,26 +166,26 @@
"filename": "main.go",
"hashed_secret": "1c8725bce2d4329f6eba1a32bd54ff5129624f96",
"is_verified": false,
"line_number": 48,
"line_number": 49,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "main.go",
"hashed_secret": "3da36c7160b1a0ee02bc7bdff973c51561f8d0cc",
"is_verified": false,
"line_number": 62,
"line_number": 63,
"is_secret": false
},
{
"type": "Secret Keyword",
"filename": "main.go",
"hashed_secret": "2347b8ae84429edaa1c0c07fecd850fc099c0554",
"is_verified": false,
"line_number": 68,
"line_number": 69,
"is_secret": false
}
]
},
"generated_at": "2022-07-22T07:35:28Z"
"generated_at": "2022-08-03T22:32:25Z"
}
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
### Added
- Improve managed group admin assignment and synchronization [#209](https://github.com/rokwire/groups-building-block/issues/209)

## [1.5.59] - 2022-07-29
### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ GR_OIDC_ADMIN_CLIENT_ID | < url > | yes | Client ID to validate with OIDC for ad
GR_OIDC_ADMIN_WEB_CLIENT_ID | < url > | yes | Client ID to validate with OIDC for web client
ROKWIRE_API_KEYS | < string (comma-separated) > | yes | List of API keys to be used for client verification
AUTHMAN_ADMIN_UIN_LIST | < string (comma-separated) > | yes | List of UINs for admin users used when loading data from AuthMan

SYNC_MANAGED_GROUP_PERIOD | < int > | no | Period at which to automatically sync managed groups in minutes. Missing or 0 disables automatic sync timer.

### Run Application

Expand Down
64 changes: 62 additions & 2 deletions core/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"groups/core/model"
"groups/driven/corebb"
"groups/driven/rewards"
"log"
"time"
)

// Application represents the corebb application code based on hexagonal architecture
Expand All @@ -38,13 +40,21 @@ type Application struct {
rewards Rewards

authmanSyncInProgress bool

//synchronize managed groups timer
syncManagedGroupsTimer *time.Timer
syncManagedGroupsTimerDone chan bool
}

// Start starts the corebb part of the application
func (app *Application) Start() {
// set storage listener
storageListener := storageListenerImpl{app: app}
app.storage.SetStorageListener(&storageListener)
app.storage.RegisterStorageListener(&storageListener)

if app.config != nil && app.config.SyncManagedGroupsPeriod != 0 {
go app.setupSyncManagedGroupTimer()
}
}

// FindUser finds an user for the provided external id
Expand Down Expand Up @@ -93,12 +103,62 @@ func (app *Application) CreateUser(clientID string, id string, externalID *strin
return user, nil
}

func (app *Application) setupSyncManagedGroupTimer() {
log.Println("setupSyncManagedGroupTimer")

//cancel if active
if app.syncManagedGroupsTimer != nil {
app.syncManagedGroupsTimerDone <- true
app.syncManagedGroupsTimer.Stop()
}

app.syncManagedGroups()
}

func (app *Application) syncManagedGroups() {
log.Println("syncManagedGroups")
if app.config == nil {
return
}

for _, clientID := range app.config.SupportedClientIDs {
configs, err := app.storage.FindManagedGroupConfigs(clientID)
if err != nil {
log.Printf("error finding managed group configs for clientID %s\n", clientID)
}
if len(configs) > 0 {
err = app.synchronizeAuthman(clientID, configs)
if err != nil {
log.Printf("error syncing authman groups %s\n", err.Error())
}
}
}

durationMins := 1440
if app.config.SyncManagedGroupsPeriod != 0 {
durationMins = app.config.SyncManagedGroupsPeriod
}
duration := time.Minute * time.Duration(durationMins)
app.syncManagedGroupsTimer = time.NewTimer(duration)
select {
case <-app.syncManagedGroupsTimer.C:
// timer expired
app.syncManagedGroupsTimer = nil

app.syncManagedGroups()
case <-app.syncManagedGroupsTimerDone:
// timer aborted
app.syncManagedGroupsTimer = nil
}
}

// NewApplication creates new Application
func NewApplication(version string, build string, storage Storage, notifications Notifications, authman Authman, core *corebb.Adapter,
rewards *rewards.Adapter, config *model.Config) *Application {

timerDone := make(chan bool)
application := Application{version: version, build: build, storage: storage, notifications: notifications,
authman: authman, corebb: core, rewards: rewards, config: config}
authman: authman, corebb: core, rewards: rewards, config: config, syncManagedGroupsTimerDone: timerDone}

//add the drivers ports/interfaces
application.Services = &servicesImpl{app: &application}
Expand Down
64 changes: 47 additions & 17 deletions core/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
package core

import (
"fmt"
"groups/core/model"
"groups/driven/notifications"
"groups/driven/storage"
"groups/utils"
"time"
)

Expand All @@ -34,8 +37,8 @@ type Services interface {
GetGroupEntityByMembership(clientID string, membershipID string) (*model.Group, error)
GetGroupEntityByTitle(clientID string, title string) (*model.Group, error)

CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *GroupError)
UpdateGroup(clientID string, current *model.User, group *model.Group) *GroupError
CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *utils.GroupError)
UpdateGroup(clientID string, current *model.User, group *model.Group) *utils.GroupError
DeleteGroup(clientID string, current *model.User, id string) error
GetAllGroups(clientID string) ([]model.Group, error)
GetGroups(clientID string, current *model.User, category *string, privacy *string, title *string, offset *int64, limit *int64, order *string) ([]map[string]interface{}, error)
Expand Down Expand Up @@ -66,8 +69,13 @@ type Services interface {
ReportPostAsAbuse(clientID string, current *model.User, group *model.Group, post *model.Post, comment string, sendToDean bool, sendToGroupAdmins bool) error
DeletePost(clientID string, current *model.User, groupID string, postID string, force bool) error

SynchronizeAuthman(clientID string, stemNames []string) error
SynchronizeAuthman(clientID string) error
SynchronizeAuthmanGroup(clientID string, group *model.Group) error

GetManagedGroupConfigs(clientID string) ([]model.ManagedGroupConfig, error)
CreateManagedGroupConfig(config model.ManagedGroupConfig) (*model.ManagedGroupConfig, error)
UpdateManagedGroupConfig(config model.ManagedGroupConfig) error
DeleteManagedGroupConfig(id string, clientID string) error
}

type servicesImpl struct {
Expand Down Expand Up @@ -103,11 +111,11 @@ func (s *servicesImpl) GetGroupEntityByTitle(clientID string, title string) (*mo
return s.app.getGroupEntityByTitle(clientID, title)
}

func (s *servicesImpl) CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *GroupError) {
func (s *servicesImpl) CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *utils.GroupError) {
return s.app.createGroup(clientID, current, group)
}

func (s *servicesImpl) UpdateGroup(clientID string, current *model.User, group *model.Group) *GroupError {
func (s *servicesImpl) UpdateGroup(clientID string, current *model.User, group *model.Group) *utils.GroupError {
return s.app.updateGroup(clientID, current, group)
}

Expand Down Expand Up @@ -215,14 +223,34 @@ func (s *servicesImpl) DeletePost(clientID string, current *model.User, groupID
return s.app.deletePost(clientID, current.ID, groupID, postID, force)
}

func (s *servicesImpl) SynchronizeAuthman(clientID string, stemNames []string) error {
return s.app.synchronizeAuthman(clientID, stemNames)
func (s *servicesImpl) SynchronizeAuthman(clientID string) error {
configs, err := s.app.storage.FindManagedGroupConfigs(clientID)
if err != nil {
return fmt.Errorf("error finding managed group configs for clientID %s", clientID)
}
return s.app.synchronizeAuthman(clientID, configs)
}

func (s *servicesImpl) SynchronizeAuthmanGroup(clientID string, group *model.Group) error {
return s.app.synchronizeAuthmanGroup(clientID, group)
}

func (s *servicesImpl) GetManagedGroupConfigs(clientID string) ([]model.ManagedGroupConfig, error) {
return s.app.getManagedGroupConfigs(clientID)
}

func (s *servicesImpl) CreateManagedGroupConfig(config model.ManagedGroupConfig) (*model.ManagedGroupConfig, error) {
return s.app.createManagedGroupConfig(config)
}

func (s *servicesImpl) UpdateManagedGroupConfig(config model.ManagedGroupConfig) error {
return s.app.updateManagedGroupConfig(config)
}

func (s *servicesImpl) DeleteManagedGroupConfig(id string, clientID string) error {
return s.app.deleteManagedGroupConfig(id, clientID)
}

// Administration exposes administration APIs for the driver adapters
type Administration interface {
GetGroups(clientID string, category *string, privacy *string, title *string, offset *int64, limit *int64, order *string) ([]model.Group, error)
Expand All @@ -238,7 +266,7 @@ func (s *administrationImpl) GetGroups(clientID string, category *string, privac

// Storage is used by corebb to storage data - DB storage adapter, file storage adapter etc
type Storage interface {
SetStorageListener(storageListener StorageListener)
RegisterStorageListener(listener storage.Listener)

FindUser(clientID string, id string, external bool) (*model.User, error)
FindUsers(clientID string, ids []string, external bool) ([]model.User, error)
Expand All @@ -250,9 +278,9 @@ type Storage interface {
ReadAllGroupCategories() ([]string, error)
FindUserGroupsMemberships(id string, external bool) ([]*model.Group, *model.User, error)

CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *GroupError)
UpdateGroupWithoutMembers(clientID string, current *model.User, group *model.Group) *GroupError
UpdateGroupWithMembers(clientID string, current *model.User, group *model.Group) *GroupError
CreateGroup(clientID string, current *model.User, group *model.Group) (*string, *utils.GroupError)
UpdateGroupWithoutMembers(clientID string, current *model.User, group *model.Group) *utils.GroupError
UpdateGroupWithMembers(clientID string, current *model.User, group *model.Group) *utils.GroupError
DeleteGroup(clientID string, id string) error
FindGroup(clientID string, id string) (*model.Group, error)
FindGroupByMembership(clientID string, membershipID string) (*model.Group, error)
Expand Down Expand Up @@ -287,18 +315,20 @@ type Storage interface {

FindAuthmanGroups(clientID string) ([]model.Group, error)
FindAuthmanGroupByKey(clientID string, authmanGroupKey string) (*model.Group, error)
}

//StorageListener listenes for change data storage events
type StorageListener interface {
OnConfigsChanged()
LoadManagedGroupConfigs() ([]model.ManagedGroupConfig, error)
FindManagedGroupConfig(id string, clientID string) (*model.ManagedGroupConfig, error)
FindManagedGroupConfigs(clientID string) ([]model.ManagedGroupConfig, error)
InsertManagedGroupConfig(config model.ManagedGroupConfig) error
UpdateManagedGroupConfig(config model.ManagedGroupConfig) error
DeleteManagedGroupConfig(id string, clientID string) error
}

type storageListenerImpl struct {
app *Application
}

func (a *storageListenerImpl) OnConfigsChanged() {
func (a *storageListenerImpl) OnManagedGroupConfigsChanged() {
//do nothing for now
}

Expand All @@ -320,7 +350,7 @@ func (n *notificationsImpl) SendNotification(recipients []notifications.Recipien
type Authman interface {
RetrieveAuthmanGroupMembers(groupName string) ([]string, error)
RetrieveAuthmanUsers(externalIDs []string) (map[string]model.AuthmanSubject, error)
RetrieveAuthmanGiesGroups(stemName string) (*model.АuthmanGroupsResponse, error)
RetrieveAuthmanStemGroups(stemName string) (*model.АuthmanGroupsResponse, error)
AddAuthmanMemberToGroup(groupName string, uin string) error
RemoveAuthmanMemberFromGroup(groupName string, uin string) error
}
Expand Down
4 changes: 2 additions & 2 deletions core/model/authman.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ func (a *AuthmanGroupEntry) HasDescription() bool {
return a.Description != ""
}

// GetGroupPettyTitleAndAdmins Gets the group pretty name and and group admin UINs
func (a *AuthmanGroupEntry) GetGroupPettyTitleAndAdmins() (string, []string) {
// GetGroupPrettyTitleAndAdmins Gets the group pretty name and and group admin UINs
func (a *AuthmanGroupEntry) GetGroupPrettyTitleAndAdmins() (string, []string) {
if strings.Contains(a.Description, "|") {
var first string
var adminUINs []string
Expand Down
15 changes: 15 additions & 0 deletions core/model/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,23 @@

package model

import "time"

// Config wrapper for in memory storage of configuration
type Config struct {
AuthmanAdminUINList []string
ReportAbuseRecipientEmail string
SyncManagedGroupsPeriod int //Period at which to automatically sync managed groups in minutes
SupportedClientIDs []string
}

// ManagedGroupConfig defines a configs for a set of managed groups
type ManagedGroupConfig struct {
ID string `json:"id" bson:"_id"`
ClientID string `json:"client_id" bson:"client_id"`
AuthmanStems []string `json:"authman_stems" bson:"authman_stems"`
AdminUINs []string `json:"admin_uins" bson:"admin_uins"`
Type string `json:"type" bson:"type"`
DateCreated time.Time `json:"date_created" bson:"date_created"`
DateUpdated *time.Time `json:"date_updated" bson:"date_updated"`
} //@name ManagedGroupConfig
Loading