2016-12-19 18:15:58 +00:00
package database
import (
2017-12-14 22:03:11 +00:00
"context"
2016-12-19 18:15:58 +00:00
"fmt"
2018-04-03 16:20:20 +00:00
"time"
2016-12-19 18:15:58 +00:00
2018-06-19 15:24:28 +00:00
"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
2016-12-19 18:15:58 +00:00
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
const SecretCredsType = "creds"
func secretCreds ( b * databaseBackend ) * framework . Secret {
return & framework . Secret {
2017-03-08 22:46:53 +00:00
Type : SecretCredsType ,
Fields : map [ string ] * framework . FieldSchema { } ,
2016-12-19 18:15:58 +00:00
2017-04-11 18:50:34 +00:00
Renew : b . secretCredsRenew ( ) ,
Revoke : b . secretCredsRevoke ( ) ,
2016-12-19 18:15:58 +00:00
}
}
2017-04-11 18:50:34 +00:00
func ( b * databaseBackend ) secretCredsRenew ( ) framework . OperationFunc {
2018-01-08 18:31:38 +00:00
return func ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2017-04-11 18:50:34 +00:00
// Get the username from the internal data
usernameRaw , ok := req . Secret . InternalData [ "username" ]
if ! ok {
return nil , fmt . Errorf ( "secret is missing username internal data" )
}
username , ok := usernameRaw . ( string )
2016-12-19 18:15:58 +00:00
2017-04-11 18:50:34 +00:00
roleNameRaw , ok := req . Secret . InternalData [ "role" ]
if ! ok {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "could not find role with name: %q" , req . Secret . InternalData [ "role" ] )
2017-04-11 18:50:34 +00:00
}
2016-12-19 18:15:58 +00:00
2018-01-19 06:44:44 +00:00
role , err := b . Role ( ctx , req . Storage , roleNameRaw . ( string ) )
2017-04-11 18:50:34 +00:00
if err != nil {
return nil , err
}
if role == nil {
2018-04-05 15:49:21 +00:00
return nil , fmt . Errorf ( "error during renew: could not find role with name %q" , req . Secret . InternalData [ "role" ] )
2017-04-11 18:50:34 +00:00
}
2016-12-19 18:15:58 +00:00
2017-04-26 22:23:14 +00:00
// Get the Database object
2018-03-21 19:05:56 +00:00
db , err := b . GetConnection ( ctx , req . Storage , role . DBName )
if err != nil {
return nil , err
2016-12-19 18:15:58 +00:00
}
2018-03-21 19:05:56 +00:00
db . RLock ( )
defer db . RUnlock ( )
2017-04-11 18:50:34 +00:00
// Make sure we increase the VALID UNTIL endpoint for this user.
2018-04-03 16:20:20 +00:00
ttl , _ , err := framework . CalculateTTL ( b . System ( ) , req . Secret . Increment , role . DefaultTTL , 0 , role . MaxTTL , 0 , req . Secret . IssueTime )
if err != nil {
return nil , err
}
if ttl > 0 {
expireTime := time . Now ( ) . Add ( ttl )
// Adding a small buffer since the TTL will be calculated again after this call
// to ensure the database credential does not expire before the lease
expireTime = expireTime . Add ( 5 * time . Second )
2018-01-08 18:31:38 +00:00
err := db . RenewUser ( ctx , role . Statements , username , expireTime )
2017-04-11 18:50:34 +00:00
if err != nil {
2018-03-21 19:05:56 +00:00
b . CloseIfShutdown ( db , err )
2017-04-11 18:50:34 +00:00
return nil , err
}
}
2018-04-03 16:20:20 +00:00
resp := & logical . Response { Secret : req . Secret }
resp . Secret . TTL = role . DefaultTTL
resp . Secret . MaxTTL = role . MaxTTL
2017-04-11 18:50:34 +00:00
return resp , nil
2016-12-19 18:15:58 +00:00
}
2017-04-11 18:50:34 +00:00
}
2016-12-19 18:15:58 +00:00
2017-04-11 18:50:34 +00:00
func ( b * databaseBackend ) secretCredsRevoke ( ) framework . OperationFunc {
2018-01-08 18:31:38 +00:00
return func ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2017-04-11 18:50:34 +00:00
// Get the username from the internal data
usernameRaw , ok := req . Secret . InternalData [ "username" ]
if ! ok {
return nil , fmt . Errorf ( "secret is missing username internal data" )
}
username , ok := usernameRaw . ( string )
2016-12-19 18:15:58 +00:00
2017-04-11 18:50:34 +00:00
var resp * logical . Response
2016-12-19 18:15:58 +00:00
2017-04-11 18:50:34 +00:00
roleNameRaw , ok := req . Secret . InternalData [ "role" ]
if ! ok {
return nil , fmt . Errorf ( "no role name was provided" )
}
2016-12-19 18:15:58 +00:00
2018-06-19 15:24:28 +00:00
var dbName string
var statements dbplugin . Statements
2018-01-19 06:44:44 +00:00
role , err := b . Role ( ctx , req . Storage , roleNameRaw . ( string ) )
2016-12-19 18:15:58 +00:00
if err != nil {
return nil , err
}
2018-06-19 15:24:28 +00:00
if role != nil {
dbName = role . DBName
statements = role . Statements
} else {
if dbNameRaw , ok := req . Secret . InternalData [ "db_name" ] ; ! ok {
return nil , fmt . Errorf ( "error during revoke: could not find role with name %q or embedded revocation db name data" , req . Secret . InternalData [ "role" ] )
} else {
dbName = dbNameRaw . ( string )
}
if statementsRaw , ok := req . Secret . InternalData [ "revocation_statements" ] ; ! ok {
return nil , fmt . Errorf ( "error during revoke: could not find role with name %q or embedded revocation statement data" , req . Secret . InternalData [ "role" ] )
} else {
2018-09-05 15:41:37 +00:00
// If we don't actually have any statements, because none were
// set in the role, we'll end up with an empty one and the
// default for the db type will be attempted
if statementsRaw != nil {
statementsSlice , ok := statementsRaw . ( [ ] interface { } )
if ! ok {
return nil , fmt . Errorf ( "error during revoke: could not find role with name %q and embedded reovcation data could not be read" , req . Secret . InternalData [ "role" ] )
} else {
for _ , v := range statementsSlice {
statements . Revocation = append ( statements . Revocation , v . ( string ) )
}
}
2018-06-28 16:42:04 +00:00
}
2018-06-19 15:24:28 +00:00
}
2016-12-19 18:15:58 +00:00
}
2017-04-11 18:50:34 +00:00
// Get our connection
2018-06-19 15:24:28 +00:00
db , err := b . GetConnection ( ctx , req . Storage , dbName )
2018-03-21 19:05:56 +00:00
if err != nil {
return nil , err
2017-04-11 18:50:34 +00:00
}
2016-12-19 18:15:58 +00:00
2018-03-21 19:05:56 +00:00
db . RLock ( )
defer db . RUnlock ( )
2018-06-19 15:24:28 +00:00
if err := db . RevokeUser ( ctx , statements , username ) ; err != nil {
2018-03-21 19:05:56 +00:00
b . CloseIfShutdown ( db , err )
2017-04-11 18:50:34 +00:00
return nil , err
}
return resp , nil
}
2016-12-19 18:15:58 +00:00
}