Documentation
¶
Overview ¶
package assertion authenticate OpenID Connect clients using private_key_jwt (private/public certificates instead of a shared secret), via OAuth 2.0 assertions specified in RFC 7521.
It offers better security since not secret must be transmitted (only the public certificate must be uploaded to the identity provider).
Example ¶
package main import ( "crypto/rand" "crypto/rsa" "log" "net/http" "time" "code.pfad.fr/gopenidclient" "code.pfad.fr/gopenidclient/assertion" ) // only for example purpose (to prevent circular dependency) type concreteProvider struct { gopenidclient.Provider Issuer string ClientID string Scopes []string ClientAssertion gopenidclient.Assertion } func main() { // persist the privateKey somewhere (can be serialized using x509.MarshalPKCS1PrivateKey for instance) privateKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { log.Fatal(err) } // create the (downgradable) certificate certificate := assertion.NewSesquiennial(privateKey, "Example Org") rs256 := assertion.RS256{ GetThumbprint: certificate.Thumbprint, Validity: time.Minute, CliendID: "<OAUTH2_CLIENT_ID from identity provider>", Key: privateKey, } // setup the provider using the assertion (instead of the client secret) // for instance using code.pfad.fr/gopenidclient/coreos.Provider var provider gopenidclient.Provider = (&concreteProvider{ Issuer: "issuer_url", ClientID: rs256.CliendID, Scopes: []string{"openid", "email", "profile"}, ClientAssertion: rs256, // ClientSecret can be omitted }) // the provider can be used like any other provider provider.SetRedirectURL("http://localhost:8080/auth/callback") // the public certificate can be exposed to ease the transmission to the identity provider http.HandleFunc("/auth/certificate.pem", func(w http.ResponseWriter, r *http.Request) { certificate.ServeDER(w, r) }) // the certificate can be downgraded on ExchangeHandler.HandleCallback error }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type RS256 ¶
type RS256 struct { // GetThumbprint identifies the public certificate. Implemented by [Sesquiennial.Thumbprint] GetThumbprint func() (Thumbprint, error) // Validity should be kept short (since the assertion should be used immediately by the identity provider) Validity time.Duration // ClientID identifies the client CliendID string // Key contains the private key to sign the assertion Key *rsa.PrivateKey }
RS256 generates JWT assertions with RSA+SHA256. Suitable for Azure AD
type Sesquiennial ¶
type Sesquiennial struct { CertificateSubject pkix.Name // duration after which a downgrade is cancelled automatically UpgradeAttemptAfter time.Duration // Return the certificate as ASN.1 marshalled X.509 v3 certificate (usually calls [x509.CreateCertificate]) CreateCertificate func(x509.Certificate) ([]byte, error) // LogDowngrade will be called on every call to [Sesquiennial.Downgrade] LogDowngrade func(isDowngrade bool, thumbprint Thumbprint) // contains filtered or unexported fields }
Sesquiennial generates public certificates valid for 18 months (always starting January 1st). By default it serves the most recent certificate. A call to Sesquiennial.Downgrade will temporarly serve the certificate from previous year (which should still be valid thanks to the 18-months period). This gives 6 months to the administrator to refresh the public certificate at the identity provider.
func NewSesquiennial ¶
func NewSesquiennial(key *rsa.PrivateKey, organisationName string) *Sesquiennial
NewSesquiennial creates a new Sesquiennial.
func (*Sesquiennial) DER ¶
func (cg *Sesquiennial) DER(year int) ([]byte, error)
DER returns a ASN.1 marshalled X.509 v3 certificate, valid for 18 months, starting on {year}-01-01.
func (*Sesquiennial) Downgrade ¶
func (cg *Sesquiennial) Downgrade() bool
Downgrade will serve the previous certificate if not downgraded yet (and return true). Calling it again will cancel the downgrade and return false. This should be called in case the Identity Provider denied a request with a "Client assertion failed signature validation" error.
func (*Sesquiennial) IsDowngraded ¶
func (cg *Sesquiennial) IsDowngraded() bool
IsDowngraded indicates if the previous certificate is being used. I can be used to display a message to the administrator to refresh the public certificate at the identity provider.
func (*Sesquiennial) ServeDER ¶
func (cg *Sesquiennial) ServeDER(w http.ResponseWriter, r *http.Request) error
ServeDER will serve the current public certificate as DER. You can get the previous version, by adding a "?old" query parameter
func (*Sesquiennial) Thumbprint ¶
func (cg *Sesquiennial) Thumbprint() (Thumbprint, error)
Thumbprint returns the thumbprint of the currently served certificate. It is suitable to use for the GetThumbprint field of RS256.
type Thumbprint ¶
type Thumbprint struct { Sha1 string `json:"x5t,omitempty"` // x5t according to https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.7 Sha256 string `json:"x5t#S256,omitempty"` // x5t#S256 according to https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.8 }
Thumbprint contains the base64 encoded-hashes of a given certificate.
func NewThumbprint ¶
func NewThumbprint(der []byte) (tb Thumbprint)
NewThumbprint returns the base64 encoded-hashes of the provided DER certificate.