github.com/safedep/dry@v0.0.0-20241016050132-a15651f0548b/apiguard/builder.go (about) 1 package apiguard 2 3 import ( 4 "crypto/subtle" 5 "errors" 6 "net/http" 7 "os" 8 ) 9 10 const ( 11 // API Guard config is the source of truth for these 12 // headers. Changes should be reflected in the API Guard 13 headerRemoteAddr = "X-Remote-Addr" 14 headerPath = "X-Path" 15 headerRequestId = "X-Request-Id" 16 headerTrustToken = "X-Gateway-Trust" 17 headerTokenEmail = "X-Jwt-Email" 18 headerTokenEmailVerified = "X-Jwt-Email-Verified" 19 headerTokenSub = "X-Jwt-Sub" 20 headerTokenAud = "X-Jwt-Aud" 21 headerMetaOrgId = "X-Org-Id" 22 headerMetaTeamId = "X-Team-Id" 23 headerMetaUserId = "X-User-Id" 24 headerMetaKeyId = "X-Key-Id" 25 ) 26 27 func EmailFromTokenHeaderName() string { 28 return headerTokenEmail 29 } 30 31 // SecurelyBuildFromHeader builds a context from the header and validates 32 // the trust token. Multiple tokens can be passed to allow zero downtime 33 // token rotation at the API Guard. 34 func SecurelyBuildFromHeader(header http.Header, tokens ...string) (*Context, error) { 35 if len(tokens) == 0 { 36 trustToken := os.Getenv("APIGUARD_TRUST_TOKEN") 37 if trustToken != "" { 38 tokens = append(tokens, trustToken) 39 } 40 } 41 42 if len(tokens) == 0 { 43 return nil, errors.New("APIGuard: Trust token not provided") 44 } 45 46 ctx, err := buildFromHeader(header) 47 if err != nil { 48 return nil, err 49 } 50 51 for _, trustToken := range tokens { 52 if subtle.ConstantTimeCompare([]byte(ctx.TrustToken), []byte(trustToken)) == 1 { 53 return ctx, nil 54 } 55 } 56 57 return nil, errors.New("APIGuard: Trust token mismatch") 58 } 59 60 // Build a context from the header. This is useful when the API Guard 61 // is a reverse proxy and the information is passed as headers. 62 func buildFromHeader(header http.Header) (*Context, error) { 63 ctx := Context{ 64 RemoteAddr: header.Get(headerRemoteAddr), 65 RequestID: header.Get(headerRequestId), 66 Path: header.Get(headerPath), 67 TrustToken: header.Get(headerTrustToken), 68 Key: KeyInfo{ 69 OrganizationID: header.Get(headerMetaOrgId), 70 TeamID: header.Get(headerMetaTeamId), 71 UserID: header.Get(headerMetaUserId), 72 KeyID: header.Get(headerMetaKeyId), 73 }, 74 Token: TokenInfo{ 75 Email: header.Get(headerTokenEmail), 76 EmailVerified: header.Get(headerTokenEmailVerified) == "true", 77 Subject: header.Get(headerTokenSub), 78 Audience: header.Get(headerTokenAud), 79 }, 80 } 81 82 return &ctx, nil 83 }