forked from TrueCloudLab/certificates
Add support for lifetime.
This commit is contained in:
parent
ae4b8f58b8
commit
7958f6ebb5
3 changed files with 91 additions and 3 deletions
|
@ -172,8 +172,9 @@ func (s *StepCAS) createCertificate(cr *x509.CertificateRequest, lifetime time.D
|
|||
}
|
||||
|
||||
resp, err := s.client.Sign(&api.SignRequest{
|
||||
CsrPEM: api.CertificateRequest{CertificateRequest: cr},
|
||||
OTT: token,
|
||||
CsrPEM: api.CertificateRequest{CertificateRequest: cr},
|
||||
OTT: token,
|
||||
NotAfter: s.lifetime(lifetime),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -203,3 +204,13 @@ func (s *StepCAS) revokeToken(subject string) (string, error) {
|
|||
|
||||
return "", errors.New("stepCAS does not have any provisioner configured")
|
||||
}
|
||||
|
||||
func (s *StepCAS) lifetime(d time.Duration) api.TimeDuration {
|
||||
if s.x5c != nil {
|
||||
d = s.x5c.Lifetime(d)
|
||||
}
|
||||
var td api.TimeDuration
|
||||
td.SetDuration(d)
|
||||
println(td.String(), d.String())
|
||||
return td
|
||||
}
|
||||
|
|
|
@ -17,6 +17,12 @@ import (
|
|||
|
||||
const defaultValidity = 5 * time.Minute
|
||||
|
||||
// timeNow returns the current time.
|
||||
// This method is used for unit testing purposes.
|
||||
var timeNow = func() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
type x5cIssuer struct {
|
||||
caURL *url.URL
|
||||
certFile string
|
||||
|
@ -58,6 +64,18 @@ func (i *x5cIssuer) RevokeToken(subject string) (string, error) {
|
|||
return i.createToken(aud, subject, nil)
|
||||
}
|
||||
|
||||
func (i *x5cIssuer) Lifetime(d time.Duration) time.Duration {
|
||||
cert, err := pemutil.ReadCertificate(i.certFile, pemutil.WithFirstBlock())
|
||||
if err != nil {
|
||||
return d
|
||||
}
|
||||
now := timeNow()
|
||||
if now.Add(d + time.Minute).After(cert.NotAfter) {
|
||||
return cert.NotAfter.Sub(now) - time.Minute
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
||||
signer, err := newX5CSigner(i.certFile, i.keyFile)
|
||||
if err != nil {
|
||||
|
@ -86,7 +104,7 @@ func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error)
|
|||
}
|
||||
|
||||
func defaultClaims(iss, sub, aud, id string) jose.Claims {
|
||||
now := time.Now()
|
||||
now := timeNow()
|
||||
return jose.Claims{
|
||||
ID: id,
|
||||
Issuer: iss,
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"go.step.sm/crypto/jose"
|
||||
)
|
||||
|
@ -25,6 +26,17 @@ func (b noneSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts)
|
|||
return digest, nil
|
||||
}
|
||||
|
||||
func fakeTime(t *testing.T) {
|
||||
t.Helper()
|
||||
tmp := timeNow
|
||||
t.Cleanup(func() {
|
||||
timeNow = tmp
|
||||
})
|
||||
timeNow = func() time.Time {
|
||||
return testX5CCrt.NotBefore
|
||||
}
|
||||
}
|
||||
|
||||
func Test_x5cIssuer_SignToken(t *testing.T) {
|
||||
caURL, err := url.Parse("https://ca.smallstep.com")
|
||||
if err != nil {
|
||||
|
@ -154,6 +166,53 @@ func Test_x5cIssuer_RevokeToken(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_x5cIssuer_Lifetime(t *testing.T) {
|
||||
fakeTime(t)
|
||||
caURL, err := url.Parse("https://ca.smallstep.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// With a leeway of 1m the max duration will be 59m.
|
||||
maxDuration := testX5CCrt.NotAfter.Sub(timeNow()) - time.Minute
|
||||
|
||||
type fields struct {
|
||||
caURL *url.URL
|
||||
certFile string
|
||||
keyFile string
|
||||
issuer string
|
||||
}
|
||||
type args struct {
|
||||
d time.Duration
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want time.Duration
|
||||
}{
|
||||
{"ok 0s", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{0}, 0},
|
||||
{"ok 1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{time.Minute}, time.Minute},
|
||||
{"ok max-1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration - time.Minute}, maxDuration - time.Minute},
|
||||
{"ok max", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration}, maxDuration},
|
||||
{"ok max+1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration + time.Minute}, maxDuration},
|
||||
{"ok fail", fields{caURL, testX5CPath + ".missing", testX5CKeyPath, "X5C"}, args{maxDuration + time.Minute}, maxDuration + time.Minute},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
i := &x5cIssuer{
|
||||
caURL: tt.fields.caURL,
|
||||
certFile: tt.fields.certFile,
|
||||
keyFile: tt.fields.keyFile,
|
||||
issuer: tt.fields.issuer,
|
||||
}
|
||||
if got := i.Lifetime(tt.args.d); got != tt.want {
|
||||
t.Errorf("x5cIssuer.Lifetime() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_newJoseSigner(t *testing.T) {
|
||||
mustSigner := func(args ...interface{}) crypto.Signer {
|
||||
if err := args[len(args)-1]; err != nil {
|
||||
|
|
Loading…
Reference in a new issue