2020-10-06 14:11:57 +00:00
|
|
|
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
// Package issuerprovider provides a thread-safe type that can hold on to an OIDC issuer name.
|
|
|
|
package issuerprovider
|
|
|
|
|
2020-10-07 14:53:05 +00:00
|
|
|
import (
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"go.pinniped.dev/internal/constable"
|
|
|
|
)
|
2020-10-06 14:11:57 +00:00
|
|
|
|
|
|
|
// Provider is a type that can hold onto an issuer value, which may be nil.
|
|
|
|
//
|
|
|
|
// It is thread-safe.
|
|
|
|
type Provider struct {
|
|
|
|
mu sync.RWMutex
|
2020-10-07 14:53:05 +00:00
|
|
|
issuer *url.URL
|
2020-10-06 14:11:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New returns an empty Provider, i.e., one that holds a nil issuer.
|
|
|
|
func New() *Provider {
|
|
|
|
return &Provider{}
|
|
|
|
}
|
|
|
|
|
2020-10-07 14:53:05 +00:00
|
|
|
// SetIssuer validates and sets the provided issuer. If validation fails, SetIssuer will return
|
|
|
|
// an error.
|
|
|
|
func (p *Provider) SetIssuer(issuer *url.URL) error {
|
|
|
|
if err := p.validateIssuer(issuer); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
p.setIssuer(issuer)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) validateIssuer(issuer *url.URL) error {
|
|
|
|
if issuer == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if issuer.Scheme != "https" && removeMeAfterWeNoLongerNeedHTTPIssuerSupport(issuer.Scheme) {
|
|
|
|
return constable.Error(`issuer must have "https" scheme`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if issuer.User != nil {
|
|
|
|
return constable.Error(`issuer must not have username or password`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(issuer.Path, "/") {
|
|
|
|
return constable.Error(`issuer must not have trailing slash in path`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if issuer.RawQuery != "" {
|
|
|
|
return constable.Error(`issuer must not have query`)
|
|
|
|
}
|
|
|
|
|
|
|
|
if issuer.Fragment != "" {
|
|
|
|
return constable.Error(`issuer must not have fragment`)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) setIssuer(issuer *url.URL) {
|
2020-10-06 14:11:57 +00:00
|
|
|
p.mu.Lock()
|
|
|
|
defer p.mu.Unlock()
|
|
|
|
p.issuer = issuer
|
|
|
|
}
|
|
|
|
|
2020-10-07 14:53:05 +00:00
|
|
|
func (p *Provider) GetIssuer() *url.URL {
|
2020-10-06 14:11:57 +00:00
|
|
|
p.mu.RLock()
|
|
|
|
defer p.mu.RUnlock()
|
|
|
|
return p.issuer
|
|
|
|
}
|
2020-10-07 14:53:05 +00:00
|
|
|
|
|
|
|
func removeMeAfterWeNoLongerNeedHTTPIssuerSupport(scheme string) bool {
|
|
|
|
return scheme != "http"
|
|
|
|
}
|