github.com/avenga/couper@v1.12.2/config/runtime/server.go (about)

     1  //go:generate stringer -type=HandlerKind -output=./server_string.go
     2  
     3  package runtime
     4  
     5  import (
     6  	"fmt"
     7  	"net"
     8  	"net/http"
     9  	"path"
    10  	"path/filepath"
    11  	"reflect"
    12  	"strconv"
    13  	"strings"
    14  
    15  	"github.com/docker/go-units"
    16  	"github.com/hashicorp/hcl/v2"
    17  	"github.com/sirupsen/logrus"
    18  
    19  	ac "github.com/avenga/couper/accesscontrol"
    20  	"github.com/avenga/couper/accesscontrol/jwk"
    21  	"github.com/avenga/couper/cache"
    22  	"github.com/avenga/couper/config"
    23  	"github.com/avenga/couper/config/configload/collect"
    24  	"github.com/avenga/couper/config/reader"
    25  	"github.com/avenga/couper/config/request"
    26  	"github.com/avenga/couper/config/runtime/server"
    27  	"github.com/avenga/couper/definitions"
    28  	"github.com/avenga/couper/errors"
    29  	"github.com/avenga/couper/eval"
    30  	"github.com/avenga/couper/eval/buffer"
    31  	"github.com/avenga/couper/handler"
    32  	"github.com/avenga/couper/handler/middleware"
    33  	"github.com/avenga/couper/oauth2"
    34  	"github.com/avenga/couper/oauth2/oidc"
    35  	"github.com/avenga/couper/utils"
    36  )
    37  
    38  const (
    39  	api HandlerKind = iota
    40  	endpoint
    41  	files
    42  	spa
    43  )
    44  
    45  type (
    46  	Port                int
    47  	Hosts               map[string]*MuxOptions
    48  	Ports               map[Port]Hosts
    49  	ServerConfiguration Ports
    50  	HandlerKind         uint8
    51  	endpointMap         map[*config.Endpoint]*config.API
    52  	endpointHandler     map[*config.Endpoint]http.Handler
    53  )
    54  
    55  func (p Port) String() string {
    56  	return strconv.Itoa(int(p))
    57  }
    58  
    59  func GetHostPort(hostPort string) (string, int, error) {
    60  	var host string
    61  	var port int
    62  
    63  	h, p, err := net.SplitHostPort(hostPort)
    64  	if err != nil {
    65  		return "", -1, err
    66  	}
    67  
    68  	host = strings.TrimRight(h, ".")
    69  
    70  	if p == "" || p == "*" {
    71  		port = -1
    72  	} else {
    73  		port, err = strconv.Atoi(p)
    74  		if err != nil {
    75  			return "", -1, err
    76  		}
    77  	}
    78  
    79  	return host, port, nil
    80  }
    81  
    82  // NewServerConfiguration sets http handler specific defaults and validates the given gateway configuration.
    83  // Wire up all endpoints and maps them within the returned Server.
    84  func NewServerConfiguration(conf *config.Couper, log *logrus.Entry, memStore *cache.MemoryStore) (ServerConfiguration, error) {
    85  	evalContext := conf.Context.Value(request.ContextType).(*eval.Context) // usually environment vars
    86  	confCtx := evalContext.HCLContext()
    87  
    88  	oidcConfigs, ocErr := configureOidcConfigs(conf, confCtx, log, memStore)
    89  	if ocErr != nil {
    90  		return nil, ocErr
    91  	}
    92  	conf.Context = evalContext.
    93  		WithMemStore(memStore).
    94  		WithOidcConfig(oidcConfigs)
    95  
    96  	accessControls, acErr := configureAccessControls(conf, confCtx, log, memStore, oidcConfigs)
    97  	if acErr != nil {
    98  		return nil, acErr
    99  	}
   100  
   101  	var (
   102  		serverConfiguration = make(ServerConfiguration)
   103  		defaultPort         = conf.Settings.DefaultPort
   104  		endpointHandlers    = make(endpointHandler)
   105  		isHostsMandatory    = len(conf.Servers) > 1
   106  	)
   107  
   108  	// Populate defined backends first...
   109  	if conf.Definitions != nil {
   110  		for _, backend := range conf.Definitions.Backend {
   111  			_, err := NewBackend(confCtx, backend.HCLBody(), log, conf, memStore)
   112  			if err != nil {
   113  				return nil, err
   114  			}
   115  		}
   116  
   117  		jobs := make(definitions.Jobs, 0)
   118  		for _, job := range conf.Definitions.Job {
   119  			serverOptions := &server.Options{
   120  				ServerErrTpl: errors.DefaultJSON,
   121  			}
   122  
   123  			endpointOptions, err := NewEndpointOptions(confCtx, job.Endpoint, nil, serverOptions, log, conf, memStore)
   124  			if err != nil {
   125  				if diags, ok := err.(hcl.Diagnostics); ok {
   126  					derr := diags[0]
   127  					derr.Summary = strings.Replace(derr.Summary, "endpoint:", "beta_job:", 1)
   128  					if strings.Contains(derr.Summary, "requires at least") {
   129  						derr.Summary = strings.Join(append([]string{},
   130  							strings.SplitAfter(derr.Summary, `" `)[0], "requires at least one request block"), "")
   131  					}
   132  					return nil, derr
   133  				}
   134  				return nil, err
   135  			}
   136  
   137  			endpointOptions.IsJob = true
   138  			epHandler := handler.NewEndpoint(endpointOptions, log, nil)
   139  
   140  			j := definitions.NewJob(job, epHandler, conf.Settings)
   141  			jobs = append(jobs, j)
   142  		}
   143  
   144  		// do not start go-routine on config check (-watch)
   145  		if _, exist := conf.Context.Value(request.ConfigDryRun).(bool); !exist {
   146  			jobs.Run(conf.Context, log)
   147  		}
   148  	}
   149  
   150  	for _, srvConf := range conf.Servers {
   151  		serverOptions, err := server.NewServerOptions(srvConf, log)
   152  		if err != nil {
   153  			return nil, err
   154  		}
   155  
   156  		if err = validateHosts(srvConf.Name, srvConf.Hosts, isHostsMandatory); err != nil {
   157  			return nil, err
   158  		}
   159  
   160  		portsHosts, err := getPortsHostsList(srvConf.Hosts, defaultPort)
   161  		if err != nil {
   162  			return nil, err
   163  		}
   164  
   165  		for port, hosts := range portsHosts {
   166  			for host, muxOpts := range hosts {
   167  				if serverConfiguration[port] == nil {
   168  					serverConfiguration[port] = make(Hosts)
   169  				}
   170  
   171  				if _, ok := serverConfiguration[port][host]; ok {
   172  					return nil, fmt.Errorf("conflict: host %q already defined for port: %d", host, port)
   173  				}
   174  
   175  				serverConfiguration[port][host] = muxOpts
   176  				serverConfiguration[port][host].ServerOptions = serverOptions
   177  			}
   178  		}
   179  
   180  		serverBodies := bodiesWithACBodies(conf.Definitions, srvConf.AccessControl, srvConf.DisableAccessControl)
   181  		serverBodies = append(serverBodies, srvConf.Remain)
   182  
   183  		var spaHandler http.Handler
   184  		var bootstrapFiles []string
   185  		spaMountPathSeen := make(map[string]struct{})
   186  		for _, spaConf := range srvConf.SPAs {
   187  			spaHandler, err = handler.NewSpa(evalContext.HCLContext(), spaConf, serverOptions, []hcl.Body{spaConf.Remain, srvConf.Remain})
   188  			if err != nil {
   189  				return nil, err
   190  			}
   191  
   192  			for _, mountPath := range spaConf.Paths {
   193  				mp := strings.Replace(mountPath, "**", "", 1)
   194  				dir := filepath.Dir(spaConf.BootstrapFile)
   195  				if !strings.HasSuffix(dir, mp) {
   196  					dir = filepath.Join(dir, mp)
   197  				}
   198  				bfp := filepath.Join(dir, filepath.Base(spaConf.BootstrapFile))
   199  				if _, seen := spaMountPathSeen[bfp]; !seen {
   200  					bootstrapFiles = append(bootstrapFiles, bfp)
   201  					spaMountPathSeen[bfp] = struct{}{}
   202  				}
   203  			}
   204  
   205  			epOpts := &handler.EndpointOptions{ErrorTemplate: serverOptions.ServerErrTpl}
   206  			notAllowedMethodsHandler := epOpts.ErrorTemplate.WithError(errors.MethodNotAllowed)
   207  			allowedMethodsHandler := middleware.NewAllowedMethodsHandler(nil, middleware.DefaultFileSpaAllowedMethods, spaHandler, notAllowedMethodsHandler)
   208  			spaHandler = allowedMethodsHandler
   209  
   210  			spaHandler, err = configureProtectedHandler(accessControls, conf, confCtx,
   211  				config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl),
   212  				config.NewAccessControl(spaConf.AccessControl, spaConf.DisableAccessControl),
   213  				&protectedOptions{
   214  					epOpts:   epOpts,
   215  					handler:  spaHandler,
   216  					memStore: memStore,
   217  					srvOpts:  serverOptions,
   218  				}, log)
   219  			if err != nil {
   220  				return nil, err
   221  			}
   222  
   223  			corsOptions, cerr := middleware.NewCORSOptions(whichCORS(srvConf, spaConf), allowedMethodsHandler.MethodAllowed)
   224  			if cerr != nil {
   225  				return nil, cerr
   226  			}
   227  
   228  			spaHandler = middleware.NewCORSHandler(corsOptions, spaHandler)
   229  
   230  			spaBodies := bodiesWithACBodies(conf.Definitions, spaConf.AccessControl, spaConf.DisableAccessControl)
   231  			spaHandler = middleware.NewCustomLogsHandler(
   232  				append(serverBodies, append(spaBodies, spaConf.Remain)...), spaHandler, "",
   233  			)
   234  
   235  			for _, p := range spaConf.Paths {
   236  				spaPath := path.Join(serverOptions.SrvBasePath, spaConf.BasePath, p)
   237  				err = setRoutesFromHosts(serverConfiguration, portsHosts, spaPath, spaHandler, spa)
   238  				if err != nil {
   239  					sbody := spaConf.HCLBody()
   240  					return nil, hcl.Diagnostics{&hcl.Diagnostic{
   241  						Subject: &sbody.Attributes["paths"].SrcRange,
   242  						Summary: err.Error(),
   243  					}}
   244  				}
   245  			}
   246  		}
   247  
   248  		var fileHandler http.Handler
   249  		for i, filesConf := range srvConf.Files {
   250  			fileHandler, err = handler.NewFile(
   251  				filesConf.DocumentRoot,
   252  				serverOptions.FilesBasePaths[i],
   253  				handler.NewPreferSpaFn(bootstrapFiles, filesConf.DocumentRoot),
   254  				serverOptions.FilesErrTpls[i],
   255  				serverOptions,
   256  				[]hcl.Body{filesConf.Remain, srvConf.Remain},
   257  			)
   258  			if err != nil {
   259  				return nil, err
   260  			}
   261  
   262  			epOpts := &handler.EndpointOptions{ErrorTemplate: serverOptions.FilesErrTpls[i]}
   263  			notAllowedMethodsHandler := epOpts.ErrorTemplate.WithError(errors.MethodNotAllowed)
   264  			allowedMethodsHandler := middleware.NewAllowedMethodsHandler(nil, middleware.DefaultFileSpaAllowedMethods, fileHandler, notAllowedMethodsHandler)
   265  			fileHandler = allowedMethodsHandler
   266  
   267  			fileHandler, err = configureProtectedHandler(accessControls, conf, confCtx,
   268  				config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl),
   269  				config.NewAccessControl(filesConf.AccessControl, filesConf.DisableAccessControl),
   270  				&protectedOptions{
   271  					epOpts:   epOpts,
   272  					handler:  fileHandler,
   273  					memStore: memStore,
   274  					srvOpts:  serverOptions,
   275  				}, log)
   276  			if err != nil {
   277  				return nil, err
   278  			}
   279  
   280  			corsOptions, cerr := middleware.NewCORSOptions(whichCORS(srvConf, filesConf), allowedMethodsHandler.MethodAllowed)
   281  			if cerr != nil {
   282  				return nil, cerr
   283  			}
   284  
   285  			fileHandler = middleware.NewCORSHandler(corsOptions, fileHandler)
   286  
   287  			fileBodies := bodiesWithACBodies(conf.Definitions, filesConf.AccessControl, filesConf.DisableAccessControl)
   288  			fileHandler = middleware.NewCustomLogsHandler(
   289  				append(serverBodies, append(fileBodies, filesConf.Remain)...), fileHandler, "",
   290  			)
   291  
   292  			err = setRoutesFromHosts(serverConfiguration, portsHosts, serverOptions.FilesBasePaths[i], fileHandler, files)
   293  			if err != nil {
   294  				return nil, err
   295  			}
   296  		}
   297  
   298  		endpointsMap, err := newEndpointMap(srvConf, serverOptions)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  
   303  		for endpointConf, parentAPI := range endpointsMap {
   304  			if endpointConf.Pattern == "" { // could happen for internally registered endpoints
   305  				return nil, fmt.Errorf("endpoint path pattern required")
   306  			}
   307  
   308  			epOpts, err := NewEndpointOptions(confCtx, endpointConf, parentAPI, serverOptions,
   309  				log, conf, memStore)
   310  			if err != nil {
   311  				return nil, err
   312  			}
   313  
   314  			// Evaluate access-control related buffer options.
   315  			acBodies := bodiesWithACBodies(conf.Definitions,
   316  				newAC(srvConf, parentAPI).
   317  					Merge(config.
   318  						NewAccessControl(endpointConf.AccessControl, endpointConf.DisableAccessControl)).List(), nil)
   319  			epOpts.BufferOpts |= buffer.Must(acBodies...)
   320  
   321  			errorHandlerDefinitions := ACDefinitions{ // misuse of definitions obj for now
   322  				"endpoint": &AccessControl{ErrorHandler: endpointConf.ErrorHandler},
   323  			}
   324  
   325  			modifier := []hcl.Body{srvConf.Remain}
   326  
   327  			kind := endpoint
   328  			if parentAPI != nil {
   329  				kind = api
   330  
   331  				modifier = []hcl.Body{parentAPI.Remain, srvConf.Remain}
   332  
   333  				errorHandlerDefinitions["api"] = &AccessControl{ErrorHandler: parentAPI.ErrorHandler}
   334  			}
   335  			epOpts.LogHandlerKind = kind.String()
   336  
   337  			var epHandler, protectedHandler http.Handler
   338  			if parentAPI != nil && parentAPI.CatchAllEndpoint == endpointConf {
   339  				protectedHandler = epOpts.ErrorTemplate.WithError(errors.RouteNotFound)
   340  			} else {
   341  				epErrorHandler, ehBufferOption, err := newErrorHandler(confCtx, conf, &protectedOptions{
   342  					epOpts:   epOpts,
   343  					memStore: memStore,
   344  					srvOpts:  serverOptions,
   345  				}, log, errorHandlerDefinitions, "api", "endpoint") // sequence of ref is important: api, endpoint (endpoint error_handler overrides api error_handler)
   346  				if err != nil {
   347  					return nil, err
   348  				}
   349  				if epErrorHandler != nil {
   350  					epOpts.ErrorHandler = epErrorHandler
   351  					epOpts.BufferOpts |= ehBufferOption
   352  				}
   353  				epHandler = handler.NewEndpoint(epOpts, log, modifier)
   354  
   355  				requiredPermissionExpr := endpointConf.RequiredPermission
   356  				if requiredPermissionExpr == nil && parentAPI != nil {
   357  					// if required permission in endpoint {} not defined, try required permission in parent api {}
   358  					requiredPermissionExpr = parentAPI.RequiredPermission
   359  				}
   360  				if requiredPermissionExpr == nil {
   361  					protectedHandler = epHandler
   362  				} else {
   363  					permissionsControl := ac.NewPermissionsControl(requiredPermissionExpr)
   364  					permissionsErrorHandler, _, err := newErrorHandler(confCtx, conf, &protectedOptions{
   365  						epOpts:   epOpts,
   366  						memStore: memStore,
   367  						srvOpts:  serverOptions,
   368  					}, log, errorHandlerDefinitions, "api", "endpoint") // sequence of ref is important: api, endpoint (endpoint error_handler overrides api error_handler)
   369  					if err != nil {
   370  						return nil, err
   371  					}
   372  
   373  					protectedHandler = middleware.NewErrorHandler(permissionsControl.Validate, permissionsErrorHandler)(epHandler)
   374  				}
   375  			}
   376  
   377  			accessControl := newAC(srvConf, parentAPI)
   378  
   379  			allowedMethods := endpointConf.AllowedMethods
   380  			if allowedMethods == nil && parentAPI != nil {
   381  				// if allowed_methods in endpoint {} not defined, try allowed_methods in parent api {}
   382  				allowedMethods = parentAPI.AllowedMethods
   383  			}
   384  			notAllowedMethodsHandler := epOpts.ErrorTemplate.WithError(errors.MethodNotAllowed)
   385  			allowedMethodsHandler := middleware.NewAllowedMethodsHandler(allowedMethods, middleware.DefaultEndpointAllowedMethods, protectedHandler, notAllowedMethodsHandler)
   386  			protectedHandler = allowedMethodsHandler
   387  
   388  			epHandler, err = configureProtectedHandler(accessControls, conf, confCtx, accessControl,
   389  				config.NewAccessControl(endpointConf.AccessControl, endpointConf.DisableAccessControl),
   390  				&protectedOptions{
   391  					epOpts:   epOpts,
   392  					handler:  protectedHandler,
   393  					memStore: memStore,
   394  					srvOpts:  serverOptions,
   395  				}, log)
   396  			if err != nil {
   397  				return nil, err
   398  			}
   399  
   400  			corsOptions, err := middleware.NewCORSOptions(whichCORS(srvConf, parentAPI), allowedMethodsHandler.MethodAllowed)
   401  			if err != nil {
   402  				return nil, err
   403  			}
   404  
   405  			epHandler = middleware.NewCORSHandler(corsOptions, epHandler)
   406  
   407  			bodies := serverBodies
   408  			if parentAPI != nil {
   409  				apiBodies := bodiesWithACBodies(conf.Definitions, parentAPI.AccessControl, parentAPI.DisableAccessControl)
   410  				bodies = append(bodies, append(apiBodies, parentAPI.Remain)...)
   411  			}
   412  			bodies = append(bodies, bodiesWithACBodies(conf.Definitions, endpointConf.AccessControl, endpointConf.DisableAccessControl)...)
   413  			epHandler = middleware.NewCustomLogsHandler(
   414  				append(bodies, endpointConf.Remain), epHandler, epOpts.LogHandlerKind,
   415  			)
   416  
   417  			basePath := serverOptions.SrvBasePath
   418  			if parentAPI != nil {
   419  				basePath = serverOptions.APIBasePaths[parentAPI]
   420  			}
   421  
   422  			pattern := utils.JoinOpenAPIPath(basePath, endpointConf.Pattern)
   423  
   424  			endpointHandlers[endpointConf] = epHandler
   425  			err = setRoutesFromHosts(serverConfiguration, portsHosts, pattern, endpointHandlers[endpointConf], kind)
   426  			if err != nil {
   427  				return nil, err
   428  			}
   429  		}
   430  	}
   431  
   432  	return serverConfiguration, nil
   433  }
   434  
   435  func bodiesWithACBodies(defs *config.Definitions, ac, dac []string) []hcl.Body {
   436  	var bodies []hcl.Body
   437  
   438  	allAccessControls := collect.ErrorHandlerSetters(defs)
   439  
   440  	for _, ehs := range allAccessControls {
   441  		acConf, ok := ehs.(config.Body)
   442  		if !ok {
   443  			continue
   444  		}
   445  
   446  		t := reflect.ValueOf(acConf)
   447  		elem := t
   448  
   449  		if t.Kind() == reflect.Ptr {
   450  			elem = t.Elem()
   451  		}
   452  
   453  		nameValue := elem.FieldByName("Name")
   454  		if !nameValue.CanInterface() {
   455  			continue
   456  		}
   457  
   458  		for _, name := range config.NewAccessControl(ac, dac).List() {
   459  			if value, vk := nameValue.Interface().(string); vk && value == name {
   460  				bodies = append(bodies, acConf.HCLBody())
   461  			}
   462  		}
   463  	}
   464  
   465  	return bodies
   466  }
   467  
   468  func whichCORS(parent *config.Server, this interface{}) *config.CORS {
   469  	val := reflect.ValueOf(this)
   470  	if val.IsZero() {
   471  		return parent.CORS
   472  	}
   473  
   474  	corsValue := val.Elem().FieldByName("CORS")
   475  	corsData, ok := corsValue.Interface().(*config.CORS)
   476  	if !ok || corsData == nil {
   477  		return parent.CORS
   478  	}
   479  
   480  	if corsData.Disable {
   481  		return nil
   482  	}
   483  
   484  	return corsData
   485  }
   486  
   487  func configureOidcConfigs(conf *config.Couper, confCtx *hcl.EvalContext, log *logrus.Entry, memStore *cache.MemoryStore) (oidc.Configs, error) {
   488  	oidcConfigs := make(oidc.Configs)
   489  	if conf.Definitions != nil {
   490  		for _, oidcConf := range conf.Definitions.OIDC {
   491  			confErr := errors.Configuration.Label(oidcConf.Name)
   492  			backends := map[string]http.RoundTripper{}
   493  			for k, backendBody := range oidcConf.Backends {
   494  				var err error
   495  				backends[k], err = NewBackend(confCtx, backendBody, log, conf, memStore)
   496  				if err != nil {
   497  					return nil, confErr.With(err)
   498  				}
   499  			}
   500  
   501  			oidcConfig, err := oidc.NewConfig(conf.Context, oidcConf, backends)
   502  			if err != nil {
   503  				return nil, confErr.With(err)
   504  			}
   505  
   506  			oidcConfigs[oidcConf.Name] = oidcConfig
   507  		}
   508  	}
   509  
   510  	return oidcConfigs, nil
   511  }
   512  
   513  func configureAccessControls(conf *config.Couper, confCtx *hcl.EvalContext, log *logrus.Entry,
   514  	memStore *cache.MemoryStore, oidcConfigs oidc.Configs) (ACDefinitions, error) {
   515  
   516  	accessControls := make(ACDefinitions)
   517  
   518  	if conf.Definitions != nil {
   519  		for _, baConf := range conf.Definitions.BasicAuth {
   520  			confErr := errors.Configuration.Label(baConf.Name)
   521  			basicAuth, err := ac.NewBasicAuth(baConf.Name, baConf.User, baConf.Pass, baConf.File)
   522  			if err != nil {
   523  				return nil, confErr.With(err)
   524  			}
   525  
   526  			accessControls.Add(baConf.Name, basicAuth, baConf.ErrorHandler)
   527  		}
   528  
   529  		for _, jwtConf := range conf.Definitions.JWT {
   530  			confErr := errors.Configuration.Label(jwtConf.Name)
   531  
   532  			jwt, err := newJWT(jwtConf, conf, confCtx, log, memStore)
   533  			if err != nil {
   534  				return nil, confErr.With(err)
   535  			}
   536  
   537  			accessControls.Add(jwtConf.Name, jwt, jwtConf.ErrorHandler)
   538  		}
   539  
   540  		for _, saml := range conf.Definitions.SAML {
   541  			confErr := errors.Configuration.Label(saml.Name)
   542  			s, err := ac.NewSAML2ACS(saml.MetadataBytes, saml.Name, saml.SpAcsURL, saml.SpEntityID, saml.ArrayAttributes)
   543  			if err != nil {
   544  				return nil, confErr.With(err)
   545  			}
   546  
   547  			accessControls.Add(saml.Name, s, saml.ErrorHandler)
   548  		}
   549  
   550  		for _, oauth2Conf := range conf.Definitions.OAuth2AC {
   551  			confErr := errors.Configuration.Label(oauth2Conf.Name)
   552  			backend, err := NewBackend(confCtx, oauth2Conf.Backend, log, conf, memStore)
   553  			if err != nil {
   554  				return nil, confErr.With(err)
   555  			}
   556  
   557  			oauth2Client, err := oauth2.NewAuthCodeClient(confCtx, oauth2Conf, oauth2Conf, backend)
   558  			if err != nil {
   559  				return nil, confErr.With(err)
   560  			}
   561  
   562  			oa := ac.NewOAuth2Callback(oauth2Client, oauth2Conf.Name)
   563  
   564  			accessControls.Add(oauth2Conf.Name, oa, oauth2Conf.ErrorHandler)
   565  		}
   566  
   567  		for _, oidcConf := range conf.Definitions.OIDC {
   568  			confErr := errors.Configuration.Label(oidcConf.Name)
   569  			oidcConfig := oidcConfigs[oidcConf.Name]
   570  			oidcClient, err := oauth2.NewOidcClient(confCtx, oidcConfig)
   571  			if err != nil {
   572  				return nil, confErr.With(err)
   573  			}
   574  
   575  			oa := ac.NewOAuth2Callback(oidcClient, oidcConf.Name)
   576  
   577  			accessControls.Add(oidcConf.Name, oa, oidcConf.ErrorHandler)
   578  		}
   579  	}
   580  
   581  	return accessControls, nil
   582  }
   583  
   584  func newJWT(jwtConf *config.JWT, conf *config.Couper, confCtx *hcl.EvalContext,
   585  	log *logrus.Entry, memStore *cache.MemoryStore) (*ac.JWT, error) {
   586  	var (
   587  		jwt                      *ac.JWT
   588  		err                      error
   589  		rolesMap, permissionsMap map[string][]string
   590  	)
   591  	rolesMap, err = reader.ReadFromAttrFileJSONObjectOptional("jwt roles map", jwtConf.RolesMap, jwtConf.RolesMapFile)
   592  	if err != nil {
   593  		return nil, err
   594  	}
   595  	permissionsMap, err = reader.ReadFromAttrFileJSONObjectOptional("jwt permissions map", jwtConf.PermissionsMap, jwtConf.PermissionsMapFile)
   596  	if err != nil {
   597  		return nil, err
   598  	}
   599  	jwtOptions := &ac.JWTOptions{
   600  		Claims:                jwtConf.Claims,
   601  		ClaimsRequired:        jwtConf.ClaimsRequired,
   602  		DisablePrivateCaching: jwtConf.DisablePrivateCaching,
   603  		Name:                  jwtConf.Name,
   604  		RolesClaim:            jwtConf.RolesClaim,
   605  		RolesMap:              rolesMap,
   606  		PermissionsClaim:      jwtConf.PermissionsClaim,
   607  		PermissionsMap:        permissionsMap,
   608  		Source:                ac.NewJWTSource(jwtConf.Cookie, jwtConf.Header, jwtConf.TokenValue),
   609  	}
   610  	if jwtConf.JWKsURL != "" {
   611  		jwks, jerr := configureJWKS(jwtConf, confCtx, log, conf, memStore)
   612  		if jerr != nil {
   613  			return nil, jerr
   614  		}
   615  
   616  		jwtOptions.JWKS = jwks
   617  		jwt, err = ac.NewJWTFromJWKS(jwtOptions)
   618  	} else {
   619  		key, kerr := reader.ReadFromAttrFile("jwt key", jwtConf.Key, jwtConf.KeyFile)
   620  		if kerr != nil {
   621  			return nil, kerr
   622  		}
   623  
   624  		jwtOptions.Algorithm = jwtConf.SignatureAlgorithm
   625  		jwtOptions.Key = key
   626  		jwt, err = ac.NewJWT(jwtOptions)
   627  	}
   628  	if err != nil {
   629  		return nil, err
   630  	}
   631  
   632  	return jwt, nil
   633  }
   634  
   635  func configureJWKS(jwtConf *config.JWT, confContext *hcl.EvalContext, log *logrus.Entry, conf *config.Couper, memStore *cache.MemoryStore) (*jwk.JWKS, error) {
   636  	backend, err := NewBackend(confContext, jwtConf.Backend, log, conf, memStore)
   637  	if err != nil {
   638  		return nil, err
   639  	}
   640  
   641  	return jwk.NewJWKS(conf.Context, jwtConf.JWKsURL, jwtConf.JWKsTTL, jwtConf.JWKsMaxStale, backend)
   642  }
   643  
   644  type protectedOptions struct {
   645  	epOpts   *handler.EndpointOptions
   646  	handler  http.Handler
   647  	memStore *cache.MemoryStore
   648  	srvOpts  *server.Options
   649  }
   650  
   651  func configureProtectedHandler(m ACDefinitions, conf *config.Couper, ctx *hcl.EvalContext, parentAC, handlerAC config.AccessControl,
   652  	opts *protectedOptions, log *logrus.Entry) (http.Handler, error) {
   653  	var list ac.List
   654  	for _, acName := range parentAC.Merge(handlerAC).List() {
   655  		eh, _, err := newErrorHandler(ctx, conf, opts, log, m, acName)
   656  		if err != nil {
   657  			return nil, err
   658  		}
   659  		list = append(
   660  			list,
   661  			ac.NewItem(acName, m[acName].Control, eh),
   662  		)
   663  	}
   664  
   665  	if len(list) > 0 {
   666  		return handler.NewAccessControl(opts.handler, list), nil
   667  	}
   668  	return opts.handler, nil
   669  }
   670  
   671  func setRoutesFromHosts(
   672  	srvConf ServerConfiguration, portsHosts Ports,
   673  	path string, handler http.Handler, kind HandlerKind,
   674  ) error {
   675  	for port, hosts := range portsHosts {
   676  		for host := range hosts {
   677  			var routes map[string]http.Handler
   678  
   679  			switch kind {
   680  			case api:
   681  				fallthrough
   682  			case endpoint:
   683  				routes = srvConf[port][host].EndpointRoutes
   684  			case files:
   685  				routes = srvConf[port][host].FileRoutes
   686  			case spa:
   687  				routes = srvConf[port][host].SPARoutes
   688  			default:
   689  				return fmt.Errorf("unknown route kind")
   690  			}
   691  
   692  			if _, exist := routes[path]; exist {
   693  				return fmt.Errorf("duplicate route found on port %d: %s", port, path)
   694  			}
   695  
   696  			routes[path] = handler
   697  		}
   698  	}
   699  
   700  	return nil
   701  }
   702  
   703  func getPortsHostsList(hosts []string, defaultPort int) (Ports, error) {
   704  	if len(hosts) == 0 {
   705  		hosts = append(hosts, fmt.Sprintf("*:%d", defaultPort))
   706  	}
   707  
   708  	portsHosts := make(Ports)
   709  
   710  	for _, hp := range hosts {
   711  		if !strings.Contains(hp, ":") {
   712  			hp += fmt.Sprintf(":%d", defaultPort)
   713  		}
   714  
   715  		host, port, err := GetHostPort(hp)
   716  		if err != nil {
   717  			return nil, err
   718  		} else if port == -1 {
   719  			port = defaultPort
   720  		}
   721  
   722  		if portsHosts[Port(port)] == nil {
   723  			portsHosts[Port(port)] = make(Hosts)
   724  		}
   725  
   726  		portsHosts[Port(port)][host] = NewMuxOptions()
   727  	}
   728  
   729  	return portsHosts, nil
   730  }
   731  
   732  func parseBodyLimit(limit string) (int64, error) {
   733  	const defaultReqBodyLimit = "64MiB"
   734  	requestBodyLimit := defaultReqBodyLimit
   735  	if limit != "" {
   736  		requestBodyLimit = limit
   737  	}
   738  	return units.FromHumanSize(requestBodyLimit)
   739  }
   740  
   741  func newAC(srvConf *config.Server, api *config.API) config.AccessControl {
   742  	accessControl := config.NewAccessControl(srvConf.AccessControl, srvConf.DisableAccessControl)
   743  
   744  	if api != nil {
   745  		accessControl = accessControl.Merge(config.NewAccessControl(api.AccessControl, api.DisableAccessControl))
   746  	}
   747  
   748  	return accessControl
   749  }