forked from TrueCloudLab/certificates
Validate audiences in the default provisioner.
This commit is contained in:
parent
33c1449360
commit
2d00cd0933
6 changed files with 50 additions and 30 deletions
|
@ -4,7 +4,6 @@ import (
|
|||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -25,7 +24,6 @@ type Authority struct {
|
|||
ottMap *sync.Map
|
||||
startTime time.Time
|
||||
provisioners *provisioner.Collection
|
||||
audiences []string
|
||||
// Do not re-initialize
|
||||
initOnce bool
|
||||
}
|
||||
|
@ -37,19 +35,11 @@ func New(config *Config) (*Authority, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// Define audiences: legacy + possible urls without the ports.
|
||||
// The CA might have proxies in front so we cannot rely on the port.
|
||||
audiences := []string{legacyAuthority}
|
||||
for _, name := range config.DNSNames {
|
||||
audiences = append(audiences, fmt.Sprintf("https://%s/sign", name), fmt.Sprintf("https://%s/1.0/sign", name))
|
||||
}
|
||||
|
||||
var a = &Authority{
|
||||
config: config,
|
||||
certificates: new(sync.Map),
|
||||
ottMap: new(sync.Map),
|
||||
provisioners: provisioner.NewCollection(audiences),
|
||||
audiences: audiences,
|
||||
provisioners: provisioner.NewCollection(config.getAudiences()),
|
||||
}
|
||||
if err := a.init(); err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -84,7 +84,7 @@ func (a *Authority) Authorize(ott string) ([]provisioner.SignOption, error) {
|
|||
// This method will also validate the audiences for JWK provisioners.
|
||||
p, ok := a.provisioners.LoadByToken(token, &claims.Claims)
|
||||
if !ok {
|
||||
return nil, &apiError{errors.Errorf("authorize: provisioner not found"),
|
||||
return nil, &apiError{errors.New("authorize: provisioner not found or invalid audience"),
|
||||
http.StatusUnauthorized, errContext}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package authority
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
|
@ -58,9 +59,8 @@ type AuthConfig struct {
|
|||
}
|
||||
|
||||
// Validate validates the authority configuration.
|
||||
func (c *AuthConfig) Validate() error {
|
||||
func (c *AuthConfig) Validate(audiences []string) error {
|
||||
var err error
|
||||
|
||||
if c == nil {
|
||||
return errors.New("authority cannot be undefined")
|
||||
}
|
||||
|
@ -71,11 +71,18 @@ func (c *AuthConfig) Validate() error {
|
|||
if c.Claims, err = c.Claims.Init(&globalProvisionerClaims); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize provisioners
|
||||
config := provisioner.Config{
|
||||
Claims: *c.Claims,
|
||||
Audiences: audiences,
|
||||
}
|
||||
for _, p := range c.Provisioners {
|
||||
if err := p.Init(c.Claims); err != nil {
|
||||
if err := p.Init(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.Template == nil {
|
||||
c.Template = &x509util.ASN1DN{}
|
||||
}
|
||||
|
@ -154,5 +161,16 @@ func (c *Config) Validate() error {
|
|||
c.TLS.Renegotiation = c.TLS.Renegotiation || DefaultTLSOptions.Renegotiation
|
||||
}
|
||||
|
||||
return c.AuthorityConfig.Validate()
|
||||
return c.AuthorityConfig.Validate(c.getAudiences())
|
||||
}
|
||||
|
||||
// getAudiences returns the legacy and possible urls without the ports that will
|
||||
// be used as the default provisioner audiences. The CA might have proxies in
|
||||
// front so we cannot rely on the port.
|
||||
func (c *Config) getAudiences() []string {
|
||||
audiences := []string{legacyAuthority}
|
||||
for _, name := range c.DNSNames {
|
||||
audiences = append(audiences, fmt.Sprintf("https://%s/sign", name), fmt.Sprintf("https://%s/1.0/sign", name))
|
||||
}
|
||||
return audiences
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ type JWT struct {
|
|||
Key *jose.JSONWebKey `json:"key,omitempty"`
|
||||
EncryptedKey string `json:"encryptedKey,omitempty"`
|
||||
Claims *Claims `json:"claims,omitempty"`
|
||||
audiences []string
|
||||
}
|
||||
|
||||
// GetID returns the provisioner unique identifier. The name and credential id
|
||||
|
@ -47,7 +48,7 @@ func (p *JWT) GetEncryptedKey() (string, string, bool) {
|
|||
}
|
||||
|
||||
// Init initializes and validates a the fields of Provisioner type.
|
||||
func (p *JWT) Init(global *Claims) (err error) {
|
||||
func (p *JWT) Init(config Config) (err error) {
|
||||
switch {
|
||||
case p.Name == "":
|
||||
return errors.New("provisioner name cannot be empty")
|
||||
|
@ -58,10 +59,12 @@ func (p *JWT) Init(global *Claims) (err error) {
|
|||
case p.Key == nil:
|
||||
return errors.New("provisioner key cannot be empty")
|
||||
}
|
||||
p.Claims, err = p.Claims.Init(global)
|
||||
p.Claims, err = p.Claims.Init(&config.Claims)
|
||||
p.audiences = config.Audiences
|
||||
return err
|
||||
}
|
||||
|
||||
// Authorize validates the given token.
|
||||
func (p *JWT) Authorize(token string) ([]SignOption, error) {
|
||||
jwt, err := jose.ParseSigned(token)
|
||||
if err != nil {
|
||||
|
@ -81,10 +84,10 @@ func (p *JWT) Authorize(token string) ([]SignOption, error) {
|
|||
return nil, errors.Wrapf(err, "invalid token")
|
||||
}
|
||||
|
||||
// if !matchesAudience(claims.Audience, a.audiences) {
|
||||
// return nil, &apiError{errors.New("authorize: token audience invalid"), http.StatusUnauthorized,
|
||||
// errContext}
|
||||
// }
|
||||
// validate audiences with the defaults
|
||||
if !matchesAudience(claims.Audience, p.audiences) {
|
||||
return nil, errors.New("invalid token: invalid audience claim (aud)")
|
||||
}
|
||||
|
||||
if claims.Subject == "" {
|
||||
return nil, errors.New("token subject cannot be empty")
|
||||
|
|
|
@ -73,7 +73,7 @@ func (o *OIDC) GetEncryptedKey() (kid string, key string, ok bool) {
|
|||
}
|
||||
|
||||
// Init validates and initializes the OIDC provider.
|
||||
func (o *OIDC) Init(global *Claims) (err error) {
|
||||
func (o *OIDC) Init(config Config) (err error) {
|
||||
switch {
|
||||
case o.Name == "":
|
||||
return errors.New("name cannot be empty")
|
||||
|
@ -84,7 +84,7 @@ func (o *OIDC) Init(global *Claims) (err error) {
|
|||
}
|
||||
|
||||
// Update claims with global ones
|
||||
if o.Claims, err = o.Claims.Init(global); err != nil {
|
||||
if o.Claims, err = o.Claims.Init(&config.Claims); err != nil {
|
||||
return err
|
||||
}
|
||||
// Decode openid-configuration endpoint
|
||||
|
|
|
@ -14,7 +14,7 @@ type Interface interface {
|
|||
GetName() string
|
||||
GetType() Type
|
||||
GetEncryptedKey() (kid string, key string, ok bool)
|
||||
Init(claims *Claims) error
|
||||
Init(config Config) error
|
||||
Authorize(token string) ([]SignOption, error)
|
||||
AuthorizeRenewal(cert *x509.Certificate) error
|
||||
AuthorizeRevoke(token string) error
|
||||
|
@ -31,11 +31,20 @@ const (
|
|||
TypeOIDC Type = 2
|
||||
)
|
||||
|
||||
// Config defines the default parameters used in the initialization of
|
||||
// provisioners.
|
||||
type Config struct {
|
||||
// Claims are the default claims.
|
||||
Claims Claims
|
||||
// Audiences are the audiences used in the default provisioner, (JWK).
|
||||
Audiences []string
|
||||
}
|
||||
|
||||
type provisioner struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Provisioner implmements the provisioner.Interface on a base provisioner. It
|
||||
// Provisioner implements the provisioner.Interface on a base provisioner. It
|
||||
// also implements custom marshalers and unmarshalers so different provisioners
|
||||
// can be represented in a configuration type.
|
||||
type Provisioner struct {
|
||||
|
@ -76,8 +85,8 @@ func (p *Provisioner) GetType() Type {
|
|||
}
|
||||
|
||||
// Init initializes the base provisioner with the given claims.
|
||||
func (p *Provisioner) Init(claims *Claims) error {
|
||||
return p.base.Init(claims)
|
||||
func (p *Provisioner) Init(c Config) error {
|
||||
return p.base.Init(c)
|
||||
}
|
||||
|
||||
// Authorize validates the given token on the base provisioner returning a list
|
||||
|
@ -107,7 +116,7 @@ func (p *Provisioner) MarshalJSON() ([]byte, error) {
|
|||
func (p *Provisioner) UnmarshalJSON(data []byte) error {
|
||||
var typ provisioner
|
||||
if err := json.Unmarshal(data, &typ); err != nil {
|
||||
return errors.Errorf("error unmarshalling provisioner")
|
||||
return errors.Errorf("error unmarshaling provisioner")
|
||||
}
|
||||
|
||||
switch strings.ToLower(typ.Type) {
|
||||
|
@ -119,7 +128,7 @@ func (p *Provisioner) UnmarshalJSON(data []byte) error {
|
|||
return errors.Errorf("provisioner type %s not supported", typ.Type)
|
||||
}
|
||||
if err := json.Unmarshal(data, &p.base); err != nil {
|
||||
return errors.Errorf("error unmarshalling provisioner")
|
||||
return errors.Errorf("error unmarshaling provisioner")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue