Merge pull request #7117 from estesp/update-restful

This commit is contained in:
Fu Wei 2022-06-30 08:02:14 +08:00 committed by GitHub
commit 42d6923fe8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 78 additions and 54 deletions

2
go.mod
View File

@ -26,7 +26,7 @@ require (
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c
github.com/docker/go-metrics v0.0.1 github.com/docker/go-metrics v0.0.1
github.com/docker/go-units v0.4.0 github.com/docker/go-units v0.4.0
github.com/emicklei/go-restful/v3 v3.7.3 github.com/emicklei/go-restful/v3 v3.8.0
github.com/fsnotify/fsnotify v1.5.1 github.com/fsnotify/fsnotify v1.5.1
github.com/google/go-cmp v0.5.8 github.com/google/go-cmp v0.5.8
github.com/google/uuid v1.2.0 github.com/google/uuid v1.2.0

4
go.sum
View File

@ -360,8 +360,8 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.7.3 h1:06a5brwUhivED9WAFB3Q1JZDhirpnHlCdEVhGz3PSfc= github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
github.com/emicklei/go-restful/v3 v3.7.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=

View File

@ -210,7 +210,7 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.7.3/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=

View File

@ -1,5 +1,15 @@
# Change history of go-restful # Change history of go-restful
## [v3.8.0] - 20221-06-06
- use exact matching of allowed domain entries, issue #489 (#493)
- this changes fixes [security] Authorization Bypass Through User-Controlled Key
by changing the behaviour of the AllowedDomains setting in the CORS filter.
To support the previous behaviour, the CORS filter type now has a AllowedDomainFunc
callback mechanism which is called when a simple domain match fails.
- add test and fix for POST without body and Content-type, issue #492 (#496)
- [Minor] Bad practice to have a mix of Receiver types. (#491)
## [v3.7.2] - 2021-11-24 ## [v3.7.2] - 2021-11-24
- restored FilterChain (#482 by SVilgelm) - restored FilterChain (#482 by SVilgelm)

View File

@ -94,12 +94,11 @@ There are several hooks to customize the behavior of the go-restful package.
- Trace logging - Trace logging
- Compression - Compression
- Encoders for other serializers - Encoders for other serializers
- Use [jsoniter](https://github.com/json-iterator/go) by build this package using a tag, e.g. `go build -tags=jsoniter .` - Use [jsoniter](https://github.com/json-iterator/go) by build this package using a tag, e.g. `go build -tags=jsoniter .`
TODO: write examples of these.
## Resources ## Resources
- [Example programs](./examples)
- [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/) - [Example posted on blog](http://ernestmicklei.com/2012/11/go-restful-first-working-example/)
- [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/) - [Design explained on blog](http://ernestmicklei.com/2012/11/go-restful-api-design/)
- [sourcegraph](https://sourcegraph.com/github.com/emicklei/go-restful) - [sourcegraph](https://sourcegraph.com/github.com/emicklei/go-restful)
@ -108,4 +107,4 @@ TODO: write examples of these.
Type ```git shortlog -s``` for a full list of contributors. Type ```git shortlog -s``` for a full list of contributors.
© 2012 - 2021, http://ernestmicklei.com. MIT License. Contributions are welcome. © 2012 - 2022, http://ernestmicklei.com. MIT License. Contributions are welcome.

13
vendor/github.com/emicklei/go-restful/v3/SECURITY.md generated vendored Normal file
View File

@ -0,0 +1,13 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| v3.7.x | :white_check_mark: |
| < v3.0.1 | :x: |
## Reporting a Vulnerability
Create an Issue and put the label `[security]` in the title of the issue.
Valid reported security issues are expected to be solved within a week.

View File

@ -83,7 +83,11 @@ func (c *CompressingResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error
} }
// WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested. // WantsCompressedResponse reads the Accept-Encoding header to see if and which encoding is requested.
func wantsCompressedResponse(httpRequest *http.Request) (bool, string) { // It also inspects the httpWriter whether its content-encoding is already set (non-empty).
func wantsCompressedResponse(httpRequest *http.Request, httpWriter http.ResponseWriter) (bool, string) {
if contentEncoding := httpWriter.Header().Get(HEADER_ContentEncoding); contentEncoding != "" {
return false, ""
}
header := httpRequest.Header.Get(HEADER_AcceptEncoding) header := httpRequest.Header.Get(HEADER_AcceptEncoding)
gi := strings.Index(header, ENCODING_GZIP) gi := strings.Index(header, ENCODING_GZIP)
zi := strings.Index(header, ENCODING_DEFLATE) zi := strings.Index(header, ENCODING_DEFLATE)

View File

@ -261,7 +261,7 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
contentEncodingEnabled = *route.contentEncodingEnabled contentEncodingEnabled = *route.contentEncodingEnabled
} }
if contentEncodingEnabled { if contentEncodingEnabled {
doCompress, encoding := wantsCompressedResponse(httpRequest) doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
if doCompress { if doCompress {
var err error var err error
writer, err = NewCompressingResponseWriter(httpWriter, encoding) writer, err = NewCompressingResponseWriter(httpWriter, encoding)
@ -288,8 +288,8 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
allFilters = append(allFilters, webService.filters...) allFilters = append(allFilters, webService.filters...)
allFilters = append(allFilters, route.Filters...) allFilters = append(allFilters, route.Filters...)
chain := FilterChain{ chain := FilterChain{
Filters: allFilters, Filters: allFilters,
Target: route.Function, Target: route.Function,
ParameterDocs: route.ParameterDocs, ParameterDocs: route.ParameterDocs,
Operation: route.Operation, Operation: route.Operation,
} }
@ -332,7 +332,7 @@ func (c *Container) ServeHTTP(httpWriter http.ResponseWriter, httpRequest *http.
} }
}() }()
doCompress, encoding := wantsCompressedResponse(httpRequest) doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
if doCompress { if doCompress {
var err error var err error
writer, err = NewCompressingResponseWriter(httpWriter, encoding) writer, err = NewCompressingResponseWriter(httpWriter, encoding)
@ -365,7 +365,7 @@ func (c *Container) Handle(pattern string, handler http.Handler) {
}() }()
if c.contentEncodingEnabled { if c.contentEncodingEnabled {
doCompress, encoding := wantsCompressedResponse(httpRequest) doCompress, encoding := wantsCompressedResponse(httpRequest, httpWriter)
if doCompress { if doCompress {
var err error var err error
writer, err = NewCompressingResponseWriter(httpWriter, encoding) writer, err = NewCompressingResponseWriter(httpWriter, encoding)

View File

@ -18,9 +18,22 @@ import (
// http://enable-cors.org/server.html // http://enable-cors.org/server.html
// http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request // http://www.html5rocks.com/en/tutorials/cors/#toc-handling-a-not-so-simple-request
type CrossOriginResourceSharing struct { type CrossOriginResourceSharing struct {
ExposeHeaders []string // list of Header names ExposeHeaders []string // list of Header names
AllowedHeaders []string // list of Header names
AllowedDomains []string // list of allowed values for Http Origin. An allowed value can be a regular expression to support subdomain matching. If empty all are allowed. // AllowedHeaders is alist of Header names. Checking is case-insensitive.
// The list may contain the special wildcard string ".*" ; all is allowed
AllowedHeaders []string
// AllowedDomains is a list of allowed values for Http Origin.
// The list may contain the special wildcard string ".*" ; all is allowed
// If empty all are allowed.
AllowedDomains []string
// AllowedDomainFunc is optional and is a function that will do the check
// when the origin is not part of the AllowedDomains and it does not contain the wildcard ".*".
AllowedDomainFunc func(origin string) bool
// AllowedMethods is either empty or has a list of http methods names. Checking is case-insensitive.
AllowedMethods []string AllowedMethods []string
MaxAge int // number of seconds before requiring new Options request MaxAge int // number of seconds before requiring new Options request
CookiesAllowed bool CookiesAllowed bool
@ -119,36 +132,24 @@ func (c CrossOriginResourceSharing) isOriginAllowed(origin string) bool {
if len(origin) == 0 { if len(origin) == 0 {
return false return false
} }
lowerOrigin := strings.ToLower(origin)
if len(c.AllowedDomains) == 0 { if len(c.AllowedDomains) == 0 {
if c.AllowedDomainFunc != nil {
return c.AllowedDomainFunc(lowerOrigin)
}
return true return true
} }
allowed := false // exact match on each allowed domain
for _, domain := range c.AllowedDomains { for _, domain := range c.AllowedDomains {
if domain == origin { if domain == ".*" || strings.ToLower(domain) == lowerOrigin {
allowed = true return true
break
} }
} }
if c.AllowedDomainFunc != nil {
if !allowed { return c.AllowedDomainFunc(origin)
if len(c.allowedOriginPatterns) == 0 {
// compile allowed domains to allowed origin patterns
allowedOriginRegexps, err := compileRegexps(c.AllowedDomains)
if err != nil {
return false
}
c.allowedOriginPatterns = allowedOriginRegexps
}
for _, pattern := range c.allowedOriginPatterns {
if allowed = pattern.MatchString(origin); allowed {
break
}
}
} }
return false
return allowed
} }
func (c CrossOriginResourceSharing) setAllowOriginHeader(req *Request, resp *Response) { func (c CrossOriginResourceSharing) setAllowOriginHeader(req *Request, resp *Response) {
@ -190,16 +191,3 @@ func (c CrossOriginResourceSharing) isValidAccessControlRequestHeader(header str
} }
return false return false
} }
// Take a list of strings and compile them into a list of regular expressions.
func compileRegexps(regexpStrings []string) ([]*regexp.Regexp, error) {
regexps := []*regexp.Regexp{}
for _, regexpStr := range regexpStrings {
r, err := regexp.Compile(regexpStr)
if err != nil {
return regexps, err
}
regexps = append(regexps, r)
}
return regexps, nil
}

View File

@ -151,6 +151,16 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
for _, candidate := range previous { for _, candidate := range previous {
available = append(available, candidate.Produces...) available = append(available, candidate.Produces...)
} }
// if POST,PUT,PATCH without body
method, length := httpRequest.Method, httpRequest.Header.Get("Content-Length")
if (method == http.MethodPost ||
method == http.MethodPut ||
method == http.MethodPatch) && length == "" {
return nil, NewError(
http.StatusUnsupportedMediaType,
fmt.Sprintf("415: Unsupported Media Type\n\nAvailable representations: %s", strings.Join(available, ", ")),
)
}
return nil, NewError( return nil, NewError(
http.StatusNotAcceptable, http.StatusNotAcceptable,
fmt.Sprintf("406: Not Acceptable\n\nAvailable representations: %s", strings.Join(available, ", ")), fmt.Sprintf("406: Not Acceptable\n\nAvailable representations: %s", strings.Join(available, ", ")),

View File

@ -168,7 +168,7 @@ func tokenizePath(path string) []string {
} }
// for debugging // for debugging
func (r Route) String() string { func (r *Route) String() string {
return r.Method + " " + r.Path return r.Method + " " + r.Path
} }

2
vendor/modules.txt vendored
View File

@ -182,7 +182,7 @@ github.com/docker/go-units
## explicit ## explicit
github.com/emicklei/go-restful github.com/emicklei/go-restful
github.com/emicklei/go-restful/log github.com/emicklei/go-restful/log
# github.com/emicklei/go-restful/v3 v3.7.3 # github.com/emicklei/go-restful/v3 v3.8.0
## explicit; go 1.13 ## explicit; go 1.13
github.com/emicklei/go-restful/v3 github.com/emicklei/go-restful/v3
github.com/emicklei/go-restful/v3/log github.com/emicklei/go-restful/v3/log