Skip to content

Commit

Permalink
Run JWKS refresh as part of the program group
Browse files Browse the repository at this point in the history
  • Loading branch information
mortenmj committed Oct 8, 2023
1 parent 0de767a commit 76aa95b
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 27 deletions.
9 changes: 5 additions & 4 deletions pkg/grpc/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/buildbarn/bb-storage/pkg/auth"
"github.com/buildbarn/bb-storage/pkg/clock"
"github.com/buildbarn/bb-storage/pkg/jwt"
"github.com/buildbarn/bb-storage/pkg/program"
configuration "github.com/buildbarn/bb-storage/pkg/proto/configuration/grpc"
"github.com/buildbarn/bb-storage/pkg/util"
"github.com/jmespath/go-jmespath"
Expand All @@ -24,7 +25,7 @@ type Authenticator interface {

// NewAuthenticatorFromConfiguration creates a tree of Authenticator
// objects based on a configuration file.
func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolicy) (Authenticator, bool, error) {
func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolicy, group program.Group) (Authenticator, bool, error) {
if policy == nil {
return nil, false, status.Error(codes.InvalidArgument, "Authentication policy not specified")
}
Expand All @@ -39,7 +40,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
children := make([]Authenticator, 0, len(policyKind.Any.Policies))
needsPeerTransportCredentials := false
for _, childConfiguration := range policyKind.Any.Policies {
child, childNeedsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(childConfiguration)
child, childNeedsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(childConfiguration, group)
if err != nil {
return nil, false, err
}
Expand All @@ -51,7 +52,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
children := make([]Authenticator, 0, len(policyKind.All.Policies))
needsPeerTransportCredentials := false
for _, childConfiguration := range policyKind.All.Policies {
child, childNeedsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(childConfiguration)
child, childNeedsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(childConfiguration, group)
if err != nil {
return nil, false, err
}
Expand Down Expand Up @@ -81,7 +82,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
metadataExtractor,
), false, nil
case *configuration.AuthenticationPolicy_Jwt:
authorizationHeaderParser, err := jwt.NewAuthorizationHeaderParserFromConfiguration(policyKind.Jwt)
authorizationHeaderParser, err := jwt.NewAuthorizationHeaderParserFromConfiguration(policyKind.Jwt, group)
if err != nil {
return nil, false, util.StatusWrap(err, "Failed to create authorization header parser for JWT authentication policy")
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func init() {
func NewServersFromConfigurationAndServe(configurations []*configuration.ServerConfiguration, registrationFunc func(grpc.ServiceRegistrar), group program.Group) error {
for _, configuration := range configurations {
// Create an authenticator for requests.
authenticator, needsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(configuration.AuthenticationPolicy)
authenticator, needsPeerTransportCredentials, err := NewAuthenticatorFromConfiguration(configuration.AuthenticationPolicy, group)
if err != nil {
return err
}
Expand Down
9 changes: 5 additions & 4 deletions pkg/http/authenticator.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/buildbarn/bb-storage/pkg/auth"
"github.com/buildbarn/bb-storage/pkg/clock"
"github.com/buildbarn/bb-storage/pkg/jwt"
"github.com/buildbarn/bb-storage/pkg/program"
configuration "github.com/buildbarn/bb-storage/pkg/proto/configuration/http"
"github.com/buildbarn/bb-storage/pkg/random"
"github.com/buildbarn/bb-storage/pkg/util"
Expand All @@ -30,7 +31,7 @@ type Authenticator interface {

// NewAuthenticatorFromConfiguration creates a tree of Authenticator
// objects based on a configuration file.
func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolicy) (Authenticator, error) {
func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolicy, group program.Group) (Authenticator, error) {
if policy == nil {
return nil, status.Error(codes.InvalidArgument, "Authentication policy not specified")
}
Expand All @@ -44,7 +45,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
case *configuration.AuthenticationPolicy_Any:
children := make([]Authenticator, 0, len(policyKind.Any.Policies))
for _, childConfiguration := range policyKind.Any.Policies {
child, err := NewAuthenticatorFromConfiguration(childConfiguration)
child, err := NewAuthenticatorFromConfiguration(childConfiguration, group)
if err != nil {
return nil, err
}
Expand All @@ -54,7 +55,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
case *configuration.AuthenticationPolicy_Deny:
return NewDenyAuthenticator(policyKind.Deny), nil
case *configuration.AuthenticationPolicy_Jwt:
authorizationHeaderParser, err := jwt.NewAuthorizationHeaderParserFromConfiguration(policyKind.Jwt)
authorizationHeaderParser, err := jwt.NewAuthorizationHeaderParserFromConfiguration(policyKind.Jwt, group)
if err != nil {
return nil, util.StatusWrap(err, "Failed to create authorization header parser for JWT authentication policy")
}
Expand Down Expand Up @@ -118,7 +119,7 @@ func NewAuthenticatorFromConfiguration(policy *configuration.AuthenticationPolic
cookieAEAD,
clock.SystemClock)
case *configuration.AuthenticationPolicy_AcceptHeader:
base, err := NewAuthenticatorFromConfiguration(policyKind.AcceptHeader.Policy)
base, err := NewAuthenticatorFromConfiguration(policyKind.AcceptHeader.Policy, group)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
// canceled.
func NewServersFromConfigurationAndServe(configurations []*configuration.ServerConfiguration, handler http.Handler, group program.Group) error {
for _, configuration := range configurations {
authenticator, err := NewAuthenticatorFromConfiguration(configuration.AuthenticationPolicy)
authenticator, err := NewAuthenticatorFromConfiguration(configuration.AuthenticationPolicy, group)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions pkg/jwt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ go_library(
"//pkg/auth",
"//pkg/clock",
"//pkg/eviction",
"//pkg/program",
"//pkg/proto/configuration/jwt",
"//pkg/random",
"//pkg/util",
Expand Down
41 changes: 24 additions & 17 deletions pkg/jwt/configuration.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package jwt

import (
"context"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"encoding/json"
"log"
"os"
"reflect"
"time"

"github.com/buildbarn/bb-storage/pkg/clock"
"github.com/buildbarn/bb-storage/pkg/eviction"
"github.com/buildbarn/bb-storage/pkg/program"
configuration "github.com/buildbarn/bb-storage/pkg/proto/configuration/jwt"
"github.com/buildbarn/bb-storage/pkg/util"
jose "github.com/go-jose/go-jose/v3"
Expand All @@ -25,7 +26,7 @@ import (
// NewAuthorizationHeaderParserFromConfiguration creates a new HTTP
// "Authorization" header parser based on options stored in a
// configuration file.
func NewAuthorizationHeaderParserFromConfiguration(config *configuration.AuthorizationHeaderParserConfiguration) (*AuthorizationHeaderParser, error) {
func NewAuthorizationHeaderParserFromConfiguration(config *configuration.AuthorizationHeaderParserConfiguration, group program.Group) (*AuthorizationHeaderParser, error) {
var signatureValidator SignatureValidator

switch key := config.Jwks.(type) {
Expand All @@ -43,7 +44,11 @@ func NewAuthorizationHeaderParserFromConfiguration(config *configuration.Authori
return nil, err
}
case *configuration.AuthorizationHeaderParserConfiguration_JwksFile:
signatureValidator = NewSignatureValidatorFromJSONWebKeySetFile(key.JwksFile)
var err error
signatureValidator, err = NewSignatureValidatorFromJSONWebKeySetFile(key.JwksFile, group)
if err != nil {
return nil, err
}
default:
return nil, status.Error(codes.InvalidArgument, "No key type provided")
}
Expand Down Expand Up @@ -119,27 +124,29 @@ func NewSignatureValidatorFromJSONWebKeySet(jwks *jose.JSONWebKeySet) (Signature
// SignatureValidator capable of validating JWTs matching keys contained
// in a JSON Web Key Set read from a file. The content of the file is
// periodically refreshed.
func NewSignatureValidatorFromJSONWebKeySetFile(path string) (SignatureValidator, error) {
func NewSignatureValidatorFromJSONWebKeySetFile(path string, group program.Group) (SignatureValidator, error) {
internalValidator, err := getJwksFromFile(path)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "Unable to read JWKS content from file at %s", path)
}
forwardingValidator := NewForwardingSignatureValidator(internalValidator)

// TODO: Run this as part of the program.Group, so that it gets
// cleaned up upon shutdown.
go func() {
group.Go(func(ctx context.Context, siblingsGroup, dependenciesGroup program.Group) error {
t := time.NewTicker(300 * time.Second)
for range t.C {
internalValidator, err := getJwksFromFile(path)
if err != nil {
log.Printf("Failed to get JWKS content from file: %v", err)
continue
}

forwardingValidator.Replace(internalValidator)
}
}()
for {
select {
case <-t.C:
internalValidator, err := getJwksFromFile(path)
if err != nil {
return err
}

forwardingValidator.Replace(internalValidator)
case <-ctx.Done():
return util.StatusFromContext(ctx)
}
}
})

return forwardingValidator, nil
}
Expand Down

0 comments on commit 76aa95b

Please sign in to comment.