vault/builtin/logical/ssh/path_verify.go
hashicorp-copywrite[bot] 0b12cdcfd1
[COMPLIANCE] License changes (#22290)
* Adding explicit MPL license for sub-package.

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Adding explicit MPL license for sub-package.

This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository.

* Updating the license from MPL to Business Source License.

Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl.

* add missing license headers

* Update copyright file headers to BUS-1.1

* Fix test that expected exact offset on hcl file

---------

Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com>
Co-authored-by: Sarah Thompson <sthompson@hashicorp.com>
Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
2023-08-10 18:14:03 -07:00

112 lines
3.0 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package ssh
import (
"context"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
)
func pathVerify(b *backend) *framework.Path {
return &framework.Path{
Pattern: "verify",
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixSSH,
OperationVerb: "verify",
OperationSuffix: "otp",
},
Fields: map[string]*framework.FieldSchema{
"otp": {
Type: framework.TypeString,
Description: "[Required] One-Time-Key that needs to be validated",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathVerifyWrite,
},
HelpSynopsis: pathVerifyHelpSyn,
HelpDescription: pathVerifyHelpDesc,
}
}
func (b *backend) getOTP(ctx context.Context, s logical.Storage, n string) (*sshOTP, error) {
entry, err := s.Get(ctx, "otp/"+n)
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
var result sshOTP
if err := entry.DecodeJSON(&result); err != nil {
return nil, err
}
return &result, nil
}
func (b *backend) pathVerifyWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
otp := d.Get("otp").(string)
// If OTP is not a UUID and a string matching VerifyEchoRequest, then the
// response will be VerifyEchoResponse. This is used by agent to check if
// connection to Vault server is proper.
if otp == api.VerifyEchoRequest {
return &logical.Response{
Data: map[string]interface{}{
"message": api.VerifyEchoResponse,
},
}, nil
}
// Create the salt of OTP because entry would have been create with the
// salt and not directly of the OTP. Salt will yield the same value which
// because the seed is the same, the backend salt.
salt, err := b.Salt(ctx)
if err != nil {
return nil, err
}
otpSalted := salt.SaltID(otp)
// Return nil if there is no entry found for the OTP
otpEntry, err := b.getOTP(ctx, req.Storage, otpSalted)
if err != nil {
return nil, err
}
if otpEntry == nil {
return logical.ErrorResponse("OTP not found"), nil
}
// Delete the OTP if found. This is what makes the key an OTP.
err = req.Storage.Delete(ctx, "otp/"+otpSalted)
if err != nil {
return nil, err
}
// Return username and IP only if there were no problems uptill this point.
return &logical.Response{
Data: map[string]interface{}{
"username": otpEntry.Username,
"ip": otpEntry.IP,
"role_name": otpEntry.RoleName,
},
}, nil
}
const pathVerifyHelpSyn = `
Validate the OTP provided by Vault SSH Agent.
`
const pathVerifyHelpDesc = `
This path will be used by Vault SSH Agent running in the remote hosts. The OTP
provided by the client is sent to Vault for validation by the agent. If Vault
finds an entry for the OTP, it responds with the username and IP it is associated
with. Agent uses this information to authenticate the client. Vault deletes the
OTP after validating it once.
`