This commit is contained in:
Mathieu Leplatre 2017-10-04 13:35:48 +02:00
Родитель 3c2cf1bd77
Коммит fbaee2e235
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 767B105F81A15CDD
7 изменённых файлов: 57 добавлений и 57 удалений

Просмотреть файл

@ -2,8 +2,8 @@ GO_LINT := $(GOPATH)/bin/golint
GO_GLIDE := $(GOPATH)/bin/glide GO_GLIDE := $(GOPATH)/bin/glide
GO_BINDATA := $(GOPATH)/bin/go-bindata GO_BINDATA := $(GOPATH)/bin/go-bindata
DATA_FILES := ./utilities/openapi.yaml ./utilities/contribute.yaml DATA_FILES := ./utilities/openapi.yaml ./utilities/contribute.yaml
SRC := *.go ./utilities/*.go ./warden/*.go SRC := *.go ./utilities/*.go ./doorman/*.go
PACKAGES := ./ ./utilities/ ./warden/ PACKAGES := ./ ./utilities/ ./doorman/
main: vendor utilities/bindata.go $(SRC) main: vendor utilities/bindata.go $(SRC)
CGO_ENABLED=0 go build -o main *.go CGO_ENABLED=0 go build -o main *.go

Просмотреть файл

@ -1,4 +1,4 @@
package warden package doorman
import ( import (
"encoding/json" "encoding/json"
@ -20,30 +20,30 @@ import (
// DefaultPoliciesFilename is the default policies filename. // DefaultPoliciesFilename is the default policies filename.
const DefaultPoliciesFilename string = "policies.yaml" const DefaultPoliciesFilename string = "policies.yaml"
// ContextKey is the Gin context key to obtain the *Warden instance. // ContextKey is the Gin context key to obtain the *Doorman instance.
const ContextKey string = "warden" const ContextKey string = "doorman"
const maxInt int64 = 1<<63 - 1 const maxInt int64 = 1<<63 - 1
// Config contains the settings of the warden. // Config contains the settings of the doorman.
type Config struct { type Config struct {
PoliciesFilename string PoliciesFilename string
JWTIssuer string JWTIssuer string
} }
// Warden is the backend in charge of checking requests against policies. // Doorman is the backend in charge of checking requests against policies.
type Warden struct { type Doorman struct {
l ladon.Ladon l ladon.Ladon
Manager ladon.Manager Manager ladon.Manager
Config *Config Config *Config
} }
// New instantiates a new warden. // New instantiates a new doorman.
func New(config *Config) *Warden { func New(config *Config) *Doorman {
l := ladon.Ladon{ l := ladon.Ladon{
Manager: manager.NewMemoryManager(), Manager: manager.NewMemoryManager(),
} }
w := &Warden{l, l.Manager, config} w := &Doorman{l, l.Manager, config}
if err := w.LoadPolicies(config.PoliciesFilename); err != nil { if err := w.LoadPolicies(config.PoliciesFilename); err != nil {
log.Fatal(err.Error()) log.Fatal(err.Error())
} }
@ -51,12 +51,12 @@ func New(config *Config) *Warden {
} }
// IsAllowed is responsible for deciding if subject can perform action on a resource with a context. // IsAllowed is responsible for deciding if subject can perform action on a resource with a context.
func (warden *Warden) IsAllowed(request *ladon.Request) error { func (doorman *Doorman) IsAllowed(request *ladon.Request) error {
return warden.l.IsAllowed(request) return doorman.l.IsAllowed(request)
} }
// LoadPolicies reads policies from the YAML file. // LoadPolicies reads policies from the YAML file.
func (warden *Warden) LoadPolicies(filename string) error { func (doorman *Doorman) LoadPolicies(filename string) error {
// If not specified, read it from ENV or read local `.policies.yaml` // If not specified, read it from ENV or read local `.policies.yaml`
if filename == "" { if filename == "" {
filename = os.Getenv("POLICIES_FILE") filename = os.Getenv("POLICIES_FILE")
@ -95,19 +95,19 @@ func (warden *Warden) LoadPolicies(filename string) error {
} }
// Clear every existing policy, and load new ones. // Clear every existing policy, and load new ones.
existing, err := warden.Manager.GetAll(0, maxInt) existing, err := doorman.Manager.GetAll(0, maxInt)
if err != nil { if err != nil {
return err return err
} }
for _, pol := range existing { for _, pol := range existing {
err := warden.Manager.Delete(pol.GetID()) err := doorman.Manager.Delete(pol.GetID())
if err != nil { if err != nil {
return err return err
} }
} }
for _, pol := range policies { for _, pol := range policies {
log.Info("Load policy ", pol.GetID()+": ", pol.GetDescription()) log.Info("Load policy ", pol.GetID()+": ", pol.GetDescription())
err := warden.Manager.Create(pol) err := doorman.Manager.Create(pol)
if err != nil { if err != nil {
return err return err
} }
@ -116,19 +116,19 @@ func (warden *Warden) LoadPolicies(filename string) error {
return nil return nil
} }
// ContextMiddleware adds the Warden instance to the Gin context. // ContextMiddleware adds the Doorman instance to the Gin context.
func ContextMiddleware(warden *Warden) gin.HandlerFunc { func ContextMiddleware(doorman *Doorman) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
c.Set(ContextKey, warden) c.Set(ContextKey, doorman)
c.Next() c.Next()
} }
} }
// SetupRoutes adds warden views to query the policies. // SetupRoutes adds doorman views to query the policies.
func SetupRoutes(r *gin.Engine, warden *Warden) { func SetupRoutes(r *gin.Engine, doorman *Doorman) {
r.Use(ContextMiddleware(warden)) r.Use(ContextMiddleware(doorman))
if warden.Config.JWTIssuer != "" { if doorman.Config.JWTIssuer != "" {
r.Use(VerifyJWTMiddleware(warden.Config.JWTIssuer)) r.Use(VerifyJWTMiddleware(doorman.Config.JWTIssuer))
} }
r.POST("/allowed", allowedHandler) r.POST("/allowed", allowedHandler)
} }
@ -156,13 +156,13 @@ func allowedHandler(c *gin.Context) {
accessRequest.Subject = payloadJWT.(*jwt.Claims).Subject accessRequest.Subject = payloadJWT.(*jwt.Claims).Subject
} }
warden := c.MustGet(ContextKey).(*Warden) doorman := c.MustGet(ContextKey).(*Doorman)
err := warden.IsAllowed(&accessRequest) err := doorman.IsAllowed(&accessRequest)
allowed := (err == nil) allowed := (err == nil)
// Show some debug information about matched policy. // Show some debug information about matched policy.
if allowed && gin.Mode() != gin.ReleaseMode { if allowed && gin.Mode() != gin.ReleaseMode {
policies, _ := warden.Manager.FindRequestCandidates(&accessRequest) policies, _ := doorman.Manager.FindRequestCandidates(&accessRequest)
matched := policies[0] matched := policies[0]
log.Debug("Policy matched ", matched.GetID()+": ", matched.GetDescription()) log.Debug("Policy matched ", matched.GetID()+": ", matched.GetDescription())
} }

Просмотреть файл

@ -1,4 +1,4 @@
package warden package doorman
import ( import (
"bytes" "bytes"
@ -38,28 +38,28 @@ func TestMain(m *testing.M) {
os.Exit(m.Run()) os.Exit(m.Run())
} }
func loadTempFile(warden *Warden, content []byte) error { func loadTempFile(doorman *Doorman, content []byte) error {
tmpfile, _ := ioutil.TempFile("", "") tmpfile, _ := ioutil.TempFile("", "")
defer os.Remove(tmpfile.Name()) // clean up defer os.Remove(tmpfile.Name()) // clean up
tmpfile.Write(content) tmpfile.Write(content)
tmpfile.Close() tmpfile.Close()
return warden.LoadPolicies(tmpfile.Name()) return doorman.LoadPolicies(tmpfile.Name())
} }
func TestLoadPolicies(t *testing.T) { func TestLoadPolicies(t *testing.T) {
warden := New(&Config{"../policies.yaml", ""}) doorman := New(&Config{"../policies.yaml", ""})
// Missing file // Missing file
var err error var err error
err = warden.LoadPolicies("/tmp/unknown.yaml") err = doorman.LoadPolicies("/tmp/unknown.yaml")
assert.NotNil(t, err) assert.NotNil(t, err)
// Bad YAML // Bad YAML
err = loadTempFile(warden, []byte("$\\--xx")) err = loadTempFile(doorman, []byte("$\\--xx"))
assert.NotNil(t, err) assert.NotNil(t, err)
// Bad policies // Bad policies
err = loadTempFile(warden, []byte(` err = loadTempFile(doorman, []byte(`
- -
id: "1" id: "1"
conditions: conditions:
@ -69,7 +69,7 @@ func TestLoadPolicies(t *testing.T) {
assert.NotNil(t, err) assert.NotNil(t, err)
// Duplicated ID // Duplicated ID
err = loadTempFile(warden, []byte(` err = loadTempFile(doorman, []byte(`
- -
id: "1" id: "1"
effect: allow effect: allow
@ -95,7 +95,7 @@ func performAllowed(t *testing.T, r *gin.Engine, body io.Reader, expected int, r
require.Nil(t, err) require.Nil(t, err)
} }
func TestWardenGet(t *testing.T) { func TestDoormanGet(t *testing.T) {
r := gin.New() r := gin.New()
SetupRoutes(r, New(&defaultConfig)) SetupRoutes(r, New(&defaultConfig))
@ -103,7 +103,7 @@ func TestWardenGet(t *testing.T) {
assert.Equal(t, w.Code, http.StatusNotFound) assert.Equal(t, w.Code, http.StatusNotFound)
} }
func TestWardenEmpty(t *testing.T) { func TestDoormanEmpty(t *testing.T) {
r := gin.New() r := gin.New()
SetupRoutes(r, New(&defaultConfig)) SetupRoutes(r, New(&defaultConfig))
@ -112,7 +112,7 @@ func TestWardenEmpty(t *testing.T) {
assert.Equal(t, response.Message, "Missing body") assert.Equal(t, response.Message, "Missing body")
} }
func TestWardenInvalidJSON(t *testing.T) { func TestDoormanInvalidJSON(t *testing.T) {
r := gin.New() r := gin.New()
SetupRoutes(r, New(&defaultConfig)) SetupRoutes(r, New(&defaultConfig))
@ -122,11 +122,11 @@ func TestWardenInvalidJSON(t *testing.T) {
assert.Contains(t, response.Message, "invalid character ';'") assert.Contains(t, response.Message, "invalid character ';'")
} }
func TestWardenAllowed(t *testing.T) { func TestDoormanAllowed(t *testing.T) {
r := gin.New() r := gin.New()
warden := New(&defaultConfig) doorman := New(&defaultConfig)
warden.LoadPolicies(samplePoliciesFile) doorman.LoadPolicies(samplePoliciesFile)
SetupRoutes(r, warden) SetupRoutes(r, doorman)
for _, request := range []*ladon.Request{ for _, request := range []*ladon.Request{
// Policy #1 // Policy #1
@ -180,11 +180,11 @@ func TestWardenAllowed(t *testing.T) {
} }
} }
func TestWardenNotAllowed(t *testing.T) { func TestDoormanNotAllowed(t *testing.T) {
r := gin.New() r := gin.New()
warden := New(&defaultConfig) doorman := New(&defaultConfig)
warden.LoadPolicies(samplePoliciesFile) doorman.LoadPolicies(samplePoliciesFile)
SetupRoutes(r, warden) SetupRoutes(r, doorman)
for _, request := range []*ladon.Request{ for _, request := range []*ladon.Request{
// Policy #1 // Policy #1

Просмотреть файл

@ -1,4 +1,4 @@
package warden package doorman
import ( import (
"net/http" "net/http"

Просмотреть файл

@ -1,4 +1,4 @@
package warden package doorman
import ( import (
"net/http" "net/http"
@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// TestMain defined in warden_test.go // TestMain defined in doorman_test.go
// func TestMain(m *testing.M) {} // func TestMain(m *testing.M) {}
func TestVerifyJWT(t *testing.T) { func TestVerifyJWT(t *testing.T) {

10
main.go
Просмотреть файл

@ -9,7 +9,7 @@ import (
"go.mozilla.org/mozlogrus" "go.mozilla.org/mozlogrus"
"github.com/leplatrem/iam/utilities" "github.com/leplatrem/iam/utilities"
"github.com/leplatrem/iam/warden" "github.com/leplatrem/iam/doorman"
) )
func init() { func init() {
@ -49,13 +49,13 @@ func setupRouter() *gin.Engine {
r.Use(gin.Logger()) r.Use(gin.Logger())
} }
// Setup warden with default config (read policies from disk) // Setup doorman with default config (read policies from disk)
config := &warden.Config{ config := &doorman.Config{
PoliciesFilename: "", PoliciesFilename: "",
JWTIssuer: os.Getenv("JWT_ISSUER"), JWTIssuer: os.Getenv("JWT_ISSUER"),
} }
w := warden.New(config) w := doorman.New(config)
warden.SetupRoutes(r, w) doorman.SetupRoutes(r, w)
utilities.SetupRoutes(r) utilities.SetupRoutes(r)

Просмотреть файл

@ -11,7 +11,7 @@ info:
tags: tags:
- name: Utilities - name: Utilities
- name: Warden - name: Doorman
paths: paths:
/__heartbeat__: /__heartbeat__:
@ -123,4 +123,4 @@ paths:
allowed: allowed:
type: boolean type: boolean
tags: tags:
- Warden - Doorman