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 }