2022-05-06 00:11:08 +00:00
|
|
|
package chiauth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"git.rootprojects.org/root/keypairs/keyfetch"
|
|
|
|
"git.rootprojects.org/root/libauth"
|
|
|
|
)
|
|
|
|
|
|
|
|
type ctxKey string
|
|
|
|
|
|
|
|
// JWSKey is used to get the InspectableToken from http.Request.Context().Value(chiauth.JWSKey)
|
|
|
|
var JWSKey = ctxKey("jws")
|
|
|
|
|
|
|
|
// VerificationParams specify the Issuer and whether or not the token is Optional (if provided, it must pass verification)
|
|
|
|
type VerificationParams struct {
|
|
|
|
Issuers keyfetch.Whitelist
|
|
|
|
Optional bool
|
|
|
|
/*
|
|
|
|
ExpLeeway int
|
|
|
|
NbfLeeway int
|
|
|
|
SelfSigned bool
|
|
|
|
PubKey keypairs.PublicKey
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewTokenVerifier returns a token-verifying middleware
|
|
|
|
//
|
2023-04-04 23:00:04 +00:00
|
|
|
// tokenVerifier := chiauth.NewTokenVerifier(chiauth.VerificationParams{
|
|
|
|
// Issuers: keyfetch.Whitelist([]string{"https://accounts.google.com"}),
|
|
|
|
// Optional: false,
|
|
|
|
// })
|
|
|
|
// r.Use(tokenVerifier)
|
2022-05-06 00:11:08 +00:00
|
|
|
//
|
2023-04-04 23:00:04 +00:00
|
|
|
// r.Post("/api/users/profile", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// ctx := r.Context()
|
|
|
|
// jws, ok := ctx.Value(chiauth.JWSKey).(*libauth.JWS)
|
|
|
|
// })
|
2022-05-06 00:11:08 +00:00
|
|
|
func NewTokenVerifier(opts VerificationParams) func(http.Handler) http.Handler {
|
|
|
|
return func(next http.Handler) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// just setting a default, other handlers can change this
|
|
|
|
|
|
|
|
token := r.Header.Get("Authorization")
|
|
|
|
|
2023-04-04 23:12:52 +00:00
|
|
|
if token == "" {
|
2022-05-06 00:11:08 +00:00
|
|
|
if opts.Optional {
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-04-04 23:22:57 +00:00
|
|
|
errmsg := "bad format: missing 'Authorization' header and 'access_token' query"
|
|
|
|
http.Error(w, errmsg, http.StatusBadRequest)
|
2022-05-06 00:11:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
parts := strings.Split(token, " ")
|
2023-04-04 23:12:52 +00:00
|
|
|
if len(parts) != 2 {
|
2023-04-04 23:22:57 +00:00
|
|
|
errmsg := "bad format: expected 'Authorization' header to be in the format of 'Bearer <Token>'"
|
|
|
|
http.Error(w, errmsg, http.StatusBadRequest)
|
2022-05-06 00:11:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
token = parts[1]
|
|
|
|
|
|
|
|
inspected, err := libauth.VerifyJWT(token, opts.Issuers, r)
|
|
|
|
if nil != err {
|
2023-04-04 23:22:57 +00:00
|
|
|
errmsg := "invalid token: " + err.Error()
|
|
|
|
http.Error(w, errmsg, http.StatusBadRequest)
|
2022-05-06 00:11:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if !inspected.Trusted {
|
2023-04-04 23:22:57 +00:00
|
|
|
errmsg := "invalid token: bad signature"
|
|
|
|
http.Error(w, errmsg, http.StatusBadRequest)
|
2022-05-06 00:11:08 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx := context.WithValue(r.Context(), JWSKey, inspected)
|
|
|
|
next.ServeHTTP(w, r.WithContext(ctx))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-05-09 21:14:12 +00:00
|
|
|
|
|
|
|
// GetJWS retrieves *libauth.JWS from r.Context()
|
|
|
|
func GetJWS(r *http.Request) *libauth.JWS {
|
|
|
|
ctx := r.Context()
|
|
|
|
jws, _ := ctx.Value(JWSKey).(*libauth.JWS)
|
|
|
|
return jws
|
|
|
|
}
|