forked from TrueCloudLab/certificates
Add support for extensions and critical options on the identity
function.
This commit is contained in:
parent
8ff8d90f8c
commit
02379d494b
4 changed files with 105 additions and 2 deletions
|
@ -384,6 +384,14 @@ func (o *OIDC) AuthorizeSSHSign(ctx context.Context, token string) ([]SignOption
|
|||
if v, err := unsafeParseSigned(token); err == nil {
|
||||
data.SetToken(v)
|
||||
}
|
||||
// Add custom extensions added in the identity function.
|
||||
for k, v := range iden.Permissions.Extensions {
|
||||
data.AddExtension(k, v)
|
||||
}
|
||||
// Add custom critical options added in the identity function.
|
||||
for k, v := range iden.Permissions.CriticalOptions {
|
||||
data.AddCriticalOption(k, v)
|
||||
}
|
||||
|
||||
templateOptions, err := TemplateSSHOptions(o.SSHOptions, data)
|
||||
if err != nil {
|
||||
|
|
|
@ -327,6 +327,13 @@ func (b *base) AuthorizeSSHRekey(ctx context.Context, token string) (*ssh.Certif
|
|||
// by provisioners to populate certificate fields.
|
||||
type Identity struct {
|
||||
Usernames []string `json:"usernames"`
|
||||
Permissions `json:"permissions"`
|
||||
}
|
||||
|
||||
// Permissions defines extra extensions and critical options to grant to an SSH certificate.
|
||||
type Permissions struct {
|
||||
Extensions map[string]string `json:"extensions"`
|
||||
CriticalOptions map[string]string `json:"criticalOptions"`
|
||||
}
|
||||
|
||||
// GetIdentityFunc is a function that returns an identity.
|
||||
|
|
|
@ -5,6 +5,7 @@ const (
|
|||
KeyIDKey = "KeyID"
|
||||
PrincipalsKey = "Principals"
|
||||
ExtensionsKey = "Extensions"
|
||||
CriticalOptionsKey = "CriticalOptions"
|
||||
TokenKey = "Token"
|
||||
InsecureKey = "Insecure"
|
||||
UserKey = "User"
|
||||
|
@ -70,6 +71,17 @@ func (t TemplateData) AddExtension(key, value string) {
|
|||
}
|
||||
}
|
||||
|
||||
// AddCriticalOption adds one critical option to the templates data.
|
||||
func (t TemplateData) AddCriticalOption(key, value string) {
|
||||
if m, ok := t[CriticalOptionsKey].(map[string]interface{}); ok {
|
||||
m[key] = value
|
||||
} else {
|
||||
t[CriticalOptionsKey] = map[string]interface{}{
|
||||
key: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets a key-value pair in the template data.
|
||||
func (t TemplateData) Set(key string, v interface{}) {
|
||||
t[key] = v
|
||||
|
@ -104,6 +116,12 @@ func (t TemplateData) SetExtensions(e map[string]interface{}) {
|
|||
t.Set(ExtensionsKey, e)
|
||||
}
|
||||
|
||||
// SetCriticalOptions sets the certificate critical options in the template
|
||||
// data.
|
||||
func (t TemplateData) SetCriticalOptions(o map[string]interface{}) {
|
||||
t.Set(CriticalOptionsKey, o)
|
||||
}
|
||||
|
||||
// SetToken sets the given token in the template data.
|
||||
func (t TemplateData) SetToken(v interface{}) {
|
||||
t.Set(TokenKey, v)
|
||||
|
@ -126,7 +144,8 @@ const DefaultCertificate = `{
|
|||
"type": "{{ .Type }}",
|
||||
"keyId": "{{ .KeyID }}",
|
||||
"principals": {{ toJson .Principals }},
|
||||
"extensions": {{ toJson .Extensions }}
|
||||
"extensions": {{ toJson .Extensions }},
|
||||
"criticalOptions": {{ toJson .CriticalOptions }}
|
||||
}`
|
||||
|
||||
const DefaultIIDCertificate = `{
|
||||
|
|
|
@ -157,6 +157,46 @@ func TestTemplateData_AddExtension(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTemplateData_AddCriticalOption(t *testing.T) {
|
||||
type args struct {
|
||||
key string
|
||||
value string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
t TemplateData
|
||||
args args
|
||||
want TemplateData
|
||||
}{
|
||||
{"empty", TemplateData{}, args{"key", "value"}, TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"key": "value"},
|
||||
}},
|
||||
{"overwrite", TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"key": "value"},
|
||||
}, args{"key", "value"}, TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
}},
|
||||
{"add", TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"foo": "bar"},
|
||||
}, args{"key", "value"}, TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{
|
||||
"key": "value",
|
||||
"foo": "bar",
|
||||
},
|
||||
}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.t.AddCriticalOption(tt.args.key, tt.args.value)
|
||||
if !reflect.DeepEqual(tt.t, tt.want) {
|
||||
t.Errorf("AddCriticalOption() = %v, want %v", tt.t, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateData_Set(t *testing.T) {
|
||||
type args struct {
|
||||
key string
|
||||
|
@ -325,6 +365,35 @@ func TestTemplateData_SetExtensions(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTemplateData_SetCriticalOptions(t *testing.T) {
|
||||
type args struct {
|
||||
e map[string]interface{}
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
t TemplateData
|
||||
args args
|
||||
want TemplateData
|
||||
}{
|
||||
{"ok", TemplateData{}, args{map[string]interface{}{"foo": "bar"}}, TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"foo": "bar"},
|
||||
}},
|
||||
{"overwrite", TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"foo": "bar"},
|
||||
}, args{map[string]interface{}{"key": "value"}}, TemplateData{
|
||||
CriticalOptionsKey: map[string]interface{}{"key": "value"},
|
||||
}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.t.SetCriticalOptions(tt.args.e)
|
||||
if !reflect.DeepEqual(tt.t, tt.want) {
|
||||
t.Errorf("SetCriticalOptions() = %v, want %v", tt.t, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateData_SetToken(t *testing.T) {
|
||||
type args struct {
|
||||
v interface{}
|
||||
|
|
Loading…
Reference in a new issue