mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-19 13:41:10 +02:00
The result will still pass gofmtcheck and won't trigger additional changes if someone isn't using goimports, but it will avoid the piecemeal imports changes we've been seeing.
130 lines
3.0 KiB
Go
130 lines
3.0 KiB
Go
package mssql
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
uuid "github.com/hashicorp/go-uuid"
|
|
"github.com/hashicorp/vault/helper/dbtxn"
|
|
"github.com/hashicorp/vault/helper/strutil"
|
|
"github.com/hashicorp/vault/logical"
|
|
"github.com/hashicorp/vault/logical/framework"
|
|
)
|
|
|
|
func pathCredsCreate(b *backend) *framework.Path {
|
|
return &framework.Path{
|
|
Pattern: "creds/" + framework.GenericNameRegex("name"),
|
|
Fields: map[string]*framework.FieldSchema{
|
|
"name": &framework.FieldSchema{
|
|
Type: framework.TypeString,
|
|
Description: "Name of the role.",
|
|
},
|
|
},
|
|
|
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
|
logical.ReadOperation: b.pathCredsCreateRead,
|
|
},
|
|
|
|
HelpSynopsis: pathCredsCreateHelpSyn,
|
|
HelpDescription: pathCredsCreateHelpDesc,
|
|
}
|
|
}
|
|
|
|
func (b *backend) pathCredsCreateRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
|
|
name := data.Get("name").(string)
|
|
|
|
// Get the role
|
|
role, err := b.Role(ctx, req.Storage, name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if role == nil {
|
|
return logical.ErrorResponse(fmt.Sprintf("unknown role: %s", name)), nil
|
|
}
|
|
|
|
// Determine if we have a lease configuration
|
|
leaseConfig, err := b.LeaseConfig(ctx, req.Storage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if leaseConfig == nil {
|
|
leaseConfig = &configLease{}
|
|
}
|
|
|
|
// Generate our username and password
|
|
displayName := req.DisplayName
|
|
if len(displayName) > 10 {
|
|
displayName = displayName[:10]
|
|
}
|
|
userUUID, err := uuid.GenerateUUID()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
username := fmt.Sprintf("%s-%s", displayName, userUUID)
|
|
password, err := uuid.GenerateUUID()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get our handle
|
|
db, err := b.DB(ctx, req.Storage)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Start a transaction
|
|
tx, err := db.Begin()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer tx.Rollback()
|
|
|
|
// Always reset database to default db of connection. Since it is in a
|
|
// transaction, all statements will be on the same connection in the pool.
|
|
roleSQL := fmt.Sprintf("USE [%s]; %s", b.defaultDb, role.SQL)
|
|
|
|
// Execute each query
|
|
for _, query := range strutil.ParseArbitraryStringSlice(roleSQL, ";") {
|
|
query = strings.TrimSpace(query)
|
|
if len(query) == 0 {
|
|
continue
|
|
}
|
|
|
|
m := map[string]string{
|
|
"name": username,
|
|
"password": password,
|
|
}
|
|
if err := dbtxn.ExecuteTxQuery(ctx, tx, m, query); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
// Commit the transaction
|
|
if err := tx.Commit(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Return the secret
|
|
resp := b.Secret(SecretCredsType).Response(map[string]interface{}{
|
|
"username": username,
|
|
"password": password,
|
|
}, map[string]interface{}{
|
|
"username": username,
|
|
})
|
|
resp.Secret.TTL = leaseConfig.TTL
|
|
resp.Secret.MaxTTL = leaseConfig.TTLMax
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
const pathCredsCreateHelpSyn = `
|
|
Request database credentials for a certain role.
|
|
`
|
|
|
|
const pathCredsCreateHelpDesc = `
|
|
This path reads database credentials for a certain role. The
|
|
database credentials will be generated on demand and will be automatically
|
|
revoked when the lease is up.
|
|
`
|