зеркало из https://github.com/mozilla/doorman.git
Move handlers to dedicated package (Fixes #86)
This commit is contained in:
Родитель
75a0828895
Коммит
2db17712e2
|
@ -1,5 +1,5 @@
|
|||
main
|
||||
utilities/bindata.go
|
||||
handlers/bindata.go
|
||||
coverage.txt
|
||||
policies.yaml
|
||||
vendor/
|
||||
|
|
22
Makefile
22
Makefile
|
@ -2,15 +2,15 @@ GO_LINT := $(GOPATH)/bin/golint
|
|||
GO_DEP := $(GOPATH)/bin/dep
|
||||
GO_BINDATA := $(GOPATH)/bin/go-bindata
|
||||
GO_PACKAGE := $(GOPATH)/src/github.com/mozilla/doorman
|
||||
DATA_FILES := ./utilities/openapi.yaml ./utilities/contribute.yaml
|
||||
SRC := *.go ./config/*.go ./utilities/*.go ./authn/*.go ./doorman/*.go
|
||||
PACKAGES := ./ ./config/ ./utilities/ ./authn/ ./doorman/
|
||||
DATA_FILES := ./handlers/openapi.yaml ./handlers/contribute.yaml
|
||||
SRC := *.go ./config/*.go ./handlers/*.go ./authn/*.go ./doorman/*.go
|
||||
PACKAGES := ./ ./config/ ./handlers/ ./authn/ ./doorman/
|
||||
|
||||
main: vendor utilities/bindata.go $(SRC) $(GO_PACKAGE)
|
||||
main: vendor handlers/bindata.go $(SRC) $(GO_PACKAGE)
|
||||
CGO_ENABLED=0 go build -o main *.go
|
||||
|
||||
clean:
|
||||
rm -f main coverage.txt utilities/bindata.go vendor
|
||||
rm -f main coverage.txt handlers/bindata.go vendor
|
||||
|
||||
$(GOPATH):
|
||||
mkdir -p $(GOPATH)
|
||||
|
@ -28,8 +28,8 @@ $(GO_BINDATA): $(GOPATH)
|
|||
vendor: $(GO_DEP) Gopkg.lock Gopkg.toml
|
||||
$(GO_DEP) ensure
|
||||
|
||||
utilities/bindata.go: $(GO_BINDATA) $(DATA_FILES)
|
||||
$(GO_BINDATA) -o utilities/bindata.go -pkg utilities $(DATA_FILES)
|
||||
handlers/bindata.go: $(GO_BINDATA) $(DATA_FILES)
|
||||
$(GO_BINDATA) -o handlers/bindata.go -pkg handlers $(DATA_FILES)
|
||||
|
||||
policies.yaml:
|
||||
touch policies.yaml
|
||||
|
@ -47,10 +47,10 @@ lint: $(GO_LINT)
|
|||
fmt:
|
||||
gofmt -w -s $(SRC)
|
||||
|
||||
test: vendor policies.yaml utilities/bindata.go lint
|
||||
test: vendor policies.yaml handlers/bindata.go lint
|
||||
go test -v $(PACKAGES)
|
||||
|
||||
test-coverage: vendor policies.yaml utilities/bindata.go
|
||||
test-coverage: vendor policies.yaml handlers/bindata.go
|
||||
# Multiple package coverage script from https://github.com/pierrre/gotestcover
|
||||
echo 'mode: atomic' > coverage.txt && go list ./... | grep -v /vendor/ | xargs -n1 -I{} sh -c 'go test -v -covermode=atomic -coverprofile=coverage.tmp {} && tail -n +2 coverage.tmp >> coverage.txt' && rm coverage.tmp
|
||||
# Exclude bindata.go from coverage.
|
||||
|
@ -62,9 +62,9 @@ docker-build: main
|
|||
docker-run:
|
||||
docker run --name doorman --rm mozilla/doorman
|
||||
|
||||
api-docs: utilities/openapi.yaml
|
||||
api-docs: handlers/openapi.yaml
|
||||
# https://github.com/sourcey/spectacle
|
||||
spectacle --target-dir api-docs utilities/openapi.yaml
|
||||
spectacle --target-dir api-docs handlers/openapi.yaml
|
||||
|
||||
api-docs-publish: api-docs
|
||||
# https://github.com/tschaub/gh-pages
|
||||
|
|
|
@ -37,11 +37,11 @@ func NewAuthenticator(idP string) (Authenticator, error) {
|
|||
return nil, fmt.Errorf("identify provider %q does not use the https:// scheme", idP)
|
||||
}
|
||||
// Reuse authenticator instances.
|
||||
v, ok := authenticators[idP]
|
||||
a, ok := authenticators[idP]
|
||||
if !ok {
|
||||
// Only OpenID is currently supported.
|
||||
v = newOpenIDAuthenticator(idP)
|
||||
authenticators[idP] = v
|
||||
a = newOpenIDAuthenticator(idP)
|
||||
authenticators[idP] = a
|
||||
}
|
||||
return v, nil
|
||||
return a, nil
|
||||
}
|
||||
|
|
|
@ -102,6 +102,8 @@ func (r *Request) Roles() Principals {
|
|||
type Doorman interface {
|
||||
// LoadPolicies is responsible for loading the services configuration into memory.
|
||||
LoadPolicies(configs ServicesConfig) error
|
||||
// ConfigSources returns the list of configuration sources.
|
||||
ConfigSources() []string
|
||||
// Authenticator by service
|
||||
Authenticator(service string) (authn.Authenticator, error)
|
||||
// ExpandPrincipals looks up and add extra principals to the ones specified.
|
||||
|
|
|
@ -32,6 +32,20 @@ func NewDefaultLadon() *LadonDoorman {
|
|||
return w
|
||||
}
|
||||
|
||||
func (doorman *LadonDoorman) ConfigSources() []string {
|
||||
var l []string
|
||||
for _, c := range doorman.services {
|
||||
l = append(l, c.Source)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// SetAuthenticator allows to manually set an authenticator instance associated to
|
||||
// a domain.
|
||||
func (doorman *LadonDoorman) SetAuthenticator(service string, a authn.Authenticator) {
|
||||
doorman.authenticators[service] = a
|
||||
}
|
||||
|
||||
func (doorman *LadonDoorman) auditLogger() *auditLogger {
|
||||
if doorman._auditLogger == nil {
|
||||
doorman._auditLogger = newAuditLogger()
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
package doorman
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
)
|
||||
|
||||
// SetupRoutes adds doorman views to query the policies.
|
||||
func SetupRoutes(r *gin.Engine, doorman Doorman) {
|
||||
r.Use(ContextMiddleware(doorman))
|
||||
|
||||
a := r.Group("")
|
||||
a.Use(AuthnMiddleware(doorman))
|
||||
a.POST("/allowed", allowedHandler)
|
||||
}
|
||||
|
||||
func allowedHandler(c *gin.Context) {
|
||||
if c.Request.ContentLength == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
|
@ -23,7 +15,7 @@ func allowedHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
var r Request
|
||||
var r doorman.Request
|
||||
if err := c.BindJSON(&r); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"message": err.Error(),
|
||||
|
@ -41,7 +33,7 @@ func allowedHandler(c *gin.Context) {
|
|||
})
|
||||
return
|
||||
}
|
||||
r.Principals = principals.(Principals)
|
||||
r.Principals = principals.(doorman.Principals)
|
||||
} else {
|
||||
if len(r.Principals) == 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
|
@ -51,11 +43,11 @@ func allowedHandler(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
doorman := c.MustGet(DoormanContextKey).(Doorman)
|
||||
d := c.MustGet(DoormanContextKey).(doorman.Doorman)
|
||||
service := c.Request.Header.Get("Origin")
|
||||
|
||||
// Expand principals with local ones.
|
||||
r.Principals = doorman.ExpandPrincipals(service, r.Principals)
|
||||
r.Principals = d.ExpandPrincipals(service, r.Principals)
|
||||
// Expand principals with specified roles.
|
||||
r.Principals = append(r.Principals, r.Roles()...)
|
||||
|
||||
|
@ -63,13 +55,13 @@ func allowedHandler(c *gin.Context) {
|
|||
// XXX: using the context field to pass custom values on *ladon.Request
|
||||
// for audit logging is not very elegant.
|
||||
if r.Context == nil {
|
||||
r.Context = Context{}
|
||||
r.Context = doorman.Context{}
|
||||
}
|
||||
r.Context["remoteIP"] = c.Request.RemoteAddr
|
||||
r.Context["_service"] = service
|
||||
r.Context["_principals"] = r.Principals
|
||||
|
||||
allowed := doorman.IsAllowed(service, &r)
|
||||
allowed := d.IsAllowed(service, &r)
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"allowed": allowed,
|
|
@ -1,4 +1,4 @@
|
|||
package doorman
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -9,28 +9,21 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mozilla/doorman/config"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type AllowedResponse struct {
|
||||
Allowed bool
|
||||
Principals Principals
|
||||
Principals doorman.Principals
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func performRequest(r http.Handler, method, path string, body io.Reader) *httptest.ResponseRecorder {
|
||||
req, _ := http.NewRequest(method, path, body)
|
||||
req.Header.Set("Origin", "https://sample.yaml")
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
return w
|
||||
}
|
||||
|
||||
func performAllowed(t *testing.T, r *gin.Engine, body io.Reader, expected int, response interface{}) {
|
||||
w := performRequest(r, "POST", "/allowed", body)
|
||||
require.Equal(t, expected, w.Code)
|
||||
|
@ -40,7 +33,7 @@ func performAllowed(t *testing.T, r *gin.Engine, body io.Reader, expected int, r
|
|||
|
||||
func TestAllowedGet(t *testing.T) {
|
||||
r := gin.New()
|
||||
d := sampleDoorman()
|
||||
d := doorman.NewDefaultLadon()
|
||||
SetupRoutes(r, d)
|
||||
|
||||
w := performRequest(r, "GET", "/allowed", nil)
|
||||
|
@ -48,14 +41,14 @@ func TestAllowedGet(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAllowedVerifiesAuthentication(t *testing.T) {
|
||||
d := NewDefaultLadon()
|
||||
d := doorman.NewDefaultLadon()
|
||||
// Will initialize an authenticator (ie. download public keys)
|
||||
d.LoadPolicies(ServicesConfig{
|
||||
ServiceConfig{
|
||||
d.LoadPolicies(doorman.ServicesConfig{
|
||||
doorman.ServiceConfig{
|
||||
Service: "https://sample.yaml",
|
||||
JWTIssuer: "https://auth.mozilla.auth0.com/",
|
||||
Policies: Policies{
|
||||
Policy{
|
||||
Policies: doorman.Policies{
|
||||
doorman.Policy{
|
||||
Actions: []string{"update"},
|
||||
},
|
||||
},
|
||||
|
@ -65,7 +58,7 @@ func TestAllowedVerifiesAuthentication(t *testing.T) {
|
|||
r := gin.New()
|
||||
SetupRoutes(r, d)
|
||||
|
||||
authzRequest := Request{}
|
||||
authzRequest := doorman.Request{}
|
||||
token, _ := json.Marshal(authzRequest)
|
||||
body := bytes.NewBuffer(token)
|
||||
var response ErrorResponse
|
||||
|
@ -109,15 +102,15 @@ func TestAllowedHandlerBadRequest(t *testing.T) {
|
|||
json.Unmarshal(w.Body.Bytes(), &errResp)
|
||||
assert.Contains(t, errResp.Message, "missing principals")
|
||||
|
||||
doorman := sampleDoorman()
|
||||
d := doorman.NewDefaultLadon()
|
||||
|
||||
// Posted principals with AuthnMiddleware enabled.
|
||||
w = httptest.NewRecorder()
|
||||
c, _ = gin.CreateTestContext(w)
|
||||
c.Set(DoormanContextKey, doorman)
|
||||
c.Set(PrincipalsContextKey, Principals{"userid:maria"}) // Simulate authn middleware.
|
||||
authzRequest := Request{
|
||||
Principals: Principals{"userid:superuser"},
|
||||
c.Set(DoormanContextKey, d)
|
||||
c.Set(PrincipalsContextKey, doorman.Principals{"userid:maria"}) // Simulate authn middleware.
|
||||
authzRequest := doorman.Request{
|
||||
Principals: doorman.Principals{"userid:superuser"},
|
||||
}
|
||||
post, _ := json.Marshal(authzRequest)
|
||||
body = bytes.NewBuffer(post)
|
||||
|
@ -134,13 +127,18 @@ func TestAllowedHandler(t *testing.T) {
|
|||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
|
||||
doorman := sampleDoorman()
|
||||
c.Set(DoormanContextKey, doorman)
|
||||
configs, err := config.Load([]string{"../sample.yaml"})
|
||||
require.Nil(t, err)
|
||||
|
||||
d := doorman.NewDefaultLadon()
|
||||
err = d.LoadPolicies(configs)
|
||||
require.Nil(t, err)
|
||||
c.Set(DoormanContextKey, d)
|
||||
|
||||
// Using principals from context (AuthnMiddleware)
|
||||
c.Set(PrincipalsContextKey, Principals{"userid:maria"})
|
||||
c.Set(PrincipalsContextKey, doorman.Principals{"userid:maria"})
|
||||
|
||||
authzRequest := Request{
|
||||
authzRequest := doorman.Request{
|
||||
Action: "update",
|
||||
}
|
||||
post, _ := json.Marshal(authzRequest)
|
||||
|
@ -153,7 +151,7 @@ func TestAllowedHandler(t *testing.T) {
|
|||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.True(t, resp.Allowed)
|
||||
assert.Equal(t, Principals{"userid:maria", "tag:admins"}, resp.Principals)
|
||||
assert.Equal(t, doorman.Principals{"userid:maria", "tag:admins"}, resp.Principals)
|
||||
}
|
||||
|
||||
func TestAllowedHandlerRoles(t *testing.T) {
|
||||
|
@ -162,15 +160,21 @@ func TestAllowedHandlerRoles(t *testing.T) {
|
|||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
|
||||
doorman := sampleDoorman()
|
||||
c.Set(DoormanContextKey, doorman)
|
||||
configs, err := config.Load([]string{"../sample.yaml"})
|
||||
require.Nil(t, err)
|
||||
|
||||
println(len(configs))
|
||||
d := doorman.NewDefaultLadon()
|
||||
err = d.LoadPolicies(configs)
|
||||
require.Nil(t, err)
|
||||
c.Set(DoormanContextKey, d)
|
||||
|
||||
// Expand principals from context roles
|
||||
authzRequest := Request{
|
||||
Principals: Principals{"userid:bob"},
|
||||
authzRequest := doorman.Request{
|
||||
Principals: doorman.Principals{"userid:bob"},
|
||||
Action: "update",
|
||||
Resource: "pto",
|
||||
Context: Context{
|
||||
Context: doorman.Context{
|
||||
"roles": []string{"editor"},
|
||||
},
|
||||
}
|
||||
|
@ -181,5 +185,5 @@ func TestAllowedHandlerRoles(t *testing.T) {
|
|||
allowedHandler(c)
|
||||
|
||||
json.Unmarshal(w.Body.Bytes(), &resp)
|
||||
assert.Equal(t, Principals{"userid:bob", "role:editor"}, resp.Principals)
|
||||
assert.Equal(t, doorman.Principals{"userid:bob", "role:editor"}, resp.Principals)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package doorman
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/mozilla/doorman/authn"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
)
|
||||
|
||||
// DoormanContextKey is the Gin context key to obtain the *Doorman instance.
|
||||
|
@ -16,16 +17,16 @@ const DoormanContextKey string = "doorman"
|
|||
const PrincipalsContextKey string = "principals"
|
||||
|
||||
// ContextMiddleware adds the Doorman instance to the Gin context.
|
||||
func ContextMiddleware(doorman Doorman) gin.HandlerFunc {
|
||||
func ContextMiddleware(d doorman.Doorman) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.Set(DoormanContextKey, doorman)
|
||||
c.Set(DoormanContextKey, d)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// AuthnMiddleware relies on the authenticator if authentication was enabled
|
||||
// for the origin.
|
||||
func AuthnMiddleware(doorman Doorman) gin.HandlerFunc {
|
||||
func AuthnMiddleware(d doorman.Doorman) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// The service requesting must send its location. It will be compared
|
||||
// with the services defined in policies files.
|
||||
|
@ -39,7 +40,7 @@ func AuthnMiddleware(doorman Doorman) gin.HandlerFunc {
|
|||
}
|
||||
|
||||
// Check if authentication was configured for this service.
|
||||
authenticator, err := doorman.Authenticator(origin)
|
||||
authenticator, err := d.Authenticator(origin)
|
||||
if err != nil {
|
||||
// Unknown service
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
|
||||
|
@ -71,9 +72,9 @@ func AuthnMiddleware(doorman Doorman) gin.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func buildPrincipals(userInfo *authn.UserInfo) Principals {
|
||||
func buildPrincipals(userInfo *authn.UserInfo) doorman.Principals {
|
||||
// Extract principals from JWT
|
||||
var principals Principals
|
||||
var principals doorman.Principals
|
||||
userid := fmt.Sprintf("userid:%s", userInfo.ID)
|
||||
principals = append(principals, userid)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package doorman
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -12,33 +12,27 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/mozilla/doorman/authn"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
)
|
||||
|
||||
// TestMain defined in doorman_test.go
|
||||
// func TestMain(m *testing.M) {}
|
||||
|
||||
type TestValidator struct {
|
||||
type TestAuthenticator struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (v *TestValidator) Initialize() error {
|
||||
args := v.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
func (v *TestValidator) ValidateRequest(request *http.Request) (*authn.UserInfo, error) {
|
||||
func (v *TestAuthenticator) ValidateRequest(request *http.Request) (*authn.UserInfo, error) {
|
||||
args := v.Called(request)
|
||||
return args.Get(0).(*authn.UserInfo), args.Error(1)
|
||||
}
|
||||
|
||||
func TestAuthnMiddleware(t *testing.T) {
|
||||
doorman := NewDefaultLadon()
|
||||
handler := AuthnMiddleware(doorman)
|
||||
d := doorman.NewDefaultLadon()
|
||||
handler := AuthnMiddleware(d)
|
||||
|
||||
audience := "https://some.api.com"
|
||||
|
||||
// Associate a fake JWT validator to this issuer.
|
||||
v := &TestValidator{}
|
||||
doorman.authenticators[audience] = v
|
||||
v := &TestAuthenticator{}
|
||||
d.SetAuthenticator(audience, v)
|
||||
|
||||
// Extract claims is ran on every request.
|
||||
claims := &authn.UserInfo{
|
||||
|
@ -58,7 +52,7 @@ func TestAuthnMiddleware(t *testing.T) {
|
|||
// Principals are set in context.
|
||||
principals, ok := c.Get(PrincipalsContextKey)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, principals, Principals{
|
||||
assert.Equal(t, principals, doorman.Principals{
|
||||
"userid:ldap|user",
|
||||
"email:user@corp.com",
|
||||
"group:Employee",
|
||||
|
@ -81,7 +75,7 @@ func TestAuthnMiddleware(t *testing.T) {
|
|||
assert.False(t, ok)
|
||||
|
||||
// Authentication not configured for this origin.
|
||||
doorman.authenticators["https://open"] = nil
|
||||
d.SetAuthenticator("https://open", nil)
|
||||
|
||||
c.Request, _ = http.NewRequest("GET", "/get", nil)
|
||||
c.Request.Header.Set("Origin", "https://open")
|
||||
|
@ -93,13 +87,13 @@ func TestAuthnMiddleware(t *testing.T) {
|
|||
claims = &authn.UserInfo{
|
||||
ID: "ldap|user",
|
||||
}
|
||||
v = &TestValidator{}
|
||||
v = &TestAuthenticator{}
|
||||
v.On("ValidateRequest", mock.Anything).Return(claims, nil)
|
||||
doorman.authenticators[audience] = v
|
||||
d.SetAuthenticator(audience, v)
|
||||
c, _ = gin.CreateTestContext(httptest.NewRecorder())
|
||||
c.Request, _ = http.NewRequest("GET", "/get", nil)
|
||||
c.Request.Header.Set("Origin", audience)
|
||||
handler(c)
|
||||
principals, _ = c.Get(PrincipalsContextKey)
|
||||
assert.Equal(t, Principals{"userid:ldap|user"}, principals)
|
||||
assert.Equal(t, doorman.Principals{"userid:ldap|user"}, principals)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
)
|
||||
|
||||
// SetupRoutes adds HTTP endpoints to the gin.Engine.
|
||||
func SetupRoutes(r *gin.Engine, d doorman.Doorman) {
|
||||
r.Use(ContextMiddleware(d))
|
||||
|
||||
a := r.Group("")
|
||||
a.Use(AuthnMiddleware(d))
|
||||
a.POST("/allowed", allowedHandler)
|
||||
|
||||
sources := d.ConfigSources()
|
||||
r.POST("/__reload__", reloadHandler(sources))
|
||||
|
||||
r.GET("/__lbheartbeat__", lbHeartbeatHandler)
|
||||
r.GET("/__heartbeat__", heartbeatHandler)
|
||||
r.GET("/__version__", versionHandler)
|
||||
r.GET("/__api__", YAMLAsJSONHandler("handlers/openapi.yaml"))
|
||||
r.GET("/contribute.json", YAMLAsJSONHandler("handlers/contribute.yaml"))
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mozilla/doorman/config"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
config.AddLoader(&config.FileLoader{})
|
||||
|
||||
//Set Gin to Test Mode
|
||||
gin.SetMode(gin.TestMode)
|
||||
// Run the other tests
|
||||
os.Exit(m.Run())
|
||||
}
|
|
@ -1,22 +1,18 @@
|
|||
package config
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/mozilla/doorman/config"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
)
|
||||
|
||||
// SetupRoutes adds the reload config view.
|
||||
func SetupRoutes(r *gin.Engine, sources []string) {
|
||||
r.POST("/__reload__", reloadHandler(sources))
|
||||
}
|
||||
|
||||
func reloadHandler(sources []string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// Load files (from folders, files, Github, etc.)
|
||||
configs, err := Load(sources)
|
||||
configs, err := config.Load(sources)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"success": false,
|
||||
|
@ -26,9 +22,9 @@ func reloadHandler(sources []string) gin.HandlerFunc {
|
|||
}
|
||||
|
||||
// Load into Doorman.
|
||||
doorman := c.MustGet(doorman.DoormanContextKey).(doorman.Doorman)
|
||||
d := c.MustGet(DoormanContextKey).(doorman.Doorman)
|
||||
|
||||
if err := doorman.LoadPolicies(configs); err != nil {
|
||||
if err := d.LoadPolicies(configs); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"success": false,
|
||||
"message": err.Error(),
|
|
@ -1,4 +1,4 @@
|
|||
package config
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
@ -41,7 +41,7 @@ policies:
|
|||
for i := 0; i < 2; i++ {
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Set(doorman.DoormanContextKey, d)
|
||||
c.Set(DoormanContextKey, d)
|
||||
c.Request = reloadReq
|
||||
|
||||
handler(c)
|
||||
|
@ -55,7 +55,7 @@ policies:
|
|||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Set(doorman.DoormanContextKey, d)
|
||||
c.Set(DoormanContextKey, d)
|
||||
c.Request = reloadReq
|
||||
|
||||
handler(c)
|
||||
|
@ -78,7 +78,7 @@ policies:
|
|||
`))
|
||||
w = httptest.NewRecorder()
|
||||
c, _ = gin.CreateTestContext(w)
|
||||
c.Set(doorman.DoormanContextKey, d)
|
||||
c.Set(DoormanContextKey, d)
|
||||
c.Request = reloadReq
|
||||
|
||||
handler(c)
|
|
@ -1,5 +1,5 @@
|
|||
// Package utilities provides utility endpoints like heartbeat, OpenAPI, contribute, etc.
|
||||
package utilities
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
@ -10,15 +10,6 @@ import (
|
|||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// SetupRoutes adds utilities views.
|
||||
func SetupRoutes(r *gin.Engine) {
|
||||
r.GET("/__lbheartbeat__", lbHeartbeatHandler)
|
||||
r.GET("/__heartbeat__", heartbeatHandler)
|
||||
r.GET("/__version__", versionHandler)
|
||||
r.GET("/__api__", YAMLAsJSONHandler("utilities/openapi.yaml"))
|
||||
r.GET("/contribute.json", YAMLAsJSONHandler("utilities/contribute.yaml"))
|
||||
}
|
||||
|
||||
// Yaml2JSON converts an unmarshalled YAML object to a JSON one.
|
||||
func Yaml2JSON(i interface{}) interface{} {
|
||||
// https://stackoverflow.com/a/40737676/141895
|
|
@ -1,7 +1,8 @@
|
|||
package utilities
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
|
@ -9,19 +10,15 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
//Set Gin to Test Mode
|
||||
gin.SetMode(gin.TestMode)
|
||||
// Run the other tests
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
|
||||
req, _ := http.NewRequest(method, path, nil)
|
||||
func performRequest(r http.Handler, method, path string, body io.Reader) *httptest.ResponseRecorder {
|
||||
req, _ := http.NewRequest(method, path, body)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Origin", "https://sample.yaml")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
return w
|
||||
|
@ -29,10 +26,10 @@ func performRequest(r http.Handler, method, path string) *httptest.ResponseRecor
|
|||
|
||||
func testJSONResponse(t *testing.T, url string, response interface{}) *httptest.ResponseRecorder {
|
||||
r := gin.New()
|
||||
SetupRoutes(r)
|
||||
w := performRequest(r, "GET", url)
|
||||
SetupRoutes(r, doorman.NewDefaultLadon())
|
||||
w := performRequest(r, "GET", url, nil)
|
||||
|
||||
assert.Equal(t, w.Code, http.StatusOK)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
require.Nil(t, err)
|
||||
|
||||
|
@ -59,11 +56,11 @@ func TestHeartbeat(t *testing.T) {
|
|||
func TestVersion(t *testing.T) {
|
||||
// HTTP 404 if not found in current dir
|
||||
r := gin.New()
|
||||
SetupRoutes(r)
|
||||
w := performRequest(r, "GET", "/__version__")
|
||||
SetupRoutes(r, doorman.NewDefaultLadon())
|
||||
w := performRequest(r, "GET", "/__version__", nil)
|
||||
assert.Equal(t, w.Code, http.StatusNotFound)
|
||||
|
||||
// Copy to ./utilities/
|
||||
// Copy to ./handlers/
|
||||
data, _ := ioutil.ReadFile("../version.json")
|
||||
ioutil.WriteFile("version.json", data, 0644)
|
||||
defer os.Remove("version.json")
|
6
main.go
6
main.go
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
"github.com/mozilla/doorman/config"
|
||||
"github.com/mozilla/doorman/doorman"
|
||||
"github.com/mozilla/doorman/utilities"
|
||||
"github.com/mozilla/doorman/handlers"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -40,9 +40,7 @@ func setupRouter() (*gin.Engine, error) {
|
|||
}
|
||||
|
||||
// Endpoints
|
||||
doorman.SetupRoutes(r, d)
|
||||
utilities.SetupRoutes(r)
|
||||
config.SetupRoutes(r, settings.Sources)
|
||||
handlers.SetupRoutes(r, d)
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче