forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
credsutil.go
87 lines (74 loc) · 2.31 KB
/
credsutil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
package credsutil
import (
"crypto/rand"
"time"
"fmt"
"github.com/hashicorp/vault/builtin/logical/database/dbplugin"
)
// CredentialsProducer can be used as an embeded interface in the Database
// definition. It implements the methods for generating user information for a
// particular database type and is used in all the builtin database types.
type CredentialsProducer interface {
GenerateUsername(usernameConfig dbplugin.UsernameConfig) (string, error)
GeneratePassword() (string, error)
GenerateExpiration(ttl time.Time) (string, error)
}
const (
reqStr = `A1a-`
minStrLen = 10
)
// RandomAlphaNumeric returns a random string of characters [A-Za-z0-9-]
// of the provided length. The string generated takes up to 4 characters
// of space that are predefined and prepended to ensure password
// character requirements. It also requires a min length of 10 characters.
func RandomAlphaNumeric(length int, prependA1a bool) (string, error) {
if length < minStrLen {
return "", fmt.Errorf("minimum length of %d is required", minStrLen)
}
var size int
var retBytes []byte
if prependA1a {
size = len(reqStr)
retBytes = make([]byte, length-size)
// Enforce alphanumeric requirements
retBytes = append([]byte(reqStr), retBytes...)
} else {
retBytes = make([]byte, length)
}
for size < length {
// Extend the len of the random byte slice to lower odds of having to
// re-roll.
c := length + len(reqStr)
bArr := make([]byte, c)
_, err := rand.Read(bArr)
if err != nil {
return "", err
}
for _, b := range bArr {
if size == length {
break
}
/**
* Each byte will be in [0, 256), but we only care about:
*
* [48, 57] 0-9
* [65, 90] A-Z
* [97, 122] a-z
*
* Which means that the highest bit will always be zero, since the last byte with high bit
* zero is 01111111 = 127 which is higher than 122. Lower our odds of having to re-roll a byte by
* dividing by two (right bit shift of 1).
*/
b = b >> 1
// Bitwise OR to set min to 48, further reduces re-roll
b |= 0x30
// The byte is any of 0-9 A-Z a-z
byteIsAllowable := (b >= 48 && b <= 57) || (b >= 65 && b <= 90) || (b >= 97 && b <= 122)
if byteIsAllowable {
retBytes[size] = b
size++
}
}
}
return string(retBytes), nil
}