provisioner issuer -> name

This commit is contained in:
max furman 2018-10-29 18:00:30 -07:00
parent ce5f420d77
commit 0d9dd2d14b
11 changed files with 57 additions and 44 deletions

View file

@ -682,13 +682,13 @@ func Test_caHandler_Provisioners(t *testing.T) {
p := []*authority.Provisioner{ p := []*authority.Provisioner{
{ {
Type: "JWK", Type: "JWK",
Issuer: "max", Name: "max",
EncryptedKey: "abc", EncryptedKey: "abc",
Key: &key, Key: &key,
}, },
{ {
Type: "JWK", Type: "JWK",
Issuer: "mariano", Name: "mariano",
EncryptedKey: "def", EncryptedKey: "def",
Key: &key, Key: &key,
}, },

View file

@ -115,7 +115,7 @@ func (a *Authority) init() error {
} }
for _, p := range a.config.AuthorityConfig.Provisioners { for _, p := range a.config.AuthorityConfig.Provisioners {
a.provisionerIDIndex.Store(p.Key.KeyID, p) a.provisionerIDIndex.Store(p.ID(), p)
if len(p.EncryptedKey) != 0 { if len(p.EncryptedKey) != 0 {
a.encryptedKeyIndex.Store(p.Key.KeyID, p.EncryptedKey) a.encryptedKeyIndex.Store(p.Key.KeyID, p.EncryptedKey)
} }

View file

@ -17,12 +17,12 @@ func testAuthority(t *testing.T) *Authority {
assert.FatalError(t, err) assert.FatalError(t, err)
p := []*Provisioner{ p := []*Provisioner{
{ {
Issuer: "Max", Name: "Max",
Type: "JWK", Type: "JWK",
Key: maxjwk, Key: maxjwk,
}, },
{ {
Issuer: "step-cli", Name: "step-cli",
Type: "JWK", Type: "JWK",
Key: clijwk, Key: clijwk,
}, },
@ -113,7 +113,7 @@ func TestAuthorityNew(t *testing.T) {
assert.True(t, auth.initOnce) assert.True(t, auth.initOnce)
assert.NotNil(t, auth.intermediateIdentity) assert.NotNil(t, auth.intermediateIdentity)
for _, p := range tc.config.AuthorityConfig.Provisioners { for _, p := range tc.config.AuthorityConfig.Provisioners {
_p, ok := auth.provisionerIDIndex.Load(p.Key.KeyID) _p, ok := auth.provisionerIDIndex.Load(p.ID())
assert.True(t, ok) assert.True(t, ok)
assert.Equals(t, p, _p) assert.Equals(t, p, _p)
if len(p.EncryptedKey) > 0 { if len(p.EncryptedKey) > 0 {

View file

@ -44,14 +44,21 @@ func (a *Authority) Authorize(ott string) ([]interface{}, error) {
http.StatusUnauthorized, errContext} http.StatusUnauthorized, errContext}
} }
// Get claims w/out verification. We need to look up the provisioner
// key in order to verify the claims and we need the issuer from the claims
// before we can look up the provisioner.
if err = token.UnsafeClaimsWithoutVerification(&claims); err != nil {
return nil, &apiError{err, http.StatusUnauthorized, errContext}
}
kid := token.Headers[0].KeyID // JWT will only have 1 header. kid := token.Headers[0].KeyID // JWT will only have 1 header.
if len(kid) == 0 { if len(kid) == 0 {
return nil, &apiError{errors.New("authorize: token KeyID cannot be empty"), return nil, &apiError{errors.New("authorize: token KeyID cannot be empty"),
http.StatusUnauthorized, errContext} http.StatusUnauthorized, errContext}
} }
val, ok := a.provisionerIDIndex.Load(kid) pid := claims.Issuer + ":" + kid
val, ok := a.provisionerIDIndex.Load(pid)
if !ok { if !ok {
return nil, &apiError{errors.Errorf("authorize: provisioner with KeyID %s not found", kid), return nil, &apiError{errors.Errorf("authorize: provisioner with id %s not found", pid),
http.StatusUnauthorized, errContext} http.StatusUnauthorized, errContext}
} }
p, ok := val.(*Provisioner) p, ok := val.(*Provisioner)
@ -67,7 +74,7 @@ func (a *Authority) Authorize(ott string) ([]interface{}, error) {
// According to "rfc7519 JSON Web Token" acceptable skew should be no // According to "rfc7519 JSON Web Token" acceptable skew should be no
// more than a few minutes. // more than a few minutes.
if err = claims.ValidateWithLeeway(jwt.Expected{ if err = claims.ValidateWithLeeway(jwt.Expected{
Issuer: p.Issuer, Issuer: p.Name,
}, time.Minute); err != nil { }, time.Minute); err != nil {
return nil, &apiError{errors.Wrapf(err, "authorize: invalid token"), return nil, &apiError{errors.Wrapf(err, "authorize: invalid token"),
http.StatusUnauthorized, errContext} http.StatusUnauthorized, errContext}

View file

@ -121,7 +121,7 @@ func TestAuthorize(t *testing.T) {
return &authorizeTest{ return &authorizeTest{
auth: a, auth: a,
ott: raw, ott: raw,
err: &apiError{errors.New("authorize: provisioner with KeyID foo not found"), err: &apiError{errors.New("authorize: provisioner with id step-cli:foo not found"),
http.StatusUnauthorized, context{"ott": raw}}, http.StatusUnauthorized, context{"ott": raw}},
} }
}, },
@ -132,7 +132,7 @@ func TestAuthorize(t *testing.T) {
(&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", "foo")) (&jose.SignerOptions{}).WithType("JWT").WithHeader("kid", "foo"))
assert.FatalError(t, err) assert.FatalError(t, err)
_a.provisionerIDIndex.Store("foo", "42") _a.provisionerIDIndex.Store(validIssuer+":foo", "42")
cl := jwt.Claims{ cl := jwt.Claims{
Subject: "test.smallstep.com", Subject: "test.smallstep.com",
@ -164,7 +164,7 @@ func TestAuthorize(t *testing.T) {
return &authorizeTest{ return &authorizeTest{
auth: a, auth: a,
ott: raw, ott: raw,
err: &apiError{errors.New("authorize: invalid token"), err: &apiError{errors.New("authorize: provisioner with id invalid-issuer:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc not found"),
http.StatusUnauthorized, context{"ott": raw}}, http.StatusUnauthorized, context{"ott": raw}},
} }
}, },

View file

@ -19,12 +19,12 @@ func TestConfigValidate(t *testing.T) {
ac := &AuthConfig{ ac := &AuthConfig{
Provisioners: []*Provisioner{ Provisioners: []*Provisioner{
{ {
Issuer: "Max", Name: "Max",
Type: "JWK", Type: "JWK",
Key: maxjwk, Key: maxjwk,
}, },
{ {
Issuer: "step-cli", Name: "step-cli",
Type: "JWK", Type: "JWK",
Key: clijwk, Key: clijwk,
}, },
@ -217,12 +217,12 @@ func TestAuthConfigValidate(t *testing.T) {
assert.FatalError(t, err) assert.FatalError(t, err)
p := []*Provisioner{ p := []*Provisioner{
{ {
Issuer: "Max", Name: "Max",
Type: "JWK", Type: "JWK",
Key: maxjwk, Key: maxjwk,
}, },
{ {
Issuer: "step-cli", Name: "step-cli",
Type: "JWK", Type: "JWK",
Key: clijwk, Key: clijwk,
}, },
@ -250,8 +250,8 @@ func TestAuthConfigValidate(t *testing.T) {
return AuthConfigValidateTest{ return AuthConfigValidateTest{
ac: &AuthConfig{ ac: &AuthConfig{
Provisioners: []*Provisioner{ Provisioners: []*Provisioner{
{Issuer: "foo", Type: "bar", Key: &jose.JSONWebKey{}}, {Name: "foo", Type: "bar", Key: &jose.JSONWebKey{}},
{Issuer: "foo", Key: &jose.JSONWebKey{}}, {Name: "foo", Key: &jose.JSONWebKey{}},
}, },
}, },
err: errors.New("provisioner type cannot be empty"), err: errors.New("provisioner type cannot be empty"),

View file

@ -85,7 +85,7 @@ func (pc *ProvisionerClaims) Validate() error {
// Provisioner - authorized entity that can sign tokens necessary for signature requests. // Provisioner - authorized entity that can sign tokens necessary for signature requests.
type Provisioner struct { type Provisioner struct {
Issuer string `json:"issuer,omitempty"` Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Key *jose.JSONWebKey `json:"key,omitempty"` Key *jose.JSONWebKey `json:"key,omitempty"`
EncryptedKey string `json:"encryptedKey,omitempty"` EncryptedKey string `json:"encryptedKey,omitempty"`
@ -95,7 +95,7 @@ type Provisioner struct {
// Init initializes and validates a the fields of Provisioner type. // Init initializes and validates a the fields of Provisioner type.
func (p *Provisioner) Init(global *ProvisionerClaims) error { func (p *Provisioner) Init(global *ProvisionerClaims) error {
switch { switch {
case p.Issuer == "": case p.Name == "":
return errors.New("provisioner issuer cannot be empty") return errors.New("provisioner issuer cannot be empty")
case p.Type == "": case p.Type == "":
@ -117,7 +117,7 @@ func (p *Provisioner) getTLSApps(so SignOptions) ([]x509util.WithOption, []certC
return []x509util.WithOption{ return []x509util.WithOption{
x509util.WithNotBeforeAfterDuration(so.NotBefore, x509util.WithNotBeforeAfterDuration(so.NotBefore,
so.NotAfter, c.DefaultTLSCertDuration()), so.NotAfter, c.DefaultTLSCertDuration()),
withProvisionerOID(p.Issuer, p.Key.KeyID), withProvisionerOID(p.Name, p.Key.KeyID),
}, []certClaim{ }, []certClaim{
&certTemporalClaim{ &certTemporalClaim{
min: c.MinTLSCertDuration(), min: c.MinTLSCertDuration(),
@ -125,3 +125,9 @@ func (p *Provisioner) getTLSApps(so SignOptions) ([]x509util.WithOption, []certC
}, },
}, nil }, nil
} }
// ID returns the provisioner identifier. The name and credential id should
// uniquely identify any provisioner.
func (p *Provisioner) ID() string {
return p.Name + ":" + p.Key.KeyID
}

View file

@ -22,19 +22,19 @@ func TestProvisionerInit(t *testing.T) {
}, },
"fail-empty-type": func(t *testing.T) ProvisionerValidateTest { "fail-empty-type": func(t *testing.T) ProvisionerValidateTest {
return ProvisionerValidateTest{ return ProvisionerValidateTest{
p: &Provisioner{Issuer: "foo"}, p: &Provisioner{Name: "foo"},
err: errors.New("provisioner type cannot be empty"), err: errors.New("provisioner type cannot be empty"),
} }
}, },
"fail-empty-key": func(t *testing.T) ProvisionerValidateTest { "fail-empty-key": func(t *testing.T) ProvisionerValidateTest {
return ProvisionerValidateTest{ return ProvisionerValidateTest{
p: &Provisioner{Issuer: "foo", Type: "bar"}, p: &Provisioner{Name: "foo", Type: "bar"},
err: errors.New("provisioner key cannot be empty"), err: errors.New("provisioner key cannot be empty"),
} }
}, },
"ok": func(t *testing.T) ProvisionerValidateTest { "ok": func(t *testing.T) ProvisionerValidateTest {
return ProvisionerValidateTest{ return ProvisionerValidateTest{
p: &Provisioner{Issuer: "foo", Type: "bar", Key: &jose.JSONWebKey{}}, p: &Provisioner{Name: "foo", Type: "bar", Key: &jose.JSONWebKey{}},
} }
}, },
} }

View file

@ -75,7 +75,7 @@ func TestGetEncryptedKey(t *testing.T) {
} }
} else { } else {
if assert.Nil(t, tc.err) { if assert.Nil(t, tc.err) {
val, ok := tc.a.provisionerIDIndex.Load(tc.kid) val, ok := tc.a.provisionerIDIndex.Load("max:" + tc.kid)
assert.Fatal(t, ok) assert.Fatal(t, ok)
p, ok := val.(*Provisioner) p, ok := val.(*Provisioner)
assert.Fatal(t, ok) assert.Fatal(t, ok)
@ -155,7 +155,7 @@ func generateProvisioner(t *testing.T) *Provisioner {
encrypted, err := jwe.CompactSerialize() encrypted, err := jwe.CompactSerialize()
assert.FatalError(t, err) assert.FatalError(t, err)
return &Provisioner{ return &Provisioner{
Issuer: issuer, Name: issuer,
Type: "JWT", Type: "JWT",
Key: &public, Key: &public,
EncryptedKey: encrypted, EncryptedKey: encrypted,

View file

@ -204,7 +204,7 @@ func TestSign(t *testing.T) {
_, err := asn1.Unmarshal(ext.Value, &val) _, err := asn1.Unmarshal(ext.Value, &val)
assert.FatalError(t, err) assert.FatalError(t, err)
assert.Equals(t, val.Type, provisionerTypeJWK) assert.Equals(t, val.Type, provisionerTypeJWK)
assert.Equals(t, val.Name, []byte(p.Issuer)) assert.Equals(t, val.Name, []byte(p.Name))
assert.Equals(t, val.CredentialID, []byte(p.Key.KeyID)) assert.Equals(t, val.CredentialID, []byte(p.Key.KeyID))
} }
assert.Equals(t, found, 1) assert.Equals(t, found, 1)

10
ca/testdata/ca.json vendored
View file

@ -20,7 +20,7 @@
"minCertDuration": "1m", "minCertDuration": "1m",
"provisioners": [ "provisioners": [
{ {
"issuer": "max", "name": "max",
"type": "jwk", "type": "jwk",
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IkpsNkZLWUp4V1UwdGRIbG9UanA1aGcifQ.Qy0EP6u5-t0ggOweoc3Z1DCzR5BllsQi.KUkviZ_TJKY4c0Mi.h7QZqgh_Fl2MZpmVy4h375yC0DORjB1dQULbNqc6MuUCW2iweWVRysFImUXiXMUKRarJC5adwWy1GhyAqUj6Xj1iOZDGLjYnqMETGWcI0rKDBwcSU7y7Y-2VYBRDSM2b7aWtTBfz3_kvEaw_vc3b5CEPJ86UlZc-jhKFRr_IcGWU-vXX5-bppoH15IPreyzi55YdjCll338lYpDecB_Paym3XBXotyd2iGXXUwoA1npEFwuyRMMEhl9zLp7rVcMW6A_32EzB8cZANEnA0C4FXGHQalY6u_2UeqxcC8_FuXPay6VIYODyRqcABvvkft3nwOcrI0pYDGBdk2w2Euk.kOAFq3Tg6s4vBGS_plMpSw", "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IkpsNkZLWUp4V1UwdGRIbG9UanA1aGcifQ.Qy0EP6u5-t0ggOweoc3Z1DCzR5BllsQi.KUkviZ_TJKY4c0Mi.h7QZqgh_Fl2MZpmVy4h375yC0DORjB1dQULbNqc6MuUCW2iweWVRysFImUXiXMUKRarJC5adwWy1GhyAqUj6Xj1iOZDGLjYnqMETGWcI0rKDBwcSU7y7Y-2VYBRDSM2b7aWtTBfz3_kvEaw_vc3b5CEPJ86UlZc-jhKFRr_IcGWU-vXX5-bppoH15IPreyzi55YdjCll338lYpDecB_Paym3XBXotyd2iGXXUwoA1npEFwuyRMMEhl9zLp7rVcMW6A_32EzB8cZANEnA0C4FXGHQalY6u_2UeqxcC8_FuXPay6VIYODyRqcABvvkft3nwOcrI0pYDGBdk2w2Euk.kOAFq3Tg6s4vBGS_plMpSw",
"key": { "key": {
@ -33,7 +33,7 @@
"y": "ZhYcFQBqtErdC_pA7sOXrO7AboCEPIKP9Ik4CHJqANk" "y": "ZhYcFQBqtErdC_pA7sOXrO7AboCEPIKP9Ik4CHJqANk"
} }
}, { }, {
"issuer": "max", "name": "max",
"type": "jwk", "type": "jwk",
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlZsWnl0dUxrWTR5enlqZXJybnN0aGcifQ.QP15wQYjZ12BLgl-XTq2Vb12G3OHAfic.X35QqAaXwnlmeCUU._2qIUp0TI8yDI7c2e9upIRdrnmB5OvtLfrYN-Su2NLBpaoYtr9O55Wo0Iryc0W2pYqnVDPvgPPes4P4nQAnzw5WhFYc1Xf1ZEetfdNhwi1x2FNwPbACBAgxm5AW40O5AAlbLcWushYASfeMBZocTGXuSGUzwFqoWD-5EDJ80TWQ7cAj3ttHrJ_3QV9hi4O9KJUCiXngN-Yz2zXrhBL4NOH2fmRbaf5c0rF8xUJIIW-TcyYJeX_Fbx1IzzKKPd9USUwkDhxD4tLa51I345xVqjuwG1PEn6nF8JKqLRVUKEKFin-ShXrfE61KceyAvm4YhWKrbJWIm3bH5Hxaphy4.TexIrIhsRxJStpE3EJ925Q", "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlZsWnl0dUxrWTR5enlqZXJybnN0aGcifQ.QP15wQYjZ12BLgl-XTq2Vb12G3OHAfic.X35QqAaXwnlmeCUU._2qIUp0TI8yDI7c2e9upIRdrnmB5OvtLfrYN-Su2NLBpaoYtr9O55Wo0Iryc0W2pYqnVDPvgPPes4P4nQAnzw5WhFYc1Xf1ZEetfdNhwi1x2FNwPbACBAgxm5AW40O5AAlbLcWushYASfeMBZocTGXuSGUzwFqoWD-5EDJ80TWQ7cAj3ttHrJ_3QV9hi4O9KJUCiXngN-Yz2zXrhBL4NOH2fmRbaf5c0rF8xUJIIW-TcyYJeX_Fbx1IzzKKPd9USUwkDhxD4tLa51I345xVqjuwG1PEn6nF8JKqLRVUKEKFin-ShXrfE61KceyAvm4YhWKrbJWIm3bH5Hxaphy4.TexIrIhsRxJStpE3EJ925Q",
"key": { "key": {
@ -46,7 +46,7 @@
"y": "wnqZSMuXpmUxORq20t83LyY4BDYmqDGV9P7FGR6mw84" "y": "wnqZSMuXpmUxORq20t83LyY4BDYmqDGV9P7FGR6mw84"
} }
}, { }, {
"issuer": "step-cli", "name": "step-cli",
"type": "jwk", "type": "jwk",
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg", "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlhOdmYxQjgxSUlLMFA2NUkwcmtGTGcifQ.XaN9zcPQeWt49zchUDm34FECUTHfQTn_.tmNHPQDqR3ebsWfd.9WZr3YVdeOyJh36vvx0VlRtluhvYp4K7jJ1KGDr1qypwZ3ziBVSNbYYQ71du7fTtrnfG1wgGTVR39tWSzBU-zwQ5hdV3rpMAaEbod5zeW6SHd95H3Bvcb43YiiqJFNL5sGZzFb7FqzVmpsZ1efiv6sZaGDHtnCAL6r12UG5EZuqGfM0jGCZitUz2m9TUKXJL5DJ7MOYbFfkCEsUBPDm_TInliSVn2kMJhFa0VOe5wZk5YOuYM3lNYW64HGtbf-llN2Xk-4O9TfeSPizBx9ZqGpeu8pz13efUDT2WL9tWo6-0UE-CrG0bScm8lFTncTkHcu49_a5NaUBkYlBjEiw.thPcx3t1AUcWuEygXIY3Fg",
"key": { "key": {
@ -59,7 +59,7 @@
"y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y" "y": "sQr2JdzwD2fgyrymBEXWsxDxFNjjqN64qLLSbLdLZ9Y"
} }
}, { }, {
"issuer": "mariano", "name": "mariano",
"type": "jwk", "type": "jwk",
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlB1UnJVQ1RZZkR1T2F5MEh2cGl6bncifQ.7a-OP5xWGbFra8m2MN9YuLGt6v4y0wmB.u-54daK2y-0UO9na.3GQy6E52-fOSUu5NJ_sEbxj_T3CTyWb7wOPFv2oI2PBWXp5CLpiWJbCFpF4v2oD9fN5XbxMP14ootbrFjATnoMWfWgyLwG-KOj9BqMGNxhG2v37yC7Wrris6s30nrPa3uyNEYZ12AOQW1K04cU2X0u_qJM3vzMCle548ZFTWs6_d6L8lp3o0F9MEbCmJ4p6CLqQxjxYtn1aD79lM91NbIXpRP3iUFQRly-y_iC2mSkXCdd_cQ6-dqLUchXwWRyVO5nBHb4J87aZ91VApw7ldTLtwRZ2ZGJpqGQGgjTwi4sgjEcMuGg0_83XGk2ubdlKDpmGFedOHS5rYCbxotts.vSYfxsi2UU9LQeySDjAnnQ", "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6IlB1UnJVQ1RZZkR1T2F5MEh2cGl6bncifQ.7a-OP5xWGbFra8m2MN9YuLGt6v4y0wmB.u-54daK2y-0UO9na.3GQy6E52-fOSUu5NJ_sEbxj_T3CTyWb7wOPFv2oI2PBWXp5CLpiWJbCFpF4v2oD9fN5XbxMP14ootbrFjATnoMWfWgyLwG-KOj9BqMGNxhG2v37yC7Wrris6s30nrPa3uyNEYZ12AOQW1K04cU2X0u_qJM3vzMCle548ZFTWs6_d6L8lp3o0F9MEbCmJ4p6CLqQxjxYtn1aD79lM91NbIXpRP3iUFQRly-y_iC2mSkXCdd_cQ6-dqLUchXwWRyVO5nBHb4J87aZ91VApw7ldTLtwRZ2ZGJpqGQGgjTwi4sgjEcMuGg0_83XGk2ubdlKDpmGFedOHS5rYCbxotts.vSYfxsi2UU9LQeySDjAnnQ",
"key": { "key": {
@ -75,7 +75,7 @@
"minTLSCertDuration": "30s" "minTLSCertDuration": "30s"
} }
}, { }, {
"issuer": "mariano", "name": "mariano",
"type": "jwk", "type": "jwk",
"encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6Ik5SLTk5ZkVMSm1CLW1FZGllUlFFc3cifQ.Fr314BEUGTda4ICJl2uxFdjpEUGGqJEV.gBbu_DZE1ONDu14r.X-7MKMyokZIF1HTCVqqL0tTWgaC1ZGZBLLltd11ZUhQTswo_8kvgiTv3cFShj7ATF0tAY8HStyJmzLO8mKPVOPDXSwjdNsPriZclI6JWGi9iOu8pEiN9pZM6-itxan1JMcDUNg2U-P1BmKppHRbDKsOTivymfRyeUk51dBIlS54p5xNK1HFLc1YtWC1Rc_ngYVqOgqlhIrCHArAEBe3jrfUaH2ym-8fkVdwVqtxmte3XXK9g8FchsygRNnOKtRcr0TyzTUV-7bPi8_t02Zi-EHLFaSawVXWV_Qk1GeLYJR22Rp74beo-b5-lCNVp10btO0xdGySUWmCJ4v4_QZw.c8unwWycwtfdJMM_0b0fuA", "encryptedKey": "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIiwicDJjIjoxMDAwMDAsInAycyI6Ik5SLTk5ZkVMSm1CLW1FZGllUlFFc3cifQ.Fr314BEUGTda4ICJl2uxFdjpEUGGqJEV.gBbu_DZE1ONDu14r.X-7MKMyokZIF1HTCVqqL0tTWgaC1ZGZBLLltd11ZUhQTswo_8kvgiTv3cFShj7ATF0tAY8HStyJmzLO8mKPVOPDXSwjdNsPriZclI6JWGi9iOu8pEiN9pZM6-itxan1JMcDUNg2U-P1BmKppHRbDKsOTivymfRyeUk51dBIlS54p5xNK1HFLc1YtWC1Rc_ngYVqOgqlhIrCHArAEBe3jrfUaH2ym-8fkVdwVqtxmte3XXK9g8FchsygRNnOKtRcr0TyzTUV-7bPi8_t02Zi-EHLFaSawVXWV_Qk1GeLYJR22Rp74beo-b5-lCNVp10btO0xdGySUWmCJ4v4_QZw.c8unwWycwtfdJMM_0b0fuA",
"key": { "key": {