mirror of
https://github.com/offen/website.git
synced 2024-11-23 01:20:29 +01:00
further define cookie specifics, break auditorium into testable pieces
This commit is contained in:
parent
7f77d693ed
commit
7a2f47cbcc
@ -44,6 +44,7 @@ def post_login():
|
|||||||
expires=expiry,
|
expires=expiry,
|
||||||
path="/",
|
path="/",
|
||||||
domain=environ.get("COOKIE_DOMAIN"),
|
domain=environ.get("COOKIE_DOMAIN"),
|
||||||
|
samesite="strict"
|
||||||
)
|
)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -33,6 +33,10 @@ custom:
|
|||||||
production: accounts.offen.dev
|
production: accounts.offen.dev
|
||||||
staging: accounts-staging.offen.dev
|
staging: accounts-staging.offen.dev
|
||||||
alpha: accounts-alpha.offen.dev
|
alpha: accounts-alpha.offen.dev
|
||||||
|
cookieDomain:
|
||||||
|
production: .offen.dev
|
||||||
|
staging: .offen.dev
|
||||||
|
alpha: .offen.dev
|
||||||
customDomain:
|
customDomain:
|
||||||
basePath: ''
|
basePath: ''
|
||||||
certificateName: '*.offen.dev'
|
certificateName: '*.offen.dev'
|
||||||
@ -64,6 +68,7 @@ functions:
|
|||||||
environment:
|
environment:
|
||||||
USER: offen
|
USER: offen
|
||||||
CORS_ORIGIN: https://${self:custom.origin.${self:custom.stage}}
|
CORS_ORIGIN: https://${self:custom.origin.${self:custom.stage}}
|
||||||
|
COOKIE_DOMAIN: ${self:custom.origin.${self:custom.stage}}
|
||||||
JWT_PRIVATE_KEY: '${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/jwtPrivateKey~true}'
|
JWT_PRIVATE_KEY: '${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/jwtPrivateKey~true}'
|
||||||
JWT_PUBLIC_KEY: '${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/jwtPublicKey~true}'
|
JWT_PUBLIC_KEY: '${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/jwtPublicKey~true}'
|
||||||
HASHED_PASSWORD: ${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/hashedPassword~true}
|
HASHED_PASSWORD: ${ssm:/aws/reference/secretsmanager/${self:custom.stage}/accounts/hashedPassword~true}
|
||||||
|
@ -14,10 +14,6 @@ import (
|
|||||||
"github.com/lestrrat-go/jwx/jwt"
|
"github.com/lestrrat-go/jwx/jwt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type keyResponse struct {
|
|
||||||
Key string `json:"key"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type contextKey string
|
type contextKey string
|
||||||
|
|
||||||
// ClaimsContextKey will be used to attach a JWT claim to a request context
|
// ClaimsContextKey will be used to attach a JWT claim to a request context
|
||||||
@ -34,27 +30,25 @@ func JWTProtect(keyURL, cookieName string) func(http.Handler) http.Handler {
|
|||||||
RespondWithJSONError(w, err, http.StatusForbidden)
|
RespondWithJSONError(w, err, http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
keyRes, keyErr := http.Get(keyURL)
|
|
||||||
|
keyRes, keyErr := fetchKey(keyURL)
|
||||||
if keyErr != nil {
|
if keyErr != nil {
|
||||||
RespondWithJSONError(w, keyErr, http.StatusInternalServerError)
|
RespondWithJSONError(w, keyErr, http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer keyRes.Body.Close()
|
|
||||||
payload := keyResponse{}
|
keyBytes, _ := pem.Decode([]byte(keyRes))
|
||||||
if err := json.NewDecoder(keyRes.Body).Decode(&payload); err != nil {
|
|
||||||
RespondWithJSONError(w, keyErr, http.StatusBadGateway)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
keyBytes, _ := pem.Decode([]byte(payload.Key))
|
|
||||||
if keyBytes == nil {
|
if keyBytes == nil {
|
||||||
RespondWithJSONError(w, errors.New("no pem block found"), http.StatusInternalServerError)
|
RespondWithJSONError(w, errors.New("no pem block found"), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
parseResult, parseErr := x509.ParsePKIXPublicKey(keyBytes.Bytes)
|
parseResult, parseErr := x509.ParsePKIXPublicKey(keyBytes.Bytes)
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
RespondWithJSONError(w, parseErr, http.StatusBadGateway)
|
RespondWithJSONError(w, parseErr, http.StatusBadGateway)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pubKey, pubKeyOk := parseResult.(*rsa.PublicKey)
|
pubKey, pubKeyOk := parseResult.(*rsa.PublicKey)
|
||||||
if !pubKeyOk {
|
if !pubKeyOk {
|
||||||
RespondWithJSONError(w, errors.New("unable to use given key"), http.StatusInternalServerError)
|
RespondWithJSONError(w, errors.New("unable to use given key"), http.StatusInternalServerError)
|
||||||
@ -79,3 +73,20 @@ func JWTProtect(keyURL, cookieName string) func(http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type keyResponse struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchKey(keyURL string) ([]byte, error) {
|
||||||
|
fetchRes, fetchErr := http.Get(keyURL)
|
||||||
|
if fetchErr != nil {
|
||||||
|
return nil, fetchErr
|
||||||
|
}
|
||||||
|
defer fetchRes.Body.Close()
|
||||||
|
payload := keyResponse{}
|
||||||
|
if err := json.NewDecoder(fetchRes.Body).Decode(&payload); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return []byte(payload.Key), nil
|
||||||
|
}
|
||||||
|
49
shared/http/jwt_test.go
Normal file
49
shared/http/jwt_test.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestJWTProtect(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
cookie *http.Cookie
|
||||||
|
keyURL string
|
||||||
|
expectedStatusCode int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"no cookie",
|
||||||
|
nil,
|
||||||
|
"http://localhost:9999",
|
||||||
|
http.StatusForbidden,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bad url",
|
||||||
|
&http.Cookie{
|
||||||
|
Name: "auth",
|
||||||
|
Value: "irrelevantgibberish",
|
||||||
|
},
|
||||||
|
"http://localhost:9999",
|
||||||
|
http.StatusInternalServerError,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
wrappedHandler := JWTProtect("http://localhost:9999", "auth")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("OK"))
|
||||||
|
}))
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||||
|
if test.cookie != nil {
|
||||||
|
r.AddCookie(test.cookie)
|
||||||
|
}
|
||||||
|
wrappedHandler.ServeHTTP(w, r)
|
||||||
|
if w.Code != test.expectedStatusCode {
|
||||||
|
t.Errorf("Unexpected status code %v", w.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user