package auth import ( "context" "crypto/rand" "errors" "fmt" "math/big" "path" "github.com/hashicorp/vault/api" ) var errNoAuth = errors.New("empty response from credential provider") // loginWrite performs POST auth// and normalises errors. // This single helper backs every "raw" method (see the method table in the // design doc) — the official api/auth/{userpass,approle,ldap,kubernetes} // submodules add nothing over this plus Field.EnvFallback. func loginWrite(ctx context.Context, c *api.Client, mount, suffix string, data map[string]interface{}) (*api.Secret, error) { p := path.Join("auth", mount, suffix) sec, err := c.Logical().WriteWithContext(ctx, p, data) if err != nil { return nil, fmt.Errorf("login at %s: %w", p, err) } if sec == nil || sec.Auth == nil || sec.Auth.ClientToken == "" { return nil, fmt.Errorf("%s: %w", p, errNoAuth) } return sec, nil } // mountOf returns req.Mount if set, else def. func mountOf(req Request, def string) string { if req.Mount != "" { return req.Mount } return def } const base62Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" // randomNonce returns an n-character base62 string from crypto/rand. Used // for OIDC's client_nonce and Okta's verify nonce — anywhere Vault's own // CLI uses go-secure-stdlib/base62.Random, which this deliberately does not // depend on (it is ~10 lines backed by the same crypto/rand primitive). func randomNonce(n int) string { b := make([]byte, n) max := big.NewInt(int64(len(base62Alphabet))) for i := range b { idx, err := rand.Int(rand.Reader, max) if err != nil { // crypto/rand failing is fatal for anything security-sensitive; // panic rather than silently degrade nonce quality. panic(fmt.Sprintf("auth: crypto/rand unavailable: %v", err)) } b[i] = base62Alphabet[idx.Int64()] } return string(b) }