This repository has been archived on 2022-07-28. You can view files and clone it, but cannot push or open issues or pull requests.
hydra_oidc_poc/common/services/oidc.go

117 lines
3.1 KiB
Go

package services
import (
"bytes"
"context"
"encoding/json"
"net/http"
"net/url"
"github.com/lestrrat-go/jwx/jwk"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"git.cacert.org/oidc_login/common/models"
)
type oidcContextKey int
// context keys
const (
ctxOidcConfig oidcContextKey = iota
ctxOAuth2Config
ctxOidcJwks
)
// Parameters for DiscoverOIDC
type OidcParams struct {
OidcServer string
OidcClientId string
OidcClientSecret string
APIClient *http.Client
}
// Discover OpenID Connect parameters from the discovery endpoint and the
// JSON Web Key Set from the discovered jwksUri.
//
// The subset of values specified by models.OpenIDConfiguration is stored in
// the given context and can be retrieved from the context by GetOidcConfig.
//
// OAuth2 specific values are stored in another context object and can be
// retrieved by GetOAuth2Config.
//
// The JSON Web Key Set can be retrieved by GetJwkSet.
func DiscoverOIDC(ctx context.Context, logger *log.Logger, params *OidcParams) (context.Context, error) {
var discoveryUrl *url.URL
discoveryUrl, err := url.Parse(params.OidcServer)
if err != nil {
logger.Fatalf("could not parse oidc.server parameter value %s: %s", params.OidcServer, err)
} else {
discoveryUrl.Path = "/.well-known/openid-configuration"
}
var body []byte
var req *http.Request
req, err = http.NewRequest(http.MethodGet, discoveryUrl.String(), bytes.NewBuffer(body))
if err != nil {
return nil, err
}
req.Header = map[string][]string{
"Accept": {"application/json"},
}
resp, err := params.APIClient.Do(req)
if err != nil {
return nil, err
}
dec := json.NewDecoder(resp.Body)
discoveryResponse := &models.OpenIDConfiguration{}
err = dec.Decode(discoveryResponse)
if err != nil {
return nil, err
}
ctx = context.WithValue(ctx, ctxOidcConfig, discoveryResponse)
oauth2Config := &oauth2.Config{
ClientID: params.OidcClientId,
ClientSecret: params.OidcClientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: discoveryResponse.AuthorizationEndpoint,
TokenURL: discoveryResponse.TokenEndpoint,
},
Scopes: []string{"openid", "offline"},
}
ctx = context.WithValue(ctx, ctxOAuth2Config, oauth2Config)
keySet, err := jwk.FetchHTTP(discoveryResponse.JwksUri, jwk.WithHTTPClient(params.APIClient))
if err != nil {
log.Fatalf("could not fetch JWKs: %s", err)
}
ctx = context.WithValue(ctx, ctxOidcJwks, keySet)
return ctx, nil
}
// Get the OpenID configuration from the context.
//
// DiscoverOIDC needs to be called before this is available.
func GetOidcConfig(ctx context.Context) *models.OpenIDConfiguration {
return ctx.Value(ctxOidcConfig).(*models.OpenIDConfiguration)
}
// Get the OAuth 2 configuration configuration from the context.
//
// DiscoverOIDC needs to be called before this is available.
func GetOAuth2Config(ctx context.Context) *oauth2.Config {
return ctx.Value(ctxOAuth2Config).(*oauth2.Config)
}
// Get the JSON Web Key set from the context.
//
// DiscoverOIDC needs to be called before this is available.
func GetJwkSet(ctx context.Context) *jwk.Set {
return ctx.Value(ctxOidcJwks).(*jwk.Set)
}