mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
renamed package to authz, inmplemented reviewer's feedback
This commit is contained in:
parent
a8b198af99
commit
48913caafd
5 changed files with 128 additions and 105 deletions
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue