Auth fetch verification (cavage) works now
All checks were successful
/ docker (push) Successful in 4m14s
All checks were successful
/ docker (push) Successful in 4m14s
- Verifying inbound requests signed with Cavage are now checked as expected - Fixed a bug where the signature header is not generated correctly - Extended config to include settings for what requests to verify - Fixed new server in main not using internal port from config
This commit is contained in:
parent
271acc8d29
commit
627926460c
8 changed files with 90 additions and 36 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
webutils "git.mstar.dev/mstar/goutils/http"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
"git.mstar.dev/mstar/linstrom/web/public/api/activitypub"
|
||||
webmiddleware "git.mstar.dev/mstar/linstrom/web/public/middleware"
|
||||
)
|
||||
|
@ -18,7 +19,10 @@ func BuildApiRouter() http.Handler {
|
|||
"/activitypub",
|
||||
webutils.ChainMiddlewares(
|
||||
activitypub.BuildActivitypubRouter(),
|
||||
webmiddleware.BuildAuthorizedFetchCheck(true, true),
|
||||
webmiddleware.BuildAuthorizedFetchCheck(
|
||||
config.GlobalConfig.Admin.AuthFetchForNonGet,
|
||||
config.GlobalConfig.Admin.AuthFetchForGet,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -5,10 +5,12 @@ import (
|
|||
"crypto/rsa"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
webutils "git.mstar.dev/mstar/goutils/http"
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
|
@ -17,12 +19,13 @@ import (
|
|||
|
||||
"git.mstar.dev/mstar/linstrom/activitypub"
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
webshared "git.mstar.dev/mstar/linstrom/web/shared"
|
||||
)
|
||||
|
||||
const signatureRegexString = `keyId="([a-zA-Z0-9_\-\.:@\/\?&=#%\+\[\]!$\(\)\*,;]+)",(?:algorithm="([a-z0-9-]+)",)?headers="([a-z0-9-_\(\) ]+)",(?:algorithm="([a-z0-9-]+)",)?signature="(.+)"`
|
||||
const signatureRegexString = `keyId="([a-zA-Z0-9_\-\.:@\/\?&=#%\+\[\]!$\(\)\*,;]+)",(?:algorithm="([a-z0-9-]+)",)?headers="([a-z0-9\-_\(\) ]+)",(?:algorithm="([a-z0-9-]+)",)?signature="(.+)"`
|
||||
|
||||
var publicPaths = []*regexp.Regexp{
|
||||
regexp.MustCompile(`/\.well-known/.+^`),
|
||||
|
@ -61,12 +64,12 @@ func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuil
|
|||
// So either you get the server actor, which is intended behaviour, or access to
|
||||
// one specific note that most likely won't even exist
|
||||
|
||||
// FIXME: Re-enable once implementation of actual verification is stable
|
||||
// if strings.Contains(path, storage.ServerActorId) {
|
||||
// log.Info().Msg("Server actor requested, no auth")
|
||||
// h.ServeHTTP(w, r)
|
||||
// return
|
||||
// }
|
||||
if !config.GlobalConfig.Experimental.AuthFetchForServerActor &&
|
||||
strings.Contains(path, storage.ServerActorId) {
|
||||
log.Info().Msg("Server actor requested, no auth")
|
||||
h.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
// Not an always open path, check methods
|
||||
if r.Method == "GET" && !forGet {
|
||||
log.Info().Msg("Get request to AP resources don't need signature")
|
||||
|
@ -78,6 +81,30 @@ func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuil
|
|||
return
|
||||
}
|
||||
log.Info().Msg("Need signature for AP request")
|
||||
rawDate := r.Header.Get("Date")
|
||||
date, err := http.ParseTime(rawDate)
|
||||
if err != nil {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusBadRequest,
|
||||
"/errors/bad-date",
|
||||
"no or invalid date header",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
if time.Since(date) > time.Hour+time.Minute*5 {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusUnauthorized,
|
||||
"/errors/invalid-auth-signature",
|
||||
"invalid authorization signature",
|
||||
other.IntoPointer("Request is outdated"),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
signatureHeader := r.Header.Get("Signature")
|
||||
if signatureHeader == "" {
|
||||
log.Info().Msg("Received AP request without signature header where one is required")
|
||||
|
@ -117,7 +144,20 @@ func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuil
|
|||
rawAlgorithm1 := match[2]
|
||||
rawHeaders := match[3]
|
||||
rawAlgorithm2 := match[4]
|
||||
signature := match[5]
|
||||
signature, err := base64.StdEncoding.DecodeString(match[5])
|
||||
if err != nil {
|
||||
webutils.ProblemDetails(
|
||||
w,
|
||||
http.StatusUnauthorized,
|
||||
"/errors/invalid-auth-signature",
|
||||
"invalid authorization signature",
|
||||
other.IntoPointer(
|
||||
"Signature not decodable as bas64",
|
||||
),
|
||||
nil,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
var rawAlgorithm string
|
||||
if rawAlgorithm2 != "" {
|
||||
|
@ -127,7 +167,7 @@ func BuildAuthorizedFetchCheck(forNonGet bool, forGet bool) webutils.HandlerBuil
|
|||
} else {
|
||||
rawAlgorithm = "hs2019"
|
||||
}
|
||||
_, err := url.Parse(rawKeyId)
|
||||
_, err = url.Parse(rawKeyId)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Key id is not an url")
|
||||
webutils.ProblemDetails(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue