2015-07-31 00:16:53 +00:00
|
|
|
// Package mfa provides wrappers to add multi-factor authentication
|
2017-09-13 01:48:52 +00:00
|
|
|
// to any auth method.
|
2015-07-31 00:16:53 +00:00
|
|
|
//
|
|
|
|
// To add MFA to a backend, replace its login path with the
|
|
|
|
// paths returned by MFAPaths and add the additional root
|
|
|
|
// paths returned by MFARootPaths. The backend provides
|
|
|
|
// the username to the MFA wrapper in Auth.Metadata['username'].
|
|
|
|
//
|
|
|
|
// To add an additional MFA type, create a subpackage that
|
|
|
|
// implements [Type]Paths, [Type]RootPaths, and [Type]Handler
|
|
|
|
// functions and add them to MFAPaths, MFARootPaths, and
|
|
|
|
// handlers respectively.
|
2015-07-27 18:23:34 +00:00
|
|
|
package mfa
|
|
|
|
|
|
|
|
import (
|
2018-01-08 18:31:38 +00:00
|
|
|
"context"
|
|
|
|
|
2015-07-27 18:23:34 +00:00
|
|
|
"github.com/hashicorp/vault/helper/mfa/duo"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/framework"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2015-07-27 18:23:34 +00:00
|
|
|
)
|
|
|
|
|
2015-07-31 00:16:53 +00:00
|
|
|
// MFAPaths returns paths to wrap the original login path and configure MFA.
|
|
|
|
// When adding MFA to a backend, these paths should be included instead of
|
|
|
|
// the login path in Backend.Paths.
|
2015-07-27 18:23:34 +00:00
|
|
|
func MFAPaths(originalBackend *framework.Backend, loginPath *framework.Path) []*framework.Path {
|
|
|
|
var b backend
|
|
|
|
b.Backend = originalBackend
|
|
|
|
return append(duo.DuoPaths(), pathMFAConfig(&b), wrapLoginPath(&b, loginPath))
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:16:53 +00:00
|
|
|
// MFARootPaths returns path strings used to configure MFA. When adding MFA
|
|
|
|
// to a backend, these paths should be included in
|
|
|
|
// Backend.PathsSpecial.Root.
|
|
|
|
func MFARootPaths() []string {
|
|
|
|
return append(duo.DuoRootPaths(), "mfa_config")
|
2015-07-27 18:23:34 +00:00
|
|
|
}
|
|
|
|
|
2015-07-31 00:16:53 +00:00
|
|
|
// HandlerFunc is the callback called to handle MFA for a login request.
|
2018-01-19 06:44:44 +00:00
|
|
|
type HandlerFunc func(context.Context, *logical.Request, *framework.FieldData, *logical.Response) (*logical.Response, error)
|
2015-07-28 01:05:06 +00:00
|
|
|
|
2015-07-31 00:16:53 +00:00
|
|
|
// handlers maps each supported MFA type to its handler.
|
2015-07-28 01:05:06 +00:00
|
|
|
var handlers = map[string]HandlerFunc{
|
|
|
|
"duo": duo.DuoHandler,
|
|
|
|
}
|
|
|
|
|
2015-07-27 18:23:34 +00:00
|
|
|
type backend struct {
|
|
|
|
*framework.Backend
|
|
|
|
}
|
|
|
|
|
|
|
|
func wrapLoginPath(b *backend, loginPath *framework.Path) *framework.Path {
|
2015-07-28 01:05:06 +00:00
|
|
|
loginPath.Fields["passcode"] = &framework.FieldSchema{
|
2015-07-27 18:23:34 +00:00
|
|
|
Type: framework.TypeString,
|
|
|
|
Description: "One time passcode (optional)",
|
|
|
|
}
|
2015-07-28 01:05:06 +00:00
|
|
|
loginPath.Fields["method"] = &framework.FieldSchema{
|
2016-08-19 20:48:32 +00:00
|
|
|
Type: framework.TypeString,
|
2015-07-27 18:23:34 +00:00
|
|
|
Description: "Multi-factor auth method to use (optional)",
|
|
|
|
}
|
2015-07-31 00:16:53 +00:00
|
|
|
// wrap write callback to do MFA after auth
|
2016-01-07 15:30:47 +00:00
|
|
|
loginHandler := loginPath.Callbacks[logical.UpdateOperation]
|
|
|
|
loginPath.Callbacks[logical.UpdateOperation] = b.wrapLoginHandler(loginHandler)
|
2015-07-27 18:23:34 +00:00
|
|
|
return loginPath
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *backend) wrapLoginHandler(loginHandler framework.OperationFunc) framework.OperationFunc {
|
2018-01-08 18:31:38 +00:00
|
|
|
return func(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
2015-07-27 18:23:34 +00:00
|
|
|
// login with original login function first
|
2018-01-08 18:31:38 +00:00
|
|
|
resp, err := loginHandler(ctx, req, d)
|
2015-07-27 18:23:34 +00:00
|
|
|
if err != nil || resp.Auth == nil {
|
|
|
|
return resp, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// check if multi-factor enabled
|
2018-01-19 06:44:44 +00:00
|
|
|
mfa_config, err := b.MFAConfig(ctx, req)
|
2015-07-27 18:23:34 +00:00
|
|
|
if err != nil || mfa_config == nil {
|
|
|
|
return resp, nil
|
|
|
|
}
|
|
|
|
|
2015-07-31 00:16:53 +00:00
|
|
|
// perform multi-factor authentication if type supported
|
2015-07-28 01:05:06 +00:00
|
|
|
handler, ok := handlers[mfa_config.Type]
|
|
|
|
if ok {
|
2018-01-19 06:44:44 +00:00
|
|
|
return handler(ctx, req, d, resp)
|
2015-07-28 01:05:06 +00:00
|
|
|
} else {
|
2015-07-27 18:23:34 +00:00
|
|
|
return resp, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|