Skip to content

Commit

Permalink
[#477] Add default assigners permission (#537)
Browse files Browse the repository at this point in the history
* add default assigner permission, insert on startup [#477]

* add descriptions, use insert many for required permissions [#477]

* update changelog [#477]

* always send grant_all_permissions as assigner in permission response [#477]

Co-authored-by: Stephen Hurwit <[email protected]>
  • Loading branch information
roberlander2 and shurwit authored Aug 26, 2022
1 parent 418b609 commit 082fbd0
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Use signature Key ID to check specific key for service account auth [#481](https://github.com/rokwire/core-building-block/issues/481)
- Include account ID in request logs [#562](https://github.com/rokwire/core-building-block/issues/562)
- Add system flag to login response [#552](https://github.com/rokwire/core-building-block/issues/552)
- Add default assigners permission [#477](https://github.com/rokwire/core-building-block/issues/477)

### Fixed
- Service registration error handling change [#468](https://github.com/rokwire/core-building-block/issues/468)
Expand All @@ -19,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Allow passing nil context to WithContext storage functions [#494](https://github.com/rokwire/core-building-block/issues/494)
- Account system configs [#558](https://github.com/rokwire/core-building-block/issues/558)

### Fixed
- Authorization policy comments not working [#506](https://github.com/rokwire/core-building-block/issues/506)

Expand Down
82 changes: 55 additions & 27 deletions core/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (c *APIs) GetVersion() string {
}

func (c *APIs) storeSystemData() error {
documentIDs := make(map[string]string)
newDocuments := make(map[string]string)

transaction := func(context storage.TransactionContext) error {
createAccount := false
Expand All @@ -81,8 +81,8 @@ func (c *APIs) storeSystemData() error {
return errors.WrapErrorAction(logutils.ActionFind, model.TypeAuthType, nil, err)
}
if emailAuthType == nil {
documentIDs["auth_type"] = uuid.NewString()
emailAuthType = &model.AuthType{ID: documentIDs["auth_type"], Code: auth.AuthTypeEmail, Description: "Authentication type relying on email and password",
newDocuments["auth_type"] = uuid.NewString()
emailAuthType = &model.AuthType{ID: newDocuments["auth_type"], Code: auth.AuthTypeEmail, Description: "Authentication type relying on email and password",
IsExternal: false, IsAnonymous: false, UseCredentials: true, IgnoreMFA: false}
_, err = c.app.storage.InsertAuthType(context, *emailAuthType)
if err != nil {
Expand All @@ -96,9 +96,9 @@ func (c *APIs) storeSystemData() error {
return errors.WrapErrorAction(logutils.ActionFind, model.TypeOrganization, nil, err)
}
if systemOrg == nil {
documentIDs["organization"] = uuid.NewString()
newDocuments["organization"] = uuid.NewString()
systemOrgConfig := model.OrganizationConfig{ID: uuid.NewString(), DateCreated: time.Now().UTC()}
newSystemOrg := model.Organization{ID: documentIDs["organization"], Name: "System", Type: "small", System: true, Config: systemOrgConfig, DateCreated: time.Now().UTC()}
newSystemOrg := model.Organization{ID: newDocuments["organization"], Name: "System", Type: "small", System: true, Config: systemOrgConfig, DateCreated: time.Now().UTC()}
_, err = c.app.storage.InsertOrganization(context, newSystemOrg)
if err != nil {
return errors.WrapErrorAction(logutils.ActionInsert, model.TypeOrganization, nil, err)
Expand All @@ -118,9 +118,9 @@ func (c *APIs) storeSystemData() error {
if c.systemAppTypeIdentifier == "" || c.systemAppTypeName == "" {
return errors.ErrorData(logutils.StatusMissing, "initial system app type identifier or name", nil)
}
documentIDs["application"] = uuid.NewString()
newDocuments["application"] = uuid.NewString()
newAndroidAppType := model.ApplicationType{ID: uuid.NewString(), Identifier: c.systemAppTypeIdentifier, Name: c.systemAppTypeName, Versions: nil}
newSystemAdminApp := model.Application{ID: documentIDs["application"], Name: "System Admin application", MultiTenant: false, Admin: true,
newSystemAdminApp := model.Application{ID: newDocuments["application"], Name: "System Admin application", MultiTenant: false, Admin: true,
SharedIdentities: false, Types: []model.ApplicationType{newAndroidAppType}, DateCreated: time.Now().UTC()}
_, err = c.app.storage.InsertApplication(context, newSystemAdminApp)
if err != nil {
Expand All @@ -141,8 +141,8 @@ func (c *APIs) storeSystemData() error {
supportedAuthTypes[i] = model.AuthTypesSupport{AppTypeID: appType.ID, SupportedAuthTypes: emailSupport}
}

documentIDs["application_organization"] = uuid.NewString()
newSystemAdminAppOrg := model.ApplicationOrganization{ID: documentIDs["application_organization"], Application: *systemAdminApp, Organization: *systemOrg,
newDocuments["application_organization"] = uuid.NewString()
newSystemAdminAppOrg := model.ApplicationOrganization{ID: newDocuments["application_organization"], Application: *systemAdminApp, Organization: *systemOrg,
SupportedAuthTypes: supportedAuthTypes, DateCreated: time.Now().UTC()}
_, err = c.app.storage.InsertApplicationOrganization(context, newSystemAdminAppOrg)
if err != nil {
Expand All @@ -165,39 +165,65 @@ func (c *APIs) storeSystemData() error {
if c.systemAPIKey == "" {
return errors.ErrorData(logutils.StatusMissing, "initial system api key", nil)
}
documentIDs["api_key"] = uuid.NewString()
newAPIKey := model.APIKey{ID: documentIDs["api_key"], AppID: systemAppOrg.Application.ID, Key: c.systemAPIKey}
newDocuments["api_key"] = uuid.NewString()
newAPIKey := model.APIKey{ID: newDocuments["api_key"], AppID: systemAppOrg.Application.ID, Key: c.systemAPIKey}
_, err := c.app.storage.InsertAPIKey(context, newAPIKey)
if err != nil {
return errors.WrapErrorAction(logutils.ActionInsert, model.TypeAPIKey, nil, err)
}
}

//5. insert all_system_core permission if does not exist
systemPermissions := []string{model.PermissionAllSystemCore}
allSystemPermissions, err := c.app.storage.FindPermissionsByName(context, systemPermissions)
//5. insert all_system_core permission and grant_all_permissions permission if they do not exist
requiredPermissions := map[string]string{
model.PermissionAllSystemCore: "Gives access to all admin and system APIs",
model.PermissionGrantAllPermissions: "Gives the ability to grant any permission",
}
existingPermissions, err := c.app.storage.FindPermissionsByName(context, []string{model.PermissionAllSystemCore, model.PermissionGrantAllPermissions})
if err != nil {
return errors.WrapErrorAction(logutils.ActionFind, model.TypePermission, &logutils.FieldArgs{"name": model.PermissionAllSystemCore}, err)
}

if len(allSystemPermissions) == 0 {
documentIDs["permission"] = uuid.NewString()
allSystemCore := model.Permission{ID: documentIDs["permission"], Name: model.PermissionAllSystemCore, ServiceID: "core",
Assigners: systemPermissions, DateCreated: time.Now().UTC()}
err = c.app.storage.InsertPermission(context, allSystemCore)
if err != nil {
return errors.WrapErrorAction(logutils.ActionInsert, model.TypePermission, nil, err)
if len(existingPermissions) < len(requiredPermissions) {
insert := []model.Permission{}
for name, desc := range requiredPermissions {
found := false
for _, existing := range existingPermissions {
if existing.Name == name {
found = true
continue
}
}
if !found {
newPermission := model.Permission{ID: uuid.NewString(), Name: name, Description: desc, ServiceID: "core",
Assigners: []string{model.PermissionAllSystemCore}, DateCreated: time.Now().UTC()}
insert = append(insert, newPermission)
}
}

allSystemPermissions = append(allSystemPermissions, allSystemCore)
if len(insert) > 0 {
names := ""
for _, p := range insert {
if len(names) > 0 {
names += ","
}
names += p.Name
}

err = c.app.storage.InsertPermissions(context, insert)
if err != nil {
return errors.WrapErrorAction(logutils.ActionCreate, model.TypePermission, logutils.StringArgs(names), err)
}

newDocuments["permissions"] = names
}
}

//6. insert system account if needed
if createAccount {
if c.systemAccountEmail == "" || c.systemAccountPassword == "" {
return errors.ErrorData(logutils.StatusMissing, "initial system account email or password", nil)
}
documentIDs["account"], err = c.Auth.InitializeSystemAccount(context, *emailAuthType, systemAppOrg, model.PermissionAllSystemCore, c.systemAccountEmail, c.systemAccountPassword, c.logger.NewRequestLog(nil))
newDocuments["account"], err = c.Auth.InitializeSystemAccount(context, *emailAuthType, systemAppOrg, model.PermissionAllSystemCore, c.systemAccountEmail, c.systemAccountPassword, c.logger.NewRequestLog(nil))
if err != nil {
return errors.WrapErrorAction(logutils.ActionInitialize, "system account", nil, err)
}
Expand All @@ -208,12 +234,14 @@ func (c *APIs) storeSystemData() error {

err := c.app.storage.PerformTransaction(transaction)
if err == nil {
for doc, id := range documentIDs {
fields := logutils.Fields{"id": id}
for doc, data := range newDocuments {
key := "id"
if doc == "permissions" {
key = "names"
}
fields := logutils.Fields{key: data}
if doc == "auth_type" {
fields["code"] = auth.AuthTypeEmail
} else if doc == "permission" {
fields["name"] = model.PermissionAllSystemCore
}
c.logger.InfoWithFields(fmt.Sprintf("new system %s created", doc), fields)
}
Expand Down
1 change: 1 addition & 0 deletions core/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ type Storage interface {
FindPermissionsByName(context storage.TransactionContext, names []string) ([]model.Permission, error)
FindPermissionsByServiceIDs(serviceIDs []string) ([]model.Permission, error)
InsertPermission(context storage.TransactionContext, item model.Permission) error
InsertPermissions(context storage.TransactionContext, items []model.Permission) error
UpdatePermission(item model.Permission) error
DeletePermission(id string) error

Expand Down
14 changes: 14 additions & 0 deletions core/mocks/Storage.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions core/model/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ const (

//PermissionAllSystemCore ...
PermissionAllSystemCore string = "all_system_core"
//PermissionGrantAllPermissions ...
PermissionGrantAllPermissions string = "grant_all_permissions"
)

// Permission represents permission entity
Expand All @@ -70,6 +72,9 @@ type Permission struct {

// CheckAssigners checks if the passed permissions satisfy the needed assigners for the permission
func (p Permission) CheckAssigners(assignerPermissions []string) error {
if authutils.ContainsString(assignerPermissions, PermissionGrantAllPermissions) {
return nil
}
if len(p.Assigners) == 0 {
return errors.Newf("not defined assigners for %s permission", p.Name)
}
Expand Down Expand Up @@ -116,6 +121,9 @@ func (c AppOrgRole) GetPermissionNamed(name string) *Permission {

// CheckAssigners checks if the passed permissions satisfy the needed assigners for all role permissions
func (c AppOrgRole) CheckAssigners(assignerPermissions []string) error {
if authutils.ContainsString(assignerPermissions, PermissionGrantAllPermissions) {
return nil
}
if len(c.Permissions) == 0 {
return nil //no permission
}
Expand Down Expand Up @@ -153,6 +161,10 @@ type AppOrgGroup struct {

// CheckAssigners checks if the passed permissions satisfy the needed assigners for the group
func (cg AppOrgGroup) CheckAssigners(assignerPermissions []string) error {
if authutils.ContainsString(assignerPermissions, PermissionGrantAllPermissions) {
return nil
}

//check permission
if len(cg.Permissions) > 0 {
for _, permission := range cg.Permissions {
Expand Down
32 changes: 28 additions & 4 deletions driven/storage/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2218,12 +2218,36 @@ func (sa *Adapter) FindPermissionsByName(context TransactionContext, names []str
return permissionsResult, nil
}

// InsertPermission inserts a new permission
func (sa *Adapter) InsertPermission(context TransactionContext, permission model.Permission) error {
_, err := sa.db.permissions.InsertOneWithContext(context, permission)
// InsertPermission inserts a new permission
func (sa *Adapter) InsertPermission(context TransactionContext, item model.Permission) error {
_, err := sa.db.permissions.InsertOneWithContext(context, item)
if err != nil {
return errors.WrapErrorAction(logutils.ActionInsert, model.TypePermission, &logutils.FieldArgs{"_id": permission.ID, "name": permission.Name}, err)
return errors.WrapErrorAction(logutils.ActionInsert, model.TypePermission, &logutils.FieldArgs{"_id": item.ID, "name": item.Name}, err)
}

return nil
}

// InsertPermissions inserts permissions
func (sa *Adapter) InsertPermissions(context TransactionContext, items []model.Permission) error {
if len(items) == 0 {
return nil
}

stgPermissions := make([]interface{}, len(items))
for i, p := range items {
stgPermissions[i] = p
}

res, err := sa.db.permissions.InsertManyWithContext(context, stgPermissions, nil)
if err != nil {
return errors.WrapErrorAction(logutils.ActionInsert, model.TypePermission, nil, err)
}

if len(res.InsertedIDs) != len(items) {
return errors.ErrorAction(logutils.ActionInsert, model.TypePermission, &logutils.FieldArgs{"inserted": len(res.InsertedIDs), "expected": len(items)})
}

return nil
}

Expand Down
1 change: 1 addition & 0 deletions driver/web/conversions_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func applicationPermissionToDef(item model.Permission) Def.Permission {
if assigners == nil {
assigners = make([]string, 0)
}
assigners = append(assigners, model.PermissionGrantAllPermissions)

//dates
var dateUpdated *string
Expand Down

0 comments on commit 082fbd0

Please sign in to comment.