Repository: avenga/couper
Pull request #221 (2021-05-03 14:31:46)

No panic for undefined ACs


Patch:
diff --git a/accesscontrol/ac.go b/accesscontrol/ac.go
index 82e247bf..244eef6f 100644
--- a/accesscontrol/ac.go
+++ b/accesscontrol/ac.go
@@ -1,6 +1,7 @@
 package accesscontrol
 
 import (
+	"fmt"
 	"net/http"
 
 	"github.com/avenga/couper/eval"
@@ -43,12 +44,14 @@ func (f ValidateFunc) Validate(req *http.Request) error {
 	return nil
 }
 
-func (m Map) MustExist(name string) {
+func (m Map) Exist(name string) error {
 	if m == nil {
 		panic("no accessControl configuration")
 	}
 
 	if _, ok := m[name]; !ok {
-		panic("accessControl is not defined: " + name)
+		return fmt.Errorf("accessControl is not defined: " + name)
 	}
+
+	return nil
 }
diff --git a/config/runtime/server.go b/config/runtime/server.go
index 625865e3..d47d92ad 100644
--- a/config/runtime/server.go
+++ b/config/runtime/server.go
@@ -158,10 +158,14 @@ func NewServerConfiguration(
 				h = spaHandler
 			}
 
-			spaHandler = configureProtectedHandler(accessControls, serverOptions.ServerErrTpl,
+			spaHandler, err = configureProtectedHandler(accessControls, serverOptions.ServerErrTpl,
 				config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl),
 				config.NewAccessControl(srvConf.Spa.AccessControl, srvConf.Spa.DisableAccessControl), h)
 
+			if err != nil {
+				return nil, err
+			}
+
 			for _, spaPath := range srvConf.Spa.Paths {
 				err = setRoutesFromHosts(serverConfiguration, portsHosts, path.Join(serverOptions.SPABasePath, spaPath), spaHandler, spa)
 				if err != nil {
@@ -189,10 +193,14 @@ func NewServerConfiguration(
 				h = fileHandler
 			}
 
-			protectedFileHandler := configureProtectedHandler(accessControls, serverOptions.FilesErrTpl,
+			protectedFileHandler, err := configureProtectedHandler(accessControls, serverOptions.FilesErrTpl,
 				config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl),
 				config.NewAccessControl(srvConf.Files.AccessControl, srvConf.Files.DisableAccessControl), h)
 
+			if err != nil {
+				return nil, err
+			}
+
 			err = setRoutesFromHosts(serverConfiguration, portsHosts, serverOptions.FilesBasePath, protectedFileHandler, files)
 			if err != nil {
 				return nil, err
@@ -254,16 +262,22 @@ func NewServerConfiguration(
 			endpointsPatterns[cleanPattern] = true
 
 			// setACHandlerFn individual wrap for access_control configuration per endpoint
-			setACHandlerFn := func(protectedHandler http.Handler) {
+			setACHandlerFn := func(protectedHandler http.Handler) error {
 				accessControl := newAC(srvConf, parentAPI)
 
 				if parentAPI != nil && parentAPI.CatchAllEndpoint == endpointConf {
 					protectedHandler = errTpl.ServeError(errors.APIRouteNotFound)
 				}
 
-				endpointHandlers[endpointConf] = configureProtectedHandler(accessControls, errTpl, accessControl,
+				endpointHandlers[endpointConf], err = configureProtectedHandler(accessControls, errTpl, accessControl,
 					config.NewAccessControl(endpointConf.AccessControl, endpointConf.DisableAccessControl),
 					protectedHandler)
+
+				if err != nil {
+					return err
+				}
+
+				return nil
 			}
 
 			var response *producer.Response
@@ -357,7 +371,10 @@ func NewServerConfiguration(
 				h = epHandler
 			}
 
-			setACHandlerFn(h)
+			err = setACHandlerFn(h)
+			if err != nil {
+				return nil, err
+			}
 
 			err = setRoutesFromHosts(serverConfiguration, portsHosts, pattern, endpointHandlers[endpointConf], kind)
 			if err != nil {
@@ -561,16 +578,18 @@ func configureAccessControls(conf *config.Couper, confCtx *hcl.EvalContext) (ac.
 	return accessControls, nil
 }
 
-func configureProtectedHandler(m ac.Map, errTpl *errors.Template, parentAC, handlerAC config.AccessControl, h http.Handler) http.Handler {
+func configureProtectedHandler(m ac.Map, errTpl *errors.Template, parentAC, handlerAC config.AccessControl, h http.Handler) (http.Handler, error) {
 	var acList ac.List
 	for _, acName := range parentAC.Merge(handlerAC).List() {
-		m.MustExist(acName)
+		if err := m.Exist(acName); err != nil {
+			return nil, err
+		}
 		acList = append(acList, ac.ListItem{Func: m[acName], Name: acName})
 	}
 	if len(acList) > 0 {
-		return hac.NewAccessControl(h, errTpl, acList)
+		return hac.NewAccessControl(h, errTpl, acList), nil
 	}
-	return h
+	return h, nil
 }
 
 func setRoutesFromHosts(


Test patch:
diff --git a/main_test.go b/main_test.go
index 13189136..31f8701a 100644
--- a/main_test.go
+++ b/main_test.go
@@ -33,6 +33,7 @@ func Test_realmain(t *testing.T) {
 		// TODO: format from file currently not possible due to the server error
 		{"json log format via env /w file", []string{"couper", "run", "-f", base + "/log_common.hcl"}, []string{"COUPER_LOG_FORMAT=json"}, `{"build":"dev","level":"error","message":"configuration error: missing server definition"`, 1},
 		{"-f w/o file", []string{"couper", "run", "-f"}, nil, `level=error msg="flag needs an argument: -f" build=dev`, 1},
+		{"undefined AC", []string{"couper", "run", "-f", base + "/04_couper.hcl"}, nil, `level=error msg="accessControl is not defined: undefined" build=dev`, 1},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/server/testdata/settings/04_couper.hcl b/server/testdata/settings/04_couper.hcl
new file mode 100644
index 00000000..cf5d182d
--- /dev/null
+++ b/server/testdata/settings/04_couper.hcl
@@ -0,0 +1,8 @@
+server "log-format-common" {
+  access_control = ["undefined"]
+  endpoint "/" {
+    response {
+      status = 500
+    }
+  }
+}