Merge pull request #150 from caos/key-selection
fix: handle keys without `use` in FindMatchingKey
This commit is contained in:
commit
219ba4e038
2 changed files with 130 additions and 8 deletions
|
@ -53,7 +53,7 @@ func FindKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (jose.JSON
|
||||||
return key, err == nil
|
return key, err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and key type
|
//FindMatchingKey searches the given JSON Web Keys for the requested key ID, usage and alg type
|
||||||
//
|
//
|
||||||
//will return the key immediately if matches exact (id, usage, type)
|
//will return the key immediately if matches exact (id, usage, type)
|
||||||
//
|
//
|
||||||
|
@ -61,15 +61,27 @@ func FindKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (jose.JSON
|
||||||
func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
|
func FindMatchingKey(keyID, use, expectedAlg string, keys ...jose.JSONWebKey) (key jose.JSONWebKey, err error) {
|
||||||
var validKeys []jose.JSONWebKey
|
var validKeys []jose.JSONWebKey
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if k.Use == use && algToKeyType(k.Key, expectedAlg) {
|
//ignore all keys with wrong use (let empty use of published key pass)
|
||||||
if k.KeyID == keyID && keyID != "" {
|
if k.Use != use && k.Use != "" {
|
||||||
return k, nil
|
continue
|
||||||
}
|
}
|
||||||
if k.KeyID == "" || keyID == "" {
|
//ignore all keys with wrong algorithm type
|
||||||
validKeys = append(validKeys, k)
|
if !algToKeyType(k.Key, expectedAlg) {
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
//if we get here, use and alg match, so an equal (not empty) keyID is an exact match
|
||||||
|
if k.KeyID == keyID && keyID != "" {
|
||||||
|
return k, nil
|
||||||
|
}
|
||||||
|
//keyIDs did not match or at least one was empty (if later, then it could be a match)
|
||||||
|
if k.KeyID == "" || keyID == "" {
|
||||||
|
validKeys = append(validKeys, k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//if we get here, no match was possible at all (use / alg) or no exact match due to
|
||||||
|
//the signed JWT and / or the published keys didn't have a kid
|
||||||
|
//if later applies and only one key could be found, we'll return it
|
||||||
|
//otherwise a corresponding error will be thrown
|
||||||
if len(validKeys) == 1 {
|
if len(validKeys) == 1 {
|
||||||
return validKeys[0], nil
|
return validKeys[0], nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"errors"
|
"errors"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -139,6 +140,27 @@ func TestFindKey(t *testing.T) {
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"single key no use, jwt with kid, match",
|
||||||
|
args{
|
||||||
|
keyID: "id",
|
||||||
|
use: KeyUseSignature,
|
||||||
|
expectedAlg: "RS256",
|
||||||
|
keys: []jose.JSONWebKey{
|
||||||
|
{
|
||||||
|
KeyID: "id",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
key: jose.JSONWebKey{
|
||||||
|
KeyID: "id",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"single key wrong kid, ErrKeyNone",
|
"single key wrong kid, ErrKeyNone",
|
||||||
args{
|
args{
|
||||||
|
@ -304,6 +326,94 @@ func TestFindKey(t *testing.T) {
|
||||||
err: nil,
|
err: nil,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"multiple keys, no use, jwt with kid, match",
|
||||||
|
args{
|
||||||
|
keyID: "id1",
|
||||||
|
use: KeyUseSignature,
|
||||||
|
expectedAlg: "RS256",
|
||||||
|
keys: []jose.JSONWebKey{
|
||||||
|
{
|
||||||
|
KeyID: "id1",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
KeyID: "id2",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
key: jose.JSONWebKey{
|
||||||
|
KeyID: "id1",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple keys, no use, jwt without kid, ErrKeyMultiple",
|
||||||
|
args{
|
||||||
|
use: KeyUseSignature,
|
||||||
|
expectedAlg: "RS256",
|
||||||
|
keys: []jose.JSONWebKey{
|
||||||
|
{
|
||||||
|
KeyID: "id1",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
KeyID: "id2",
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
key: jose.JSONWebKey{},
|
||||||
|
err: ErrKeyMultiple,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple keys, no use or id, jwt with kid, ErrKeyMultiple",
|
||||||
|
args{
|
||||||
|
use: KeyUseSignature,
|
||||||
|
expectedAlg: "RS256",
|
||||||
|
keyID: "id1",
|
||||||
|
keys: []jose.JSONWebKey{
|
||||||
|
{
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
key: jose.JSONWebKey{},
|
||||||
|
err: ErrKeyMultiple,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"multiple keys (only one matching alg), jwt with kid, match",
|
||||||
|
args{
|
||||||
|
use: KeyUseSignature,
|
||||||
|
expectedAlg: "RS256",
|
||||||
|
keyID: "id1",
|
||||||
|
keys: []jose.JSONWebKey{
|
||||||
|
{
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Key: &ecdsa.PublicKey{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
key: jose.JSONWebKey{
|
||||||
|
Key: &rsa.PublicKey{},
|
||||||
|
},
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue