renamed package to authz, inmplemented reviewer's feedback

This commit is contained in:
Souhaila Noor 2021-12-15 13:35:30 -06:00
parent a8b198af99
commit 48913caafd
5 changed files with 128 additions and 105 deletions

View file

@ -1,11 +1,23 @@
// Copyright 2021 Molecula Corp. All rights reserved.
package auth
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package authz
import (
"fmt"
"io"
"io/ioutil"
"log"
"path/filepath"
"gopkg.in/yaml.v2"
)
@ -46,48 +58,39 @@ type Permissions struct {
Permission string `yaml:"permission"`
}
func ReadPermissionsFile(filePath string) (yamlData []byte) {
filePathAbs, _ := filepath.Abs(filePath)
yamlData, err := ioutil.ReadFile(filePathAbs)
type Group struct {
ID string `json:"id"`
Name string `json:"displayName"`
}
func (p *GroupPermissions) ReadPermissionsFile(permsFile io.Reader) (err error) {
permsData, err := ioutil.ReadAll(permsFile)
if err != nil {
panic(err)
return fmt.Errorf("reading permissions failed with error: %s", err)
}
return yamlData
}
func (p *GroupPermissions) CreatePermissionsStruct(data []byte) {
err := yaml.Unmarshal([]byte(data), p)
err = yaml.Unmarshal(permsData, p)
if err != nil {
log.Fatalf("error %s", err)
return fmt.Errorf("unmarshalling permissions failed with error: %s", err)
}
return nil
}
func GetPermissions(Auth *Auth, groups []map[string]string, index []string) (permission string, err error) {
// read yaml permissions file
yamlData := ReadPermissionsFile(Auth.PermissionsFile)
// get group permissions
var p GroupPermissions
p.CreatePermissionsStruct(yamlData)
// check permissions for all groups and index, and return most permissive
return p.ResolvePermissions(groups, index)
}
func (p *GroupPermissions) ResolvePermissions(groups []map[string]string, index []string) (permission string, err error) {
func (p *GroupPermissions) GetPermissions(groups []Group, index []string) (permission string, err error) {
// get union of groups the user is part of obtained from identity provider and groups in permissions file
var groupMatch []Permissions
for _, group := range groups {
for i := range p.Permissions {
if group["id"] == p.Permissions[i].GroupId {
if group.ID == p.Permissions[i].GroupId {
groupMatch = append(groupMatch, p.Permissions[i])
}
}
}
if len(groupMatch) == 0 {
return "", fmt.Errorf("user is NOT allowed access to FeatureBase")
return "", fmt.Errorf("the user's groups %s are NOT allowed access to FeatureBase", groups)
}
// check that user's groups have access to the index user want to access
@ -110,7 +113,7 @@ func (p *GroupPermissions) ResolvePermissions(groups []map[string]string, index
indexNotFound = append(indexNotFound, idx)
}
}
return "", fmt.Errorf("user is not allowed access to index: %s", indexNotFound)
return "", fmt.Errorf("user is NOT allowed access to index: %s", indexNotFound)
}
// check permissions for index user has access to

View file

@ -11,7 +11,7 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth_test
package authz_test
import (
"fmt"
@ -19,23 +19,23 @@ import (
"strings"
"testing"
"github.com/molecula/featurebase/v2/auth"
"github.com/molecula/featurebase/v2/authz"
)
func TestAuth_CreatePermissionsStruct(t *testing.T) {
var singleInput = []byte(`group_permissions:
func TestAuth_ReadPermissionsFile(t *testing.T) {
var singleInput = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee55906b"
index: "test"
permission: "read"`)
permission: "read"`
var emptyInput = []byte(`group_permissions:
var emptyInput = `group_permissions:
- group:
groupId: ""
index: ""
permission: ""`)
permission: ""`
var multiInput = []byte(`group_permissions:
var multiInput = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee55906b"
index: "test"
@ -43,28 +43,28 @@ func TestAuth_CreatePermissionsStruct(t *testing.T) {
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
permission: "admin"`)
permission: "admin"`
singleStruct := auth.GroupPermissions{
Permissions: []auth.Permissions{
singleStruct := authz.GroupPermissions{
Permissions: []authz.Permissions{
{"dca35310-ecda-4f23-86cd-876aee55906b", "test", "read"},
},
}
emptyStruct := auth.GroupPermissions{
Permissions: []auth.Permissions{
emptyStruct := authz.GroupPermissions{
Permissions: []authz.Permissions{
{"", "", ""},
},
}
multiStruct := auth.GroupPermissions{
Permissions: []auth.Permissions{
multiStruct := authz.GroupPermissions{
Permissions: []authz.Permissions{
{"dca35310-ecda-4f23-86cd-876aee55906b", "test", "read"},
{"dca35310-ecda-4f23-86cd-876aee559900", "test", "admin"},
},
}
tests := []struct {
input []byte
output auth.GroupPermissions
input string
output authz.GroupPermissions
}{
{singleInput, singleStruct},
{emptyInput, emptyStruct},
@ -73,8 +73,11 @@ func TestAuth_CreatePermissionsStruct(t *testing.T) {
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
var p auth.GroupPermissions
p.CreatePermissionsStruct(test.input)
permFile := strings.NewReader(test.input)
var p authz.GroupPermissions
if err := p.ReadPermissionsFile(permFile); err != nil {
t.Fatalf("readPermissionsFile error: %s", err)
}
if !reflect.DeepEqual(p, test.output) {
t.Fatalf("expected output %s, but got %s", test.output, p)
@ -84,26 +87,15 @@ func TestAuth_CreatePermissionsStruct(t *testing.T) {
}
}
func createGroupMaps(groups []string) []map[string]string {
var group1 []map[string]string
for _, i := range groups {
map1 := map[string]string{}
map1["id"] = i
group1 = append(group1, map1)
}
return group1
}
func TestAuth_ResolvePermissions(t *testing.T) {
// initializes different example of permissions file in yaml
var permissions1 = []byte(`group_permissions:
var permissions1 = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee55906b"
index: "test"
permission: "read"`)
permission: "read"`
var permissions2 = []byte(`group_permissions:
var permissions2 = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
@ -111,9 +103,9 @@ func TestAuth_ResolvePermissions(t *testing.T) {
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
permission: "write"`)
permission: "write"`
var permissions3 = []byte(`group_permissions:
var permissions3 = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
@ -121,9 +113,9 @@ func TestAuth_ResolvePermissions(t *testing.T) {
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
permission: "admin"`)
permission: "admin"`
var permissions4 = []byte(`group_permissions:
var permissions4 = `group_permissions:
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee55906b"
index: "test"
@ -131,65 +123,68 @@ func TestAuth_ResolvePermissions(t *testing.T) {
- group:
groupId: "dca35310-ecda-4f23-86cd-876aee559900"
index: "test"
permission: "admin"`)
permission: "admin"`
// initializes groups that are returned from identity provider
groupsList1 := []string{}
groupsList2 := []string{"dca35310-ecda-4f23-86cd-876aee55906b"}
groupsList3 := []string{"dca35310-ecda-4f23-86cd-876aee55906b", "dca35310-ecda-4f23-86cd-876aee559900"}
groupsList1 := []authz.Group{}
groupsList2 := []authz.Group{{"dca35310-ecda-4f23-86cd-876aee55906b", "name"}}
groupsList3 := []authz.Group{
{"dca35310-ecda-4f23-86cd-876aee55906b", "name"},
{"dca35310-ecda-4f23-86cd-876aee559900", "name"},
}
tests := []struct {
permissions []byte
groups []map[string]string
index []string
userAccess string
err string
yamlData string
groups []authz.Group
index []string
userAccess string
err string
}{
{
permissions1,
createGroupMaps(groupsList1),
groupsList1,
[]string{"test"},
"",
"user is NOT allowed access to FeatureBase",
"NOT allowed access to FeatureBase",
},
{
permissions1,
createGroupMaps(groupsList2),
groupsList2,
[]string{"test1"},
"",
"user is not allowed access to index",
"NOT allowed access to index",
},
{
permissions1,
createGroupMaps(groupsList2),
groupsList2,
[]string{"test"},
"read",
"",
},
{
permissions2,
createGroupMaps(groupsList3),
groupsList3,
[]string{"test"},
"write",
"",
},
{
permissions3,
createGroupMaps(groupsList3),
groupsList3,
[]string{"test"},
"admin",
"",
},
{
permissions2,
createGroupMaps(groupsList3),
groupsList3,
[]string{"test"},
"write",
"",
},
{
permissions4,
createGroupMaps(groupsList2),
groupsList2,
[]string{"test"},
"",
"no permissions found",
@ -199,10 +194,11 @@ func TestAuth_ResolvePermissions(t *testing.T) {
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
var p auth.GroupPermissions
p.CreatePermissionsStruct(test.permissions)
permFile := strings.NewReader(test.yamlData)
var p authz.GroupPermissions
p.ReadPermissionsFile(permFile)
p1, err := p.ResolvePermissions(test.groups, test.index)
p1, err := p.GetPermissions(test.groups, test.index)
if p1 != test.userAccess {
t.Errorf("expected permission to be %s, but got %s", test.userAccess, p1)

View file

@ -7,13 +7,14 @@ import (
"log"
"net"
"net/url"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
"github.com/molecula/featurebase/v2/auth"
"github.com/molecula/featurebase/v2/authz"
petcd "github.com/molecula/featurebase/v2/etcd"
rbfcfg "github.com/molecula/featurebase/v2/rbf/cfg"
"github.com/molecula/featurebase/v2/storage"
@ -232,7 +233,7 @@ type Config struct {
SchemaDetailsOn bool `toml:"schema-details-on"`
// Enable AuthZ/AuthN
Auth auth.Auth `toml:"auth"`
Auth authz.Auth `toml:"auth"`
}
// Namespace returns the namespace to use based on the Future flag.
@ -642,13 +643,22 @@ func (c *Config) ValidateAuth() ([]error, error) {
}
func (c *Config) ValidatePermissions() (err error) {
permsFile, err := os.Open(c.Auth.PermissionsFile)
if err != nil {
return err
}
var p *authz.GroupPermissions
if err := p.ReadPermissionsFile(permsFile); err != nil {
return err
}
yamlData := auth.ReadPermissionsFile(c.Auth.PermissionsFile)
var p auth.GroupPermissions
p.CreatePermissionsStruct(yamlData)
if len(p.Permissions) == 0 {
return fmt.Errorf("no group permissions found in permissions file: %s", c.Auth.PermissionsFile)
}
defer permsFile.Close()
return nil
}

View file

@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/molecula/featurebase/v2/auth"
"github.com/molecula/featurebase/v2/authz"
)
type addrs struct{ bind, advertise string }
@ -294,7 +294,7 @@ func TestConfig_validateAuth(t *testing.T) {
tests := []struct {
expErrs []string
input auth.Auth
input authz.Auth
}{
{
@ -308,7 +308,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: emptyString,
ClientSecret: emptyString,
@ -329,7 +329,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: emptyString,
@ -350,7 +350,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: emptyString,
ClientSecret: validClientSecret,
@ -370,7 +370,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -389,7 +389,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -407,7 +407,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgEmpty,
errorMesgEmpty,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -423,7 +423,7 @@ func TestConfig_validateAuth(t *testing.T) {
[]string{
errorMesgURL,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -440,7 +440,7 @@ func TestConfig_validateAuth(t *testing.T) {
errorMesgURL,
errorMesgURL,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -456,7 +456,7 @@ func TestConfig_validateAuth(t *testing.T) {
[]string{
errorMesgPermissions,
},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -470,7 +470,7 @@ func TestConfig_validateAuth(t *testing.T) {
{
// Auth enabled, all configs are set properly
[]string{},
auth.Auth{
authz.Auth{
Enable: enable,
ClientId: validClientID,
ClientSecret: validClientSecret,
@ -484,7 +484,7 @@ func TestConfig_validateAuth(t *testing.T) {
{
// Auth disabled, all configs are set to empty string
[]string{},
auth.Auth{
authz.Auth{
Enable: disable,
ClientId: emptyString,
ClientSecret: emptyString,

View file

@ -29,6 +29,7 @@ import (
"golang.org/x/sync/errgroup"
pilosa "github.com/molecula/featurebase/v2"
"github.com/molecula/featurebase/v2/authz"
"github.com/molecula/featurebase/v2/boltdb"
"github.com/molecula/featurebase/v2/encoding/proto"
petcd "github.com/molecula/featurebase/v2/etcd"
@ -224,6 +225,19 @@ func (m *Command) Start() (err error) {
if m.Config.Auth.Enable {
m.Config.MustValidateAuth()
// Read permissions file
permsFile, err := os.Open(m.Config.Auth.PermissionsFile)
if err != nil {
return err
}
var p authz.GroupPermissions
if err := p.ReadPermissionsFile(permsFile); err != nil {
return err
}
defer permsFile.Close()
}
// Initialize server.