Allow alternative syntax for auth0 tenants as environment variable

This commit is contained in:
Ingo Oppermann 2023-01-02 11:39:58 +01:00
parent 391681447e
commit 992b04d180
No known key found for this signature in database
GPG key ID: 2AB32426E9DD229E
3 changed files with 107 additions and 25 deletions

View file

@ -4,6 +4,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url"
"strings" "strings"
) )
@ -16,6 +17,28 @@ type Auth0Tenant struct {
Users []string `json:"users"` Users []string `json:"users"`
} }
func (a *Auth0Tenant) String() string {
u := url.URL{
Scheme: "auth0",
Host: a.Domain,
}
if len(a.ClientID) != 0 {
u.User = url.User(a.ClientID)
}
q := url.Values{}
q.Set("aud", a.Audience)
for _, user := range a.Users {
q.Add("user", user)
}
u.RawQuery = q.Encode()
return u.String()
}
type TenantList struct { type TenantList struct {
p *[]Auth0Tenant p *[]Auth0Tenant
separator string separator string
@ -32,18 +55,34 @@ func NewTenantList(p *[]Auth0Tenant, val []Auth0Tenant, separator string) *Tenan
return v return v
} }
// Set allows to set a tenant list in two formats:
// - a separator separated list of bas64 encoded Auth0Tenant JSON objects
// - a separator separated list of Auth0Tenant in URL representation: auth0://[clientid]@[domain]?aud=[audience]&user=...&user=...
func (s *TenantList) Set(val string) error { func (s *TenantList) Set(val string) error {
list := []Auth0Tenant{} list := []Auth0Tenant{}
for i, elm := range strings.Split(val, s.separator) { for i, elm := range strings.Split(val, s.separator) {
data, err := base64.StdEncoding.DecodeString(elm)
if err != nil {
return fmt.Errorf("invalid base64 encoding of tenant %d: %w", i, err)
}
t := Auth0Tenant{} t := Auth0Tenant{}
if err := json.Unmarshal(data, &t); err != nil {
return fmt.Errorf("invalid JSON in tenant %d: %w", i, err) if strings.HasPrefix(elm, "auth0://") {
data, err := url.Parse(elm)
if err != nil {
return fmt.Errorf("invalid url encoding of tenant %d: %w", i, err)
}
t.Domain = data.Host
t.ClientID = data.User.Username()
t.Audience = data.Query().Get("aud")
t.Users = data.Query()["user"]
} else {
data, err := base64.StdEncoding.DecodeString(elm)
if err != nil {
return fmt.Errorf("invalid base64 encoding of tenant %d: %w", i, err)
}
if err := json.Unmarshal(data, &t); err != nil {
return fmt.Errorf("invalid JSON in tenant %d: %w", i, err)
}
} }
list = append(list, t) list = append(list, t)
@ -62,10 +101,10 @@ func (s *TenantList) String() string {
list := []string{} list := []string{}
for _, t := range *s.p { for _, t := range *s.p {
list = append(list, fmt.Sprintf("%s (%d users)", t.Domain, len(t.Users))) list = append(list, t.String())
} }
return strings.Join(list, ",") return strings.Join(list, s.separator)
} }
func (s *TenantList) Validate() error { func (s *TenantList) Validate() error {

View file

@ -0,0 +1,43 @@
package value
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestAuth0Value(t *testing.T) {
tenants := []Auth0Tenant{}
v := NewTenantList(&tenants, nil, " ")
require.Equal(t, "(empty)", v.String())
v.Set("auth0://clientid@domain?aud=audience&user=user1&user=user2 auth0://domain2?aud=audience2&user=user3")
require.Equal(t, []Auth0Tenant{
{
Domain: "domain",
ClientID: "clientid",
Audience: "audience",
Users: []string{"user1", "user2"},
},
{
Domain: "domain2",
Audience: "audience2",
Users: []string{"user3"},
},
}, tenants)
require.Equal(t, "auth0://clientid@domain?aud=audience&user=user1&user=user2 auth0://domain2?aud=audience2&user=user3", v.String())
require.NoError(t, v.Validate())
v.Set("eyJkb21haW4iOiJkYXRhcmhlaS5ldS5hdXRoMC5jb20iLCJhdWRpZW5jZSI6Imh0dHBzOi8vZGF0YXJoZWkuY29tL2NvcmUiLCJ1c2VycyI6WyJhdXRoMHx4eHgiXX0=")
require.Equal(t, []Auth0Tenant{
{
Domain: "datarhei.eu.auth0.com",
ClientID: "",
Audience: "https://datarhei.com/core",
Users: []string{"auth0|xxx"},
},
}, tenants)
require.Equal(t, "auth0://datarhei.eu.auth0.com?aud=https%3A%2F%2Fdatarhei.com%2Fcore&user=auth0%7Cxxx", v.String())
require.NoError(t, v.Validate())
}

View file

@ -3,7 +3,7 @@ package value
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/require"
) )
func TestIntValue(t *testing.T) { func TestIntValue(t *testing.T) {
@ -11,19 +11,19 @@ func TestIntValue(t *testing.T) {
ivar := NewInt(&i, 11) ivar := NewInt(&i, 11)
assert.Equal(t, "11", ivar.String()) require.Equal(t, "11", ivar.String())
assert.Equal(t, nil, ivar.Validate()) require.Equal(t, nil, ivar.Validate())
assert.Equal(t, false, ivar.IsEmpty()) require.Equal(t, false, ivar.IsEmpty())
i = 42 i = 42
assert.Equal(t, "42", ivar.String()) require.Equal(t, "42", ivar.String())
assert.Equal(t, nil, ivar.Validate()) require.Equal(t, nil, ivar.Validate())
assert.Equal(t, false, ivar.IsEmpty()) require.Equal(t, false, ivar.IsEmpty())
ivar.Set("77") ivar.Set("77")
assert.Equal(t, int(77), i) require.Equal(t, int(77), i)
} }
type testdata struct { type testdata struct {
@ -37,22 +37,22 @@ func TestCopyStruct(t *testing.T) {
NewInt(&data1.value1, 1) NewInt(&data1.value1, 1)
NewInt(&data1.value2, 2) NewInt(&data1.value2, 2)
assert.Equal(t, int(1), data1.value1) require.Equal(t, int(1), data1.value1)
assert.Equal(t, int(2), data1.value2) require.Equal(t, int(2), data1.value2)
data2 := testdata{} data2 := testdata{}
val21 := NewInt(&data2.value1, 3) val21 := NewInt(&data2.value1, 3)
val22 := NewInt(&data2.value2, 4) val22 := NewInt(&data2.value2, 4)
assert.Equal(t, int(3), data2.value1) require.Equal(t, int(3), data2.value1)
assert.Equal(t, int(4), data2.value2) require.Equal(t, int(4), data2.value2)
data2 = data1 data2 = data1
assert.Equal(t, int(1), data2.value1) require.Equal(t, int(1), data2.value1)
assert.Equal(t, int(2), data2.value2) require.Equal(t, int(2), data2.value2)
assert.Equal(t, "1", val21.String()) require.Equal(t, "1", val21.String())
assert.Equal(t, "2", val22.String()) require.Equal(t, "2", val22.String())
} }