-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Moved credentials file parsing from jwt to nkey.
This allows to avoid unnecessary jwt dependencies. Signed-off-by: Matthias Hanel <[email protected]>
- Loading branch information
1 parent
b5fd77f
commit 069eed1
Showing
2 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package nkeys | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"regexp" | ||
) | ||
|
||
var userConfigRE = regexp.MustCompile(`\s*(?:(?:[-]{3,}.*[-]{3,}\r?\n)([\w\-.=]+)(?:\r?\n[-]{3,}.*[-]{3,}\r?\n))`) | ||
|
||
// ParseDecoratedJWT takes a creds file and returns the JWT portion. | ||
func ParseDecoratedJWT(contents []byte) (string, error) { | ||
items := userConfigRE.FindAllSubmatch(contents, -1) | ||
if len(items) == 0 { | ||
return string(contents), nil | ||
} | ||
// First result should be the user JWT. | ||
// We copy here so that if the file contained a seed file too we wipe appropriately. | ||
raw := items[0][1] | ||
tmp := make([]byte, len(raw)) | ||
copy(tmp, raw) | ||
return string(tmp), nil | ||
} | ||
|
||
// ParseDecoratedNKey takes a creds file, finds the NKey portion and creates a | ||
// key pair from it. | ||
func ParseDecoratedNKey(contents []byte) (KeyPair, error) { | ||
var seed []byte | ||
|
||
items := userConfigRE.FindAllSubmatch(contents, -1) | ||
if len(items) > 1 { | ||
seed = items[1][1] | ||
} else { | ||
lines := bytes.Split(contents, []byte("\n")) | ||
for _, line := range lines { | ||
if bytes.HasPrefix(bytes.TrimSpace(line), []byte("SO")) || | ||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SA")) || | ||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SU")) { | ||
seed = line | ||
break | ||
} | ||
} | ||
} | ||
if seed == nil { | ||
return nil, errors.New("no nkey seed found") | ||
} | ||
if !bytes.HasPrefix(seed, []byte("SO")) && | ||
!bytes.HasPrefix(seed, []byte("SA")) && | ||
!bytes.HasPrefix(seed, []byte("SU")) { | ||
return nil, errors.New("doesn't contain a seed nkey") | ||
} | ||
kp, err := FromSeed(seed) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return kp, nil | ||
} | ||
|
||
// ParseDecoratedUserNKey takes a creds file, finds the NKey portion and creates a | ||
// key pair from it. Similar to ParseDecoratedNKey but fails for non-user keys. | ||
func ParseDecoratedUserNKey(contents []byte) (KeyPair, error) { | ||
nk, err := ParseDecoratedNKey(contents) | ||
if err != nil { | ||
return nil, err | ||
} | ||
seed, err := nk.Seed() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if !bytes.HasPrefix(seed, []byte("SU")) { | ||
return nil, errors.New("doesn't contain an user seed nkey") | ||
} | ||
kp, err := FromSeed(seed) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return kp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package nkeys | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func Test_ParseDecoratedJWTBad(t *testing.T) { | ||
v, err := ParseDecoratedJWT([]byte("foo")) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if v != "foo" { | ||
t.Fatal("unexpected input was not returned") | ||
} | ||
} | ||
|
||
func Test_ParseDecoratedSeedBad(t *testing.T) { | ||
if _, err := ParseDecoratedNKey([]byte("foo")); err == nil { | ||
t.Fatal("Expected error") | ||
} else if err.Error() != "no nkey seed found"{ | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
const( | ||
credsSeed =`SUAOTBNEUHZDFJT3EUMELT7MQTP24JF3XVCXQNDSCU74G5IU6VAJBKH5LI` | ||
credsJwt = `eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJHVDROVU5NRUY3Wk1XQ1JCWFZWVURLUVQ2WllQWjc3VzRKUlFYRDNMMjRIS1VKRUNRSDdRIiwiaWF0IjoxNTkwNzgxNTkzLCJpc3MiOiJBQURXTFRISUNWNFNVQUdGNkVLTlZFVzVCQlA3WVJESUJHV0dHSFo1SkJET1FZQTdHVUZNNkFRVSIsIm5hbWUiOiJPUEVSQVRPUiIsInN1YiI6IlVERTZXVEdMVFRQQ1JKUkpDS0JKUkdWTlpUTElWUjdMRUVFTFI0Q1lXV1dCS0pTN1hZSUtYRFVVIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9LCJ0eXBlIjoidXNlciIsInZlcnNpb24iOjJ9fQ.c_XQT04wEoVVNDRjPHeKwe17BOrSpQTcftwIbB7KoNEIz6peZCJDc4-J3emVepHofUOWy7IAo9TlLwYhuGHWAQ` | ||
decoratedCreds = `-----BEGIN NATS USER JWT----- | ||
eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5LW5rZXkifQ.eyJqdGkiOiJHVDROVU5NRUY3Wk1XQ1JCWFZWVURLUVQ2WllQWjc3VzRKUlFYRDNMMjRIS1VKRUNRSDdRIiwiaWF0IjoxNTkwNzgxNTkzLCJpc3MiOiJBQURXTFRISUNWNFNVQUdGNkVLTlZFVzVCQlA3WVJESUJHV0dHSFo1SkJET1FZQTdHVUZNNkFRVSIsIm5hbWUiOiJPUEVSQVRPUiIsInN1YiI6IlVERTZXVEdMVFRQQ1JKUkpDS0JKUkdWTlpUTElWUjdMRUVFTFI0Q1lXV1dCS0pTN1hZSUtYRFVVIiwibmF0cyI6eyJwdWIiOnt9LCJzdWIiOnt9LCJ0eXBlIjoidXNlciIsInZlcnNpb24iOjJ9fQ.c_XQT04wEoVVNDRjPHeKwe17BOrSpQTcftwIbB7KoNEIz6peZCJDc4-J3emVepHofUOWy7IAo9TlLwYhuGHWAQ | ||
------END NATS USER JWT------ | ||
************************* IMPORTANT ************************* | ||
NKEY Seed printed below can be used to sign and prove identity. | ||
NKEYs are sensitive and should be treated as secrets. | ||
-----BEGIN USER NKEY SEED----- | ||
SUAOTBNEUHZDFJT3EUMELT7MQTP24JF3XVCXQNDSCU74G5IU6VAJBKH5LI | ||
------END USER NKEY SEED------ | ||
************************************************************* | ||
` | ||
) | ||
|
||
func Test_ParseDecoratedSeedAndJWT(t *testing.T) { | ||
// test with and without \r\n | ||
for _, creds := range [][]byte{[]byte(decoratedCreds), | ||
bytes.ReplaceAll([]byte(decoratedCreds), []byte{'\n'}, []byte{'\r', '\n'})} { | ||
kp, err := ParseDecoratedUserNKey(creds) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
pu, err := kp.Seed() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !bytes.Equal(pu, []byte(credsSeed)) { | ||
t.Fatal("seeds don't match") | ||
} | ||
|
||
kp, err = ParseDecoratedNKey(creds) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
pu, err = kp.Seed() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !bytes.Equal(pu, []byte(credsSeed)) { | ||
t.Fatal("seeds don't match") | ||
} | ||
|
||
jwt, err := ParseDecoratedJWT(creds) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if !bytes.Equal([]byte(jwt), []byte(credsJwt)) { | ||
t.Fatal("jwt don't match") | ||
} | ||
} | ||
} | ||
|