pkg/internal/token/execCredentialPlugin.go (77 lines of code) (raw):
package token
//go:generate sh -c "mockgen -destination mock_$GOPACKAGE/execCredentialPlugin.go github.com/Azure/kubelogin/pkg/internal/token ExecCredentialPlugin"
import (
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
klog "k8s.io/klog/v2"
)
type ExecCredentialPlugin interface {
Do(ctx context.Context) error
}
type execCredentialPlugin struct {
o *Options
cachedRecord CachedRecordProvider
execCredentialWriter ExecCredentialWriter
newCredentialFunc func(record azidentity.AuthenticationRecord, o *Options) (CredentialProvider, error)
}
var errAuthenticateNotSupported = errors.New("authenticate is not supported")
func New(o *Options) (ExecCredentialPlugin, error) {
klog.V(10).Info(o.ToString())
return &execCredentialPlugin{
o: o,
execCredentialWriter: &execCredentialWriter{},
cachedRecord: &defaultCachedRecordProvider{
file: o.authRecordCacheFile,
},
newCredentialFunc: NewAzIdentityCredential,
}, nil
}
func (p *execCredentialPlugin) Do(ctx context.Context) error {
if p.o.ServerID == "" {
return errors.New("server-id is required")
}
ctx, cancel := context.WithTimeout(ctx, p.o.Timeout)
defer cancel()
record, err := p.cachedRecord.Retrieve()
if err != nil {
klog.V(5).Infof("failed to retrieve cached record: %s", err)
}
cred, err := p.newCredentialFunc(record, p.o)
if err != nil {
return fmt.Errorf("failed to create azidentity credential: %w", err)
}
klog.V(5).Infof("using credential: %s", cred.Name())
scopes := []string{GetScope(p.o.ServerID)}
tokenRequestOptions := policy.TokenRequestOptions{
TenantID: p.o.TenantID,
Scopes: scopes,
}
if cred.NeedAuthenticate() && record == (azidentity.AuthenticationRecord{}) {
// No stored record; call Authenticate to acquire one.
// This will prompt the user to authenticate interactively.
klog.V(5).Info("no stored record; calling Authenticate")
record, err = cred.Authenticate(ctx, &tokenRequestOptions)
if err != nil {
return fmt.Errorf("failed to authenticate: %w", err)
}
err = p.cachedRecord.Store(record)
if err != nil {
return fmt.Errorf("failed to store record: %w", err)
}
}
klog.V(5).Infof("getting token with scopes: %v", scopes)
token, err := cred.GetToken(ctx, tokenRequestOptions)
if err != nil {
return fmt.Errorf("failed to get token: %w", err)
}
return p.execCredentialWriter.Write(token, os.Stdout)
}
func GetScope(serverID string) string {
scope := strings.TrimRight(serverID, "/")
if !strings.HasSuffix(scope, defaultScope) {
scope += defaultScope
}
return scope
}