oneandone-billing-mailer/pkg/auth/oauth.go

115 lines
2.7 KiB
Go
Raw Normal View History

2022-08-17 01:34:18 +00:00
package auth
import (
"context"
"crypto/sha256"
"net/url"
"git.icedream.tech/icedream/oneandone-billing-mailer/pkg/appcontext"
"github.com/go-logr/logr"
"github.com/google/uuid"
"golang.org/x/oauth2"
"golang.org/x/oauth2/authhandler"
)
type OAuth struct {
config *oauth2.Config
ctx context.Context
pkceKey string
}
func NewOAuth(ctx context.Context, clientID string, clientSecret string, baseUri *url.URL) *OAuth {
endpoint := oauth2.Endpoint{
AuthURL: baseUri.ResolveReference(&url.URL{Path: "auth/init"}).String(),
TokenURL: baseUri.ResolveReference(&url.URL{Path: "token"}).String(),
}
config := &oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
Endpoint: endpoint,
RedirectURL: redirect_url,
Scopes: []string{"openid", "account_otk"},
}
return &OAuth{
ctx: ctx,
config: config,
}
}
func NewOAuthFromEnvironment(ctx context.Context) (*OAuth, error) {
appctx, err := appcontext.GetEnvironmentContext()
if err != nil {
return nil, err
}
baseURL, err := appctx.CentralLogin.BaseURL()
if err != nil {
return nil, err
}
clientID := client_id
clientSecret := clientSecretForEnvironment()
return NewOAuth(ctx, clientID, clientSecret, baseURL), nil
}
func (h *OAuth) randomKey() (string, error) {
pkceKeyUUID, err := uuid.NewRandom()
if err != nil {
return "", err
}
pkceKey := pkceKeyUUID.String()
return pkceKey, nil
}
func (h *OAuth) TokenSource(t *oauth2.Token, authHandler authhandler.AuthorizationHandler) (oauth2.TokenSource, error) {
log := logr.FromContextOrDiscard(h.ctx).WithName("OAuth")
log.V(2).Info("TokenSource was called")
if t != nil && len(t.RefreshToken) > 0 {
// Use a refresher based on given token's refresh token instead
return h.config.TokenSource(h.ctx, t), nil
}
// Generate state.
//
// Note that the Control Center app does not even pass a state at all, but
// the oauth server properly implements handling it.
//state, err := h.randomKey()
//if err != nil {
// return nil, err
//}
state := ""
// Generate pkce key (which becomes our code verifier)
if len(h.pkceKey) == 0 {
pkceKey, err := h.randomKey()
if err != nil {
return nil, err
}
h.pkceKey = pkceKey
}
// Generate pkce key digest (which becomes our code challenge)
messageDigest := sha256.New()
messageDigest.Write([]byte(h.pkceKey))
messageDigestResult := messageDigest.Sum(nil)
messageDigestResultB64 := urlEncodingWithoutPadding.EncodeToString(messageDigestResult)
pkce := &authhandler.PKCEParams{
Challenge: messageDigestResultB64,
ChallengeMethod: "S256",
Verifier: h.pkceKey,
}
tok := authhandler.TokenSourceWithPKCE(
context.Background(),
h.config,
state,
authHandler,
pkce)
return tok, nil
}