Move handlers to dedicated package (Fixes #86)

This commit is contained in:
Mathieu Leplatre 2018-01-29 13:02:10 +01:00
Родитель 75a0828895
Коммит 2db17712e2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 767B105F81A15CDD
18 изменённых файлов: 166 добавлений и 135 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -1,5 +1,5 @@
main
utilities/bindata.go
handlers/bindata.go
coverage.txt
policies.yaml
vendor/

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

@ -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)
}

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

24
handlers/handlers.go Normal file
Просмотреть файл

@ -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"))
}

18
handlers/handlers_test.go Normal file
Просмотреть файл

@ -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")

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

@ -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
}