fix(engine): harden htpasswd validation

pull/32033/head
Asish Kumar 1 day ago
parent 3cd7b37cb6
commit 170ef218ba

@ -92,6 +92,9 @@ func htpasswd(username, password string, hashAlgorithms ...string) (string, erro
if strings.Contains(username, ":") {
return fmt.Sprintf("invalid username: %s", username), nil
}
if strings.ContainsAny(username, "\n\r") {
return "", fmt.Errorf("invalid username %q: must not contain newline characters", username)
}
if len(hashAlgorithms) > 1 {
return "", fmt.Errorf("wrong number of args for htpasswd: want 2 or 3 got %d", len(hashAlgorithms)+2)
@ -104,7 +107,7 @@ func htpasswd(username, password string, hashAlgorithms ...string) (string, erro
switch algorithm {
case "bcrypt":
return fmt.Sprintf("%s:%s", username, sprigBcrypt(password)), nil
return bcryptHtpasswd(username, password)
case "sha", "sha1":
sum := sha1.Sum([]byte(password))
return fmt.Sprintf("%s:{SHA}%s", username, base64.StdEncoding.EncodeToString(sum[:])), nil
@ -113,13 +116,13 @@ func htpasswd(username, password string, hashAlgorithms ...string) (string, erro
}
}
func sprigBcrypt(input string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(input), bcrypt.DefaultCost)
func bcryptHtpasswd(username, password string) (string, error) {
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return fmt.Sprintf("failed to encrypt string with bcrypt: %s", err)
return "", fmt.Errorf("failed to encrypt password with bcrypt: %w", err)
}
return string(hash)
return fmt.Sprintf("%s:%s", username, string(hash)), nil
}
// toYAML takes an interface, marshals it to yaml, and returns a string. It will

@ -17,6 +17,7 @@ limitations under the License.
package engine
import (
"fmt"
"strings"
"testing"
"text/template"
@ -223,11 +224,26 @@ func TestHtpasswd(t *testing.T) {
tpl: `{{ htpasswd "bad:user" "testpassword" }}`,
expect: `invalid username: bad:user`,
},
{
name: "rejects username with newline",
tpl: "{{ htpasswd \"bad\\nuser\" \"testpassword\" }}",
expectError: `must not contain newline characters`,
},
{
name: "returns bcrypt errors",
tpl: fmt.Sprintf(`{{ htpasswd "testuser" %q }}`, strings.Repeat("x", 73)),
expectError: `password length exceeds 72 bytes`,
},
{
name: "rejects unsupported algorithms",
tpl: `{{ htpasswd "testuser" "testpassword" "md5" }}`,
expectError: `unsupported htpasswd hash algorithm "md5"`,
},
{
name: "rejects too many hash algorithm args",
tpl: `{{ htpasswd "testuser" "testpassword" "sha" "extra" }}`,
expectError: `wrong number of args for htpasswd: want 2 or 3 got 4`,
},
}
for _, tt := range tests {

Loading…
Cancel
Save