-
Notifications
You must be signed in to change notification settings - Fork 3.3k
feat: adds support to generate passwords #13344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gizmo-rt
wants to merge
8
commits into
hashicorp:main
Choose a base branch
from
gizmo-rt:feat/password_data_source
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
33f6afd
feat: adds support to generate passwords
gizmo-rt 5cde618
feat:adds unit test for create string function
gizmo-rt 58faef7
feat:removes default config
gizmo-rt 818b8bd
feat:updates comments
gizmo-rt 20c4048
feat: adds documentation for password datasource
gizmo-rt af93eb0
feat: fixes formatting issue and updates comments
gizmo-rt d923020
feat: lint fixes
gizmo-rt c34aabd
Merge branch 'hashicorp:main' into feat/password_data_source
gizmo-rt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,140 @@ | ||
| // Copyright (c) HashiCorp, Inc. | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
|
|
||
| //go:generate packer-sdc struct-markdown | ||
| //go:generate packer-sdc mapstructure-to-hcl2 -type DatasourceOutput,Config | ||
| package password | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "github.com/hashicorp/hcl/v2/hcldec" | ||
| "github.com/hashicorp/packer-plugin-sdk/common" | ||
| "github.com/hashicorp/packer-plugin-sdk/hcl2helper" | ||
| packersdk "github.com/hashicorp/packer-plugin-sdk/packer" | ||
| "github.com/hashicorp/packer-plugin-sdk/template/config" | ||
| "github.com/zclconf/go-cty/cty" | ||
| ) | ||
|
|
||
| type Config struct { | ||
| common.PackerConfig `mapstructure:",squash"` | ||
| // The desired length of password. | ||
| Length int64 `mapstructure:"length" required:"true"` | ||
| // Include special characters in the result. These are `!@#$%&*()-_=+[]{}<>:?`. Default value is true | ||
| Special bool `mapstructure:"special" required:"false"` | ||
| // Include uppercase alphabet characters in the result. Default value is true | ||
| Upper bool `mapstructure:"upper" required:"false"` | ||
| // Include lowercase alphabet characters in the result. Default value is true | ||
| Lower bool `mapstructure:"lower" required:"false"` | ||
| // Include numeric characters in the result. Default value is true | ||
| Numeric bool `mapstructure:"numeric" required:"false"` | ||
| // Minimum number of numeric characters in the result. Default value is 0 | ||
| MinNumeric int64 `mapstructure:"min_numeric" required:"false"` | ||
| // Minimum number of uppercase alphabet characters in the result. Default value is 0 | ||
| MinUpper int64 `mapstructure:"min_upper" required:"false"` | ||
| // Minimum number of lowercase alphabet characters in the result. Default value is 0 | ||
| MinLower int64 `mapstructure:"min_lower" required:"false"` | ||
| // Minimum number of special characters in the result. Default value is 0 | ||
| MinSpecial int64 `mapstructure:"min_special" required:"false"` | ||
| // Supply your own list of special characters to use for string generation. | ||
| // This overrides the default character list in the special argument. | ||
| // The `special` argument must still be set to true for any overwritten characters to be used in generation. | ||
| OverrideSpecial string `mapstructure:"override_special" required:"false"` | ||
| } | ||
|
|
||
| type Datasource struct { | ||
| config Config | ||
| } | ||
|
|
||
| type DatasourceOutput struct { | ||
| // The result of the password generation. This is the final password string. | ||
| Result string `mapstructure:"result"` | ||
| // A bcrypt hash of the generated random string | ||
| // **NOTE**: If the generated random string is greater than 72 bytes in length, | ||
| // `bcrypt_hash` will contain a hash of the first 72 bytes | ||
| BcryptHash string `mapstructure:"bcrypt_hash"` | ||
| } | ||
|
|
||
| func (d *Datasource) ConfigSpec() hcldec.ObjectSpec { | ||
| return d.config.FlatMapstructure().HCL2Spec() | ||
| } | ||
|
|
||
| func (d *Datasource) Configure(raws ...interface{}) error { | ||
|
|
||
| d.config = fetchDefaultPasswordParameters() | ||
|
|
||
| err := config.Decode(&d.config, nil, raws...) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| var errs *packersdk.MultiError | ||
|
|
||
| if d.config.Length < 1 || | ||
| d.config.Length < (d.config.MinLower+d.config.MinUpper+d.config.MinNumeric+d.config.MinSpecial) { | ||
|
|
||
| errs = packersdk.MultiErrorAppend( | ||
| errs, | ||
| fmt.Errorf("the minimum value for length is 1 and, "+ | ||
| "length must also be >= (`min_upper` + `min_lower` + `min_numeric` + `min_special`)")) | ||
| } | ||
|
|
||
| if errs != nil && len(errs.Errors) > 0 { | ||
| return errs | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func (d *Datasource) OutputSpec() hcldec.ObjectSpec { | ||
| return (&DatasourceOutput{}).FlatMapstructure().HCL2Spec() | ||
| } | ||
|
|
||
| func (d *Datasource) Execute() (cty.Value, error) { | ||
| params := StringParams{ | ||
| Length: d.config.Length, | ||
| Upper: d.config.Upper, | ||
| MinUpper: d.config.MinUpper, | ||
| Lower: d.config.Lower, | ||
| MinLower: d.config.MinLower, | ||
| Numeric: d.config.Numeric, | ||
| MinNumeric: d.config.MinNumeric, | ||
| Special: d.config.Special, | ||
| MinSpecial: d.config.MinSpecial, | ||
| OverrideSpecial: d.config.OverrideSpecial, | ||
| } | ||
|
|
||
| result, err := CreateString(params) | ||
| if err != nil { | ||
| return cty.NullVal(cty.EmptyObject), fmt.Errorf( | ||
| "while attempting to generate a random value a read error was generated: %s", | ||
| err.Error(), | ||
| ) | ||
| } | ||
|
|
||
| hash, err := generateHash(result) | ||
| if err != nil { | ||
| return cty.NullVal(cty.EmptyObject), fmt.Errorf( | ||
| "while attempting to generate a hash from the password an error occurred: %s", | ||
| err.Error(), | ||
| ) | ||
| } | ||
|
|
||
| output := DatasourceOutput{ | ||
| Result: result, | ||
| BcryptHash: hash, | ||
| } | ||
|
|
||
| return hcl2helper.HCL2ValueFromConfig(output, d.OutputSpec()), nil | ||
| } | ||
|
|
||
| func fetchDefaultPasswordParameters() Config { | ||
| return Config{ | ||
| Special: true, | ||
| Lower: true, | ||
| Upper: true, | ||
| Numeric: true, | ||
| MinLower: int64(0), | ||
| MinUpper: int64(0), | ||
| MinNumeric: int64(0), | ||
| MinSpecial: int64(0), | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or 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,75 @@ | ||
| // Copyright (c) HashiCorp, Inc. | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
|
|
||
| package password | ||
|
|
||
| import ( | ||
| _ "embed" | ||
| "fmt" | ||
| "os/exec" | ||
| "testing" | ||
|
|
||
| "github.com/hashicorp/packer-plugin-sdk/acctest" | ||
| ) | ||
|
|
||
| //go:embed test-fixtures/basic.pkr.hcl | ||
| var testDatasourceBasic string | ||
|
|
||
| //go:embed test-fixtures/basic-custom-charset.pkr.hcl | ||
| var testDatasourceBasicWithCustomCharset string | ||
|
|
||
| //go:embed test-fixtures/invalid-length.pkr.hcl | ||
| var testDataSourceInvalidLength string | ||
|
|
||
| //go:embed test-fixtures/empty-charset.pkr.hcl | ||
| var testDataSourceEmptyCharset string | ||
|
|
||
| func TestPasswordDataSource(t *testing.T) { | ||
| tests := []struct { | ||
| Name string | ||
| Path string | ||
| Error bool | ||
| }{ | ||
| { | ||
| Name: "basic_test", | ||
| Path: testDatasourceBasic, | ||
| Error: false, | ||
| }, | ||
| { | ||
| Name: "basic_with_custom_charset_test", | ||
| Path: testDatasourceBasicWithCustomCharset, | ||
| Error: false, | ||
| }, | ||
| { | ||
| Name: "invalid_length_test", | ||
| Path: testDataSourceInvalidLength, | ||
| Error: true, | ||
| }, | ||
| { | ||
| Name: "empty_charset_test", | ||
| Path: testDataSourceEmptyCharset, | ||
| Error: true, | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.Name, func(t *testing.T) { | ||
| testCase := &acctest.PluginTestCase{ | ||
| Name: tt.Name, | ||
| Template: tt.Path, | ||
| Check: func(buildCommand *exec.Cmd, logfile string) error { | ||
| if buildCommand.ProcessState != nil { | ||
| if buildCommand.ProcessState.ExitCode() != 0 && !tt.Error { | ||
| return fmt.Errorf("Bad exit code. Logfile: %s", logfile) | ||
| } | ||
| if tt.Error && buildCommand.ProcessState.ExitCode() == 0 { | ||
| return fmt.Errorf("Expected Bad exit code.") | ||
| } | ||
| } | ||
| return nil | ||
| }, | ||
| } | ||
| acctest.TestPlugin(t, testCase) | ||
| }) | ||
| } | ||
|
|
||
| } |
22 changes: 22 additions & 0 deletions
22
datasource/password/test-fixtures/basic-custom-charset.pkr.hcl
This file contains hidden or 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,22 @@ | ||
| source "null" "example" { | ||
| communicator = "none" | ||
| } | ||
|
|
||
| data "password" "sample" { | ||
| length = 16 | ||
| override_special = "pasword" | ||
| special = true | ||
| } | ||
|
|
||
| build { | ||
| name = "mybuild" | ||
| sources = [ | ||
| "source.null.example" | ||
| ] | ||
| provisioner "shell-local" { | ||
| inline = [ | ||
| "echo password: '${data.password.sample.result}'", | ||
| "echo generated hash is '${data.password.sample.bcrypt_hash}'" | ||
| ] | ||
| } | ||
| } |
This file contains hidden or 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,23 @@ | ||
| source "null" "example" { | ||
| communicator = "none" | ||
| } | ||
|
|
||
| data "password" "sample" { | ||
| length = 16 | ||
| special = true | ||
| lower = true | ||
| upper = true | ||
| } | ||
|
|
||
| build { | ||
| name = "mybuild" | ||
| sources = [ | ||
| "source.null.example" | ||
| ] | ||
| provisioner "shell-local" { | ||
| inline = [ | ||
| "echo password: '${data.password.sample.result}'", | ||
| "echo generated hash is '${data.password.sample.bcrypt_hash}'" | ||
| ] | ||
| } | ||
| } |
This file contains hidden or 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,20 @@ | ||
| source "null" "example" { | ||
| communicator = "none" | ||
| } | ||
|
|
||
| data "password" "sample" { | ||
| length = 16 | ||
gizmo-rt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| build { | ||
| name = "mybuild" | ||
| sources = [ | ||
| "source.null.example" | ||
| ] | ||
| provisioner "shell-local" { | ||
| inline = [ | ||
| "echo password: '${data.password.sample.result}'", | ||
| "echo generated hash is '${data.password.sample.bcrypt_hash}'" | ||
| ] | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.