-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1216 from hashicorp/userpass-update
Userpass: Update the password and policies associated to user
- Loading branch information
Showing
8 changed files
with
569 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package userpass | ||
|
||
import ( | ||
"fmt" | ||
|
||
"golang.org/x/crypto/bcrypt" | ||
|
||
"github.com/hashicorp/vault/logical" | ||
"github.com/hashicorp/vault/logical/framework" | ||
) | ||
|
||
func pathUserPassword(b *backend) *framework.Path { | ||
return &framework.Path{ | ||
Pattern: "users/" + framework.GenericNameRegex("username") + "/password$", | ||
Fields: map[string]*framework.FieldSchema{ | ||
"username": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Username for this user.", | ||
}, | ||
|
||
"password": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Password for this user.", | ||
}, | ||
}, | ||
|
||
ExistenceCheck: b.userPasswordExistenceCheck, | ||
|
||
Callbacks: map[logical.Operation]framework.OperationFunc{ | ||
logical.UpdateOperation: b.pathUserPasswordUpdate, | ||
}, | ||
|
||
HelpSynopsis: pathUserPasswordHelpSyn, | ||
HelpDescription: pathUserPasswordHelpDesc, | ||
} | ||
} | ||
|
||
// By always returning true, this endpoint will be enforced to be invoked only upon UpdateOperation. | ||
// The existence of user will be checked in the operation handler. | ||
func (b *backend) userPasswordExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) { | ||
return true, nil | ||
} | ||
|
||
func (b *backend) pathUserPasswordUpdate( | ||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | ||
|
||
username := d.Get("username").(string) | ||
|
||
userEntry, err := b.user(req.Storage, username) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if userEntry == nil { | ||
return nil, fmt.Errorf("username does not exist") | ||
} | ||
|
||
err = b.updateUserPassword(req, d, userEntry) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return nil, b.setUser(req.Storage, username, userEntry) | ||
} | ||
|
||
func (b *backend) updateUserPassword(req *logical.Request, d *framework.FieldData, userEntry *UserEntry) error { | ||
password := d.Get("password").(string) | ||
if password == "" { | ||
return fmt.Errorf("missing password") | ||
} | ||
// Generate a hash of the password | ||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) | ||
if err != nil { | ||
return err | ||
} | ||
userEntry.PasswordHash = hash | ||
return nil | ||
} | ||
|
||
const pathUserPasswordHelpSyn = ` | ||
Reset user's password. | ||
` | ||
|
||
const pathUserPasswordHelpDesc = ` | ||
This endpoint allows resetting the user's password. | ||
` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package userpass | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/hashicorp/vault/logical" | ||
"github.com/hashicorp/vault/logical/framework" | ||
) | ||
|
||
func pathUserPolicies(b *backend) *framework.Path { | ||
return &framework.Path{ | ||
Pattern: "users/" + framework.GenericNameRegex("username") + "/policies$", | ||
Fields: map[string]*framework.FieldSchema{ | ||
"username": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Username for this user.", | ||
}, | ||
"policies": &framework.FieldSchema{ | ||
Type: framework.TypeString, | ||
Description: "Comma-separated list of policies", | ||
}, | ||
}, | ||
|
||
ExistenceCheck: b.userPoliciesExistenceCheck, | ||
|
||
Callbacks: map[logical.Operation]framework.OperationFunc{ | ||
logical.UpdateOperation: b.pathUserPoliciesUpdate, | ||
}, | ||
|
||
HelpSynopsis: pathUserPoliciesHelpSyn, | ||
HelpDescription: pathUserPoliciesHelpDesc, | ||
} | ||
} | ||
|
||
// By always returning true, this endpoint will be enforced to be invoked only upon UpdateOperation. | ||
// The existence of user will be checked in the operation handler. | ||
func (b *backend) userPoliciesExistenceCheck(req *logical.Request, data *framework.FieldData) (bool, error) { | ||
return true, nil | ||
} | ||
|
||
func (b *backend) pathUserPoliciesUpdate( | ||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) { | ||
|
||
username := d.Get("username").(string) | ||
|
||
userEntry, err := b.user(req.Storage, username) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if userEntry == nil { | ||
return nil, fmt.Errorf("username does not exist") | ||
} | ||
|
||
err = b.updateUserPolicies(req, d, userEntry) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return nil, b.setUser(req.Storage, username, userEntry) | ||
} | ||
|
||
func (b *backend) updateUserPolicies(req *logical.Request, d *framework.FieldData, userEntry *UserEntry) error { | ||
policies := strings.Split(d.Get("policies").(string), ",") | ||
for i, p := range policies { | ||
policies[i] = strings.TrimSpace(p) | ||
} | ||
userEntry.Policies = policies | ||
return nil | ||
} | ||
|
||
const pathUserPoliciesHelpSyn = ` | ||
Update the policies associated with the username. | ||
` | ||
|
||
const pathUserPoliciesHelpDesc = ` | ||
This endpoint allows updating the policies associated with the username. | ||
` |
Oops, something went wrong.