2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
package cf
|
2019-06-06 19:26:04 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
2020-01-09 22:56:34 +00:00
|
|
|
"net/http"
|
2019-06-06 19:26:04 +00:00
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
cf "github.com/hashicorp/vault-plugin-auth-cf"
|
|
|
|
"github.com/hashicorp/vault-plugin-auth-cf/signatures"
|
2019-06-06 19:26:04 +00:00
|
|
|
"github.com/hashicorp/vault/api"
|
|
|
|
"github.com/hashicorp/vault/command/agent/auth"
|
|
|
|
)
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
type cfMethod struct {
|
2019-06-06 19:26:04 +00:00
|
|
|
mountPath string
|
|
|
|
roleName string
|
|
|
|
}
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
func NewCFAuthMethod(conf *auth.AuthConfig) (auth.AuthMethod, error) {
|
2019-06-06 19:26:04 +00:00
|
|
|
if conf == nil {
|
|
|
|
return nil, errors.New("empty config")
|
|
|
|
}
|
|
|
|
if conf.Config == nil {
|
|
|
|
return nil, errors.New("empty config data")
|
|
|
|
}
|
2019-08-26 16:55:08 +00:00
|
|
|
a := &cfMethod{
|
2019-06-06 19:26:04 +00:00
|
|
|
mountPath: conf.MountPath,
|
|
|
|
}
|
|
|
|
if raw, ok := conf.Config["role"]; ok {
|
|
|
|
if roleName, ok := raw.(string); ok {
|
|
|
|
a.roleName = roleName
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("could not convert 'role' config value to string")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, errors.New("missing 'role' value")
|
|
|
|
}
|
|
|
|
return a, nil
|
|
|
|
}
|
|
|
|
|
2020-01-09 22:56:34 +00:00
|
|
|
func (p *cfMethod) Authenticate(ctx context.Context, client *api.Client) (string, http.Header, map[string]interface{}, error) {
|
2019-08-26 16:55:08 +00:00
|
|
|
pathToClientCert := os.Getenv(cf.EnvVarInstanceCertificate)
|
2019-06-06 19:26:04 +00:00
|
|
|
if pathToClientCert == "" {
|
2020-01-09 22:56:34 +00:00
|
|
|
return "", nil, nil, fmt.Errorf("missing %q value", cf.EnvVarInstanceCertificate)
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
|
|
|
certBytes, err := ioutil.ReadFile(pathToClientCert)
|
|
|
|
if err != nil {
|
2020-01-09 22:56:34 +00:00
|
|
|
return "", nil, nil, err
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
2019-08-26 16:55:08 +00:00
|
|
|
pathToClientKey := os.Getenv(cf.EnvVarInstanceKey)
|
2019-06-06 19:26:04 +00:00
|
|
|
if pathToClientKey == "" {
|
2020-01-09 22:56:34 +00:00
|
|
|
return "", nil, nil, fmt.Errorf("missing %q value", cf.EnvVarInstanceKey)
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
|
|
|
signingTime := time.Now().UTC()
|
|
|
|
signatureData := &signatures.SignatureData{
|
2019-06-19 17:04:49 +00:00
|
|
|
SigningTime: signingTime,
|
|
|
|
Role: p.roleName,
|
|
|
|
CFInstanceCertContents: string(certBytes),
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
|
|
|
signature, err := signatures.Sign(pathToClientKey, signatureData)
|
|
|
|
if err != nil {
|
2020-01-09 22:56:34 +00:00
|
|
|
return "", nil, nil, err
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
|
|
|
data := map[string]interface{}{
|
2019-06-19 17:04:49 +00:00
|
|
|
"role": p.roleName,
|
|
|
|
"cf_instance_cert": string(certBytes),
|
|
|
|
"signing_time": signingTime.Format(signatures.TimeFormat),
|
|
|
|
"signature": signature,
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
2020-01-09 22:56:34 +00:00
|
|
|
return fmt.Sprintf("%s/login", p.mountPath), nil, data, nil
|
2019-06-06 19:26:04 +00:00
|
|
|
}
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
func (p *cfMethod) NewCreds() chan struct{} {
|
2019-06-06 19:26:04 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
func (p *cfMethod) CredSuccess() {}
|
2019-06-06 19:26:04 +00:00
|
|
|
|
2019-08-26 16:55:08 +00:00
|
|
|
func (p *cfMethod) Shutdown() {}
|