2015-04-24 17:31:57 +00:00
package cert
import (
2015-10-06 01:10:20 +00:00
"fmt"
2015-04-24 17:31:57 +00:00
"strings"
2015-04-24 19:58:39 +00:00
"time"
2015-04-24 17:31:57 +00:00
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathCerts ( b * backend ) * framework . Path {
return & framework . Path {
2015-08-21 07:56:13 +00:00
Pattern : "certs/" + framework . GenericNameRegex ( "name" ) ,
2015-04-24 17:31:57 +00:00
Fields : map [ string ] * framework . FieldSchema {
"name" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "The name of the certificate" ,
} ,
"certificate" : & framework . FieldSchema {
2015-09-18 18:01:28 +00:00
Type : framework . TypeString ,
Description : ` The public certificate that should be trusted .
Must be x509 PEM encoded . ` ,
2015-04-24 17:31:57 +00:00
} ,
"display_name" : & framework . FieldSchema {
2015-09-18 18:01:28 +00:00
Type : framework . TypeString ,
Description : ` The display name to use for clients using this
certificate . ` ,
2015-04-24 17:31:57 +00:00
} ,
"policies" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Comma-seperated list of policies." ,
} ,
2015-04-24 19:58:39 +00:00
"lease" : & framework . FieldSchema {
2015-09-18 18:01:28 +00:00
Type : framework . TypeInt ,
Description : ` Deprecated : use "ttl" instead . TTL time in
seconds . Defaults to system / backend default TTL . ` ,
} ,
"ttl" : & framework . FieldSchema {
2015-10-06 01:10:20 +00:00
Type : framework . TypeString ,
Description : ` TTL for tokens issued by this backend .
Defaults to system / backend default TTL time . ` ,
2015-04-24 19:58:39 +00:00
} ,
2015-04-24 17:31:57 +00:00
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . DeleteOperation : b . pathCertDelete ,
logical . ReadOperation : b . pathCertRead ,
logical . WriteOperation : b . pathCertWrite ,
} ,
HelpSynopsis : pathCertHelpSyn ,
HelpDescription : pathCertHelpDesc ,
}
}
func ( b * backend ) Cert ( s logical . Storage , n string ) ( * CertEntry , error ) {
entry , err := s . Get ( "cert/" + strings . ToLower ( n ) )
if err != nil {
return nil , err
}
if entry == nil {
return nil , nil
}
var result CertEntry
if err := entry . DecodeJSON ( & result ) ; err != nil {
return nil , err
}
return & result , nil
}
func ( b * backend ) pathCertDelete (
req * logical . Request , d * framework . FieldData ) ( * logical . Response , error ) {
err := req . Storage . Delete ( "cert/" + strings . ToLower ( d . Get ( "name" ) . ( string ) ) )
if err != nil {
return nil , err
}
return nil , nil
}
func ( b * backend ) pathCertRead (
req * logical . Request , d * framework . FieldData ) ( * logical . Response , error ) {
cert , err := b . Cert ( req . Storage , strings . ToLower ( d . Get ( "name" ) . ( string ) ) )
if err != nil {
return nil , err
}
if cert == nil {
return nil , nil
}
2015-09-18 18:01:28 +00:00
duration := cert . TTL
if duration == 0 {
duration = b . System ( ) . DefaultLeaseTTL ( )
}
2015-04-24 17:31:57 +00:00
return & logical . Response {
Data : map [ string ] interface { } {
"certificate" : cert . Certificate ,
"display_name" : cert . DisplayName ,
"policies" : strings . Join ( cert . Policies , "," ) ,
2015-10-06 01:10:20 +00:00
"ttl" : duration / time . Second ,
2015-04-24 17:31:57 +00:00
} ,
} , nil
}
func ( b * backend ) pathCertWrite (
req * logical . Request , d * framework . FieldData ) ( * logical . Response , error ) {
name := strings . ToLower ( d . Get ( "name" ) . ( string ) )
certificate := d . Get ( "certificate" ) . ( string )
displayName := d . Get ( "display_name" ) . ( string )
policies := strings . Split ( d . Get ( "policies" ) . ( string ) , "," )
for i , p := range policies {
policies [ i ] = strings . TrimSpace ( p )
}
2015-04-24 17:52:17 +00:00
// Default the display name to the certificate name if not given
if displayName == "" {
displayName = name
}
2015-04-24 17:39:44 +00:00
if len ( policies ) == 0 {
return logical . ErrorResponse ( "policies required" ) , nil
}
parsed := parsePEM ( [ ] byte ( certificate ) )
if len ( parsed ) == 0 {
return logical . ErrorResponse ( "failed to parse certificate" ) , nil
}
2015-10-06 01:10:20 +00:00
certEntry := & CertEntry {
Name : name ,
Certificate : certificate ,
DisplayName : displayName ,
Policies : policies ,
}
2015-09-18 18:01:28 +00:00
// Parse the lease duration or default to backend/system default
2015-10-06 01:10:20 +00:00
var err error
maxTTL := b . System ( ) . MaxLeaseTTL ( )
ttlStr := d . Get ( "ttl" ) . ( string )
var ttl time . Duration
if len ( ttlStr ) == 0 {
ttl = time . Second * time . Duration ( d . Get ( "lease" ) . ( int ) )
} else {
ttl , err = time . ParseDuration ( ttlStr )
if err != nil {
return logical . ErrorResponse ( fmt . Sprintf ( "Failed to parse ttl of %d" , ttlStr ) ) , nil
}
}
if ttl > maxTTL {
return logical . ErrorResponse ( fmt . Sprintf ( "Given TTL of %d seconds greater than current mount/system default of %d seconds" , ttl / time . Second , maxTTL / time . Second ) ) , nil
2015-09-18 18:01:28 +00:00
}
2015-10-06 01:10:20 +00:00
if ttl > time . Duration ( 0 ) {
certEntry . TTL = ttl
2015-04-24 19:58:39 +00:00
}
2015-04-24 17:31:57 +00:00
// Store it
2015-10-06 01:10:20 +00:00
entry , err := logical . StorageEntryJSON ( "cert/" + name , certEntry )
2015-04-24 17:31:57 +00:00
if err != nil {
return nil , err
}
if err := req . Storage . Put ( entry ) ; err != nil {
return nil , err
}
return nil , nil
}
type CertEntry struct {
Name string
Certificate string
DisplayName string
Policies [ ] string
2015-08-21 00:47:17 +00:00
TTL time . Duration
2015-04-24 17:31:57 +00:00
}
const pathCertHelpSyn = `
Manage trusted certificates used for authentication .
`
const pathCertHelpDesc = `
This endpoint allows you to create , read , update , and delete trusted certificates
that are allowed to authenticate .
Deleting a certificate will not revoke auth for prior authenticated connections .
To do this , do a revoke on "login" . If you don ' t need to revoke login immediately ,
then the next renew will cause the lease to expire .
`