Perform initialization of DPoP and OIDC options once

pull/1671/head
Herman Slatman 5 months ago
parent 79739e5073
commit 24795720e1
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F

@ -4309,7 +4309,7 @@ func Test_parseAndVerifyWireAccessToken(t *testing.T) {
key := `
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAB2IYqBWXAouDt3WcCZgCM3t9gumMEKMlgMsGenSu+fA=
-----END PUBLIC KEY-----` // TODO(hs): different format?
-----END PUBLIC KEY-----`
publicKey, err := pemutil.Parse([]byte(key))
require.NoError(t, err)
issuer := "http://wire.com:19983/clients/7a41cf5b79683410/access-token"

@ -3,7 +3,6 @@ package wire
import (
"bytes"
"crypto"
"errors"
"fmt"
"text/template"
@ -15,48 +14,32 @@ type DPOPOptions struct {
SigningKey []byte `json:"key"`
// URI template for the URI the ACME client must call to fetch the DPoP challenge proof (an access token from wire-server)
Target string `json:"target"`
}
func (o *DPOPOptions) GetSigningKey() crypto.PublicKey {
if o == nil {
return nil
}
k, err := pemutil.Parse(o.SigningKey) // TODO(hs): do this once?
if err != nil {
return nil
}
return k
signingKey crypto.PublicKey
target *template.Template
}
func (o *DPOPOptions) GetTarget() string {
if o == nil {
return ""
}
return o.Target
func (o *DPOPOptions) GetSigningKey() crypto.PublicKey {
return o.signingKey
}
func (o *DPOPOptions) EvaluateTarget(deviceID string) (string, error) {
if o == nil {
return "", errors.New("misconfigured target template configuration")
}
tmpl, err := template.New("DeviceID").Parse(o.GetTarget())
if err != nil {
return "", fmt.Errorf("failed parsing dpop template: %w", err)
}
buf := new(bytes.Buffer)
if err = tmpl.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
return "", fmt.Errorf("failed executing dpop template: %w", err)
}
return buf.String(), nil
}
func (o *DPOPOptions) validate() error {
if _, err := pemutil.Parse(o.SigningKey); err != nil {
func (o *DPOPOptions) validateAndInitialize() (err error) {
o.signingKey, err = pemutil.Parse(o.SigningKey)
if err != nil {
return fmt.Errorf("failed parsing key: %w", err)
}
if _, err := template.New("DeviceID").Parse(o.GetTarget()); err != nil {
return fmt.Errorf("failed parsing template: %w", err)
o.target, err = template.New("DeviceID").Parse(o.Target)
if err != nil {
return fmt.Errorf("failed parsing DPoP template: %w", err)
}
return nil
}

@ -34,13 +34,16 @@ type Config struct {
type OIDCOptions struct {
Provider *Provider `json:"provider,omitempty"`
Config *Config `json:"config,omitempty"`
oidcProviderConfig *oidc.ProviderConfig
target *template.Template
}
func (o *OIDCOptions) GetProvider(ctx context.Context) *oidc.Provider {
if o == nil || o.Provider == nil {
if o == nil || o.Provider == nil || o.oidcProviderConfig == nil {
return nil
}
return toOIDCProviderConfig(o.Provider).NewProvider(ctx)
return o.oidcProviderConfig.NewProvider(ctx)
}
func (o *OIDCOptions) GetConfig() *oidc.Config {
@ -59,40 +62,40 @@ func (o *OIDCOptions) GetConfig() *oidc.Config {
}
}
func (o *OIDCOptions) validate() error {
func (o *OIDCOptions) validateAndInitialize() (err error) {
if o.Provider == nil {
return errors.New("provider not set")
}
if o.Provider.IssuerURL == "" {
return errors.New("issuer URL must not be empty")
}
if _, err := url.Parse(o.Provider.IssuerURL); err != nil {
return fmt.Errorf("failed parsing issuer URL: %w", err)
o.oidcProviderConfig, err = toOIDCProviderConfig(o.Provider)
if err != nil {
return fmt.Errorf("failed creationg OIDC provider config: %w", err)
}
if _, err := template.New("DeviceID").Parse(o.Provider.IssuerURL); err != nil {
return fmt.Errorf("failed parsing template: %w", err)
o.target, err = template.New("DeviceID").Parse(o.Provider.IssuerURL)
if err != nil {
return fmt.Errorf("failed parsing OIDC template: %w", err)
}
return nil
}
func (o *OIDCOptions) EvaluateTarget(deviceID string) (string, error) {
if o == nil {
return "", errors.New("misconfigured target template configuration")
}
tmpl, err := template.New("DeviceID").Parse(o.Provider.IssuerURL)
if err != nil {
return "", fmt.Errorf("failed parsing OIDC template: %w", err)
}
buf := new(bytes.Buffer)
if err = tmpl.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
if err := o.target.Execute(buf, struct{ DeviceID string }{DeviceID: deviceID}); err != nil {
return "", fmt.Errorf("failed executing OIDC template: %w", err)
}
return buf.String(), nil
}
func toOIDCProviderConfig(in *Provider) *oidc.ProviderConfig {
issuerURL, _ := url.Parse(in.IssuerURL) // NOTE: validation is performed in validate()
func toOIDCProviderConfig(in *Provider) (*oidc.ProviderConfig, error) {
issuerURL, err := url.Parse(in.IssuerURL)
if err != nil {
return nil, fmt.Errorf("failed parsing issuer URL: %w", err)
}
// Removes query params from the URL because we use it as a way to notify client about the actual OAuth ClientId
// for this provisioner.
// This URL is going to look like: "https://idp:5556/dex?clientid=foo"
@ -107,5 +110,5 @@ func toOIDCProviderConfig(in *Provider) *oidc.ProviderConfig {
UserInfoURL: in.UserInfoURL,
JWKSURL: in.JWKSURL,
Algorithms: in.Algorithms,
}
}, nil
}

@ -43,16 +43,16 @@ func (o *Options) Validate() error {
func validate(o *Options) error {
if oidc := o.GetOIDCOptions(); oidc != nil {
if err := oidc.validate(); err != nil {
return fmt.Errorf("failed validating OIDC options: %w", err)
if err := oidc.validateAndInitialize(); err != nil {
return fmt.Errorf("failed initializing OIDC options: %w", err)
}
} else {
return errors.New("no OIDC options available")
}
if dpop := o.GetDPOPOptions(); dpop != nil {
if err := dpop.validate(); err != nil {
return fmt.Errorf("failed validating DPoP options: %w", err)
if err := dpop.validateAndInitialize(); err != nil {
return fmt.Errorf("failed initializing DPoP options: %w", err)
}
} else {
return errors.New("no DPoP options available")

@ -68,7 +68,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
},
DPOP: &DPOPOptions{},
},
expectedErr: errors.New(`failed validating OIDC options: failed parsing issuer URL: parse "\x00": net/url: invalid control character in URL`),
expectedErr: errors.New(`failed validating OIDC options: failed creationg OIDC provider config: failed parsing issuer URL: parse "\x00": net/url: invalid control character in URL`),
},
{
name: "fail/issuer-url-template",
@ -81,7 +81,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
},
DPOP: &DPOPOptions{},
},
expectedErr: errors.New(`failed validating OIDC options: failed parsing template: template: DeviceID:1: unexpected "}" in command`),
expectedErr: errors.New(`failed validating OIDC options: failed parsing OIDC template: template: DeviceID:1: unexpected "}" in command`),
},
{
name: "fail/no-dpop-options",
@ -126,7 +126,7 @@ MCowBQYDK2VwAyEA5c+4NKZSNQcR1T8qN6SjwgdPZQ0Ge12Ylx/YeGAJ35k=
Target: "{{}",
},
},
expectedErr: errors.New(`failed validating DPoP options: failed parsing template: template: DeviceID:1: unexpected "}" in command`),
expectedErr: errors.New(`failed validating DPoP options: failed parsing DPoP template: template: DeviceID:1: unexpected "}" in command`),
},
}
for _, tt := range tests {

Loading…
Cancel
Save