42616e7d8a
This is kind of a subtle bug, but we were using the unversioned Kubernetes type package here, where we should have been using the v1beta1 version. They have the same fields, but they serialize to JSON differently. Signed-off-by: Matt Moyer <moyerm@vmware.com>
83 lines
2.7 KiB
Go
83 lines
2.7 KiB
Go
/*
|
|
Copyright 2020 VMware, Inc.
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package client
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
|
|
placeholderv1alpha1 "github.com/suzerain-io/placeholder-name-api/pkg/apis/placeholder/v1alpha1"
|
|
placeholderclientset "github.com/suzerain-io/placeholder-name-client-go/pkg/generated/clientset/versioned"
|
|
"github.com/suzerain-io/placeholder-name/internal/constable"
|
|
)
|
|
|
|
// ErrLoginFailed is returned by ExchangeToken when the server rejects the login request.
|
|
const ErrLoginFailed = constable.Error("login failed")
|
|
|
|
func ExchangeToken(ctx context.Context, token, caBundle, apiEndpoint string) (*clientauthenticationv1beta1.ExecCredential, error) {
|
|
clientset, err := getClient(apiEndpoint, caBundle)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not get API client: %w", err)
|
|
}
|
|
|
|
resp, err := clientset.PlaceholderV1alpha1().LoginRequests().Create(ctx, &placeholderv1alpha1.LoginRequest{
|
|
Spec: placeholderv1alpha1.LoginRequestSpec{
|
|
Type: placeholderv1alpha1.TokenLoginCredentialType,
|
|
Token: &placeholderv1alpha1.LoginRequestTokenCredential{
|
|
Value: token,
|
|
},
|
|
},
|
|
}, metav1.CreateOptions{})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not login: %w", err)
|
|
}
|
|
if resp.Status.Credential == nil || resp.Status.Message != "" {
|
|
return nil, fmt.Errorf("%w: %s", ErrLoginFailed, resp.Status.Message)
|
|
}
|
|
|
|
return &clientauthenticationv1beta1.ExecCredential{
|
|
TypeMeta: metav1.TypeMeta{
|
|
Kind: "ExecCredential",
|
|
APIVersion: "client.authentication.k8s.io/v1beta1",
|
|
},
|
|
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
|
ExpirationTimestamp: resp.Status.Credential.ExpirationTimestamp,
|
|
ClientCertificateData: resp.Status.Credential.ClientCertificateData,
|
|
ClientKeyData: resp.Status.Credential.ClientKeyData,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// getClient returns an anonymous clientset for the placeholder-name API at the provided endpoint/CA bundle.
|
|
func getClient(apiEndpoint string, caBundle string) (placeholderclientset.Interface, error) {
|
|
cfg, err := clientcmd.NewNonInteractiveClientConfig(clientcmdapi.Config{
|
|
Clusters: map[string]*clientcmdapi.Cluster{
|
|
"cluster": {
|
|
Server: apiEndpoint,
|
|
CertificateAuthorityData: []byte(caBundle),
|
|
},
|
|
},
|
|
Contexts: map[string]*clientcmdapi.Context{
|
|
"current": {
|
|
Cluster: "cluster",
|
|
AuthInfo: "client",
|
|
},
|
|
},
|
|
AuthInfos: map[string]*clientcmdapi.AuthInfo{
|
|
"client": {},
|
|
},
|
|
}, "current", nil, nil).ClientConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return placeholderclientset.NewForConfig(cfg)
|
|
}
|