-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow dynamic naming of GitLab tokens using the name property
- Loading branch information
Showing
8 changed files
with
257 additions
and
10 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package gitlab | ||
|
||
import ( | ||
"crypto/rand" | ||
"fmt" | ||
"strings" | ||
"text/template" | ||
"time" | ||
_ "unsafe" | ||
) | ||
|
||
func yesNoBool(in bool) string { | ||
if in { | ||
return "yes" | ||
} | ||
return "no" | ||
} | ||
func randHexString(bytes int) string { | ||
buf := make([]byte, bytes) | ||
_, _ = rand.Read(buf) | ||
return fmt.Sprintf("%x", buf) | ||
} | ||
|
||
func timeNowFormat(layout string) string { | ||
return time.Now().UTC().Format(layout) | ||
} | ||
|
||
var tplFuncMap = template.FuncMap{ | ||
"randHexString": randHexString, | ||
"stringsJoin": strings.Join, | ||
"yesNoBool": yesNoBool, | ||
"timeNowFormat": timeNowFormat, | ||
} | ||
|
||
func TokenName(role *EntryRole) (name string, err error) { | ||
if role == nil { | ||
return "", fmt.Errorf("role: %w", ErrNilValue) | ||
} | ||
var tpl *template.Template | ||
tpl, err = template.New("name").Funcs(tplFuncMap).Parse(role.Name) | ||
if err != nil { | ||
return "", err | ||
} | ||
buf := new(strings.Builder) | ||
var data = role.LogicalResponseData() | ||
data["unix_timestamp_utc"] = time.Now().UTC().Unix() | ||
delete(data, "name") | ||
err = tpl.Execute(buf, data) | ||
name = buf.String() | ||
return name, err | ||
} |
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,28 @@ | ||
package gitlab_test | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
g "github.com/ilijamt/vault-plugin-secrets-gitlab" | ||
) | ||
|
||
func TestTokenNameGenerator_RandString(t *testing.T) { | ||
val, err := g.TokenName( | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ randHexString 8 }}", | ||
Scopes: []string{g.TokenScopeApi.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: false, | ||
}, | ||
) | ||
require.NoError(t, err) | ||
require.NotEmpty(t, val) | ||
require.Len(t, val, 16) | ||
} |
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,96 @@ | ||
package gitlab_test | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
g "github.com/ilijamt/vault-plugin-secrets-gitlab" | ||
) | ||
|
||
func TestTokenNameGenerator(t *testing.T) { | ||
var tests = []struct { | ||
in *g.EntryRole | ||
outVal string | ||
outErr bool | ||
}{ | ||
{nil, "", true}, | ||
|
||
// invalid template | ||
{ | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ .role_name", | ||
Scopes: []string{g.TokenScopeApi.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: true, | ||
}, | ||
"", | ||
true, | ||
}, | ||
|
||
// combination template | ||
{ | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", | ||
Scopes: []string{g.TokenScopeApi.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: true, | ||
}, | ||
"test-personal-access-token-yes", | ||
false, | ||
}, | ||
|
||
// with stringsJoin | ||
{ | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", | ||
Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: false, | ||
}, | ||
"test-personal-api-sudo-no", | ||
false, | ||
}, | ||
|
||
// with timeNowFormat | ||
{ | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", | ||
Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: false, | ||
}, | ||
fmt.Sprintf("test-personal-%d-%02d", time.Now().UTC().Year(), time.Now().UTC().Month()), | ||
false, | ||
}, | ||
} | ||
|
||
for _, tst := range tests { | ||
t.Logf("TokenName(%v)", tst.in) | ||
val, err := g.TokenName(tst.in) | ||
assert.Equal(t, tst.outVal, val) | ||
if tst.outErr { | ||
assert.Error(t, err, tst.outErr) | ||
} else { | ||
assert.NoError(t, err) | ||
} | ||
} | ||
} |
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,32 @@ | ||
package gitlab_test | ||
|
||
import ( | ||
"strconv" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
g "github.com/ilijamt/vault-plugin-secrets-gitlab" | ||
) | ||
|
||
func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { | ||
now := time.Now().UTC().Unix() | ||
val, err := g.TokenName( | ||
&g.EntryRole{ | ||
RoleName: "test", | ||
TTL: time.Hour, | ||
Path: "/path", | ||
Name: "{{ .unix_timestamp_utc }}", | ||
Scopes: []string{g.TokenScopeApi.String()}, | ||
AccessLevel: g.AccessLevelNoPermissions, | ||
TokenType: g.TokenTypePersonal, | ||
GitlabRevokesTokens: false, | ||
}, | ||
) | ||
require.NoError(t, err) | ||
require.NotEmpty(t, val) | ||
i, err := strconv.ParseInt(val, 10, 64) | ||
require.NoError(t, err) | ||
require.GreaterOrEqual(t, i, now) | ||
} |
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