This commit is contained in:
parent
b00f5e9777
commit
7eac1db475
4 changed files with 111 additions and 5 deletions
104
web/public/middleware/authFetchCheck.go
Normal file
104
web/public/middleware/authFetchCheck.go
Normal file
|
@ -0,0 +1,104 @@
|
|||
package webmiddleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
|
||||
webutils "git.mstar.dev/mstar/goutils/http"
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
)
|
||||
|
||||
const signatureRegexString = `keyId=([a-zA-Z0-9_\-\.:@/\?&=#%\+\[\]!$\(\)\*,;]+),headers="([a-z0-9-_\(\) ]+)",(?:algorithm="([a-z0-9-])+",)?signature="(.+)"`
|
||||
|
||||
var publicPaths = []*regexp.Regexp{
|
||||
regexp.MustCompile(`/\.well-known/.+^`),
|
||||
// regexp.MustCompile(``),
|
||||
}
|
||||
|
||||
var signatureRegex = regexp.MustCompile(signatureRegexString)
|
||||
|
||||
// Builder for the authorized fetch check middleware.
|
||||
// forNonGet determines whether the check should happen for non-GET requests.
|
||||
// forGet determines whether the check should also happen for GET requests.
|
||||
// forGet being true implicitly sets forNonGet true too.
|
||||
// Requests to the server actor and other, required public resources
|
||||
// will never be checked
|
||||
func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuilder {
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
// Check always open path first
|
||||
for _, re := range publicPaths {
|
||||
if re.Match([]byte(path)) {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Not an always open path, check methods
|
||||
if r.Method == "GET" && !forGet {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
} else if !forGet && !forNonGet {
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
// TODO: Perform check here
|
||||
signatureHeader := r.Header.Get("Signature")
|
||||
if signatureHeader == "" {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusUnauthorized,
|
||||
"/errors/invalid-auth-signature",
|
||||
"invalid authorization signature",
|
||||
other.IntoPointer("Missing Signature header for authorization"),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
match := signatureRegex.FindStringSubmatch(signatureHeader)
|
||||
if len(match) <= 1 {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusUnauthorized,
|
||||
"/errors/invalid-auth-signature",
|
||||
"invalid authorization signature",
|
||||
other.IntoPointer("Invalid signature header format"),
|
||||
map[string]any{
|
||||
"used signature regex": signatureRegexString,
|
||||
"signature format": `keyId="<url to actor with used key>",headers="<list of headers used, including pseudo header (request-target)>",(optional: algorithm="<one of rsa-sha256, hs2019>", (defaults to rsa-sha256 if not set))signature="signed message"`,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
// fullMatch = match[0]
|
||||
rawKeyId := match[1]
|
||||
rawHeaders := match[2]
|
||||
rawAlgorithm := match[3]
|
||||
signature := match[4]
|
||||
|
||||
_, err := url.Parse(rawKeyId)
|
||||
if err != nil {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusUnauthorized,
|
||||
"/errors/invalid-auth-signature",
|
||||
"invalid authorization signature",
|
||||
other.IntoPointer("keyId must be a valid url"),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if rawAlgorithm == "" {
|
||||
rawAlgorithm = "hs2019"
|
||||
// w.Header().Add("X-Algorithm-Hint", "")
|
||||
}
|
||||
|
||||
_ = rawHeaders
|
||||
_ = signature
|
||||
_ = rawAlgorithm
|
||||
panic("not implemented")
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue