Skip to content

Commit

Permalink
feat(template): JWT parser/verifier. (#95)
Browse files Browse the repository at this point in the history
* feat(template): JWT parser/verifier.

* doc(changelog): update changelog

* doc(template): functions documentation.
  • Loading branch information
Zenithar authored Jan 18, 2022
1 parent 7f46820 commit a52b8a5
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 1 deletion.
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
## 0.2.4
## 0.2.5

## Not released yet

FEATURES:

* template/engine [#95](https://github.com/elastic/harp/pull/95)
* `parseJwt` to parse JWT without signature validation
* `verifyJwt` to parse a JWT with signature validation

## 0.2.4

### 2022-01-14

DIST:

* Github actions release automation
* go: Build with Golang 1.17.6.

## 0.2.3

### 2021-12-10
Expand Down
29 changes: 29 additions & 0 deletions docs/onboarding/1-template-engine/2-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,35 @@ Decrypt input encoded as JWE.
{{ decryptJwe $passphrase $encrypted }}
```
#### parseJwt
Extract claims _WITHOUT_ signature validation.
```ruby
{{ $token = "..." }}
# Parse the JWT
{{ $t := parseJwt $token }}
# Access token claims
{{ $t.Claims | toJson }}
# Access token headers
{{ $t.Headers | toJson }}
```
#### verifyJwt
Extract claims _WITH_ signature validation.
```ruby
{{ $token = "..." }}
{{ $key = "..." }}
# Parse the JWT
{{ $t := verifyJwt $token $key.Public }}
# Access token claims
{{ $t.Claims | toJson }}
# Access token headers
{{ $t.Headers | toJson }}
```
#### toSSH
Encode the given key for OpenSSH usages.
Expand Down
46 changes: 46 additions & 0 deletions pkg/sdk/security/crypto/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
_ "golang.org/x/crypto/blake2b"
"golang.org/x/crypto/ssh"
jose "gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"

"github.com/elastic/harp/build/fips"
"github.com/elastic/harp/pkg/sdk/security/crypto/bech32"
Expand Down Expand Up @@ -346,6 +347,51 @@ func ToJWS(payload, privkey interface{}) (string, error) {
return serialize, nil
}

// ParseJWT unpack a JWT without signature verification.
func ParseJWT(token string) (interface{}, error) {
// Parse token
t, err := jwt.ParseSigned(token)
if err != nil {
return nil, fmt.Errorf("unable to parse input token: %w", err)
}

// Extract claims without verification
var claims map[string]interface{}
if err := t.UnsafeClaimsWithoutVerification(&claims); err != nil {
return nil, fmt.Errorf("unable to extract claims from token: %w", err)
}

return struct {
Headers []jose.Header
Claims map[string]interface{}
}{
Headers: t.Headers,
Claims: claims,
}, nil
}

func VerifyJWT(token string, key interface{}) (interface{}, error) {
// Parse token
t, err := jwt.ParseSigned(token)
if err != nil {
return nil, fmt.Errorf("unable to parse input token: %w", err)
}

// Extract claims without verification
var claims map[string]interface{}
if err := t.Claims(key, &claims); err != nil {
return nil, fmt.Errorf("unable to extract claims from token: %w", err)
}

return struct {
Headers []jose.Header
Claims map[string]interface{}
}{
Headers: t.Headers,
Claims: claims,
}, nil
}

// Bech32Decode decodes given bech32 encoded string.
func Bech32Decode(in string) (interface{}, error) {
hrp, data, err := bech32.Decode(in)
Expand Down
6 changes: 6 additions & 0 deletions pkg/template/engine/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package engine

import (
"encoding/base64"
"encoding/hex"
"encoding/json"
"net/url"
"strconv"
Expand Down Expand Up @@ -74,6 +75,11 @@ func FuncMap(secretReaders []SecretReaderFunc) template.FuncMap {
"encryptJwe": crypto.EncryptJWE,
"decryptJwe": crypto.DecryptJWE,
"toJws": crypto.ToJWS,
"parseJwt": crypto.ParseJWT,
"verifyJwt": crypto.VerifyJWT,
// Hex
"hexenc": hex.EncodeToString,
"hexdec": hex.DecodeString,
// Bech32
"bech32enc": bech32.Encode,
"bech32dec": crypto.Bech32Decode,
Expand Down
4 changes: 4 additions & 0 deletions pkg/template/engine/funcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func TestFuncs(t *testing.T) {
tpl: `{{ unquote . }}`,
expect: `{"channel":"buu","name":"john", "msg":"doe"}`,
vars: `"{\"channel\":\"buu\",\"name\":\"john\", \"msg\":\"doe\"}"`,
}, {
tpl: `{{ parseJwt . }}`,
expect: `{[{ <nil> HS256 [] map[typ:JWT]}] map[iat:1.516239022e+09 name:John Doe sub:1234567890]}`,
vars: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c`,
}}

for _, tt := range tests {
Expand Down

0 comments on commit a52b8a5

Please sign in to comment.