diff --git a/go.mod b/go.mod index cc9f60b..d4375da 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.15 require ( github.com/caos/logging v0.0.0-20191210002624-b3260f690a6a github.com/golang/mock v1.4.4 - github.com/google/go-cmp v0.4.1 // indirect + github.com/google/go-cmp v0.5.2 // indirect github.com/google/go-github/v31 v31.0.0 github.com/google/uuid v1.1.2 github.com/gorilla/handlers v1.5.0 @@ -15,11 +15,11 @@ require ( github.com/kr/pretty v0.1.0 // indirect github.com/sirupsen/logrus v1.6.0 github.com/stretchr/testify v1.6.1 - golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1 // indirect - golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 + golang.org/x/net v0.0.0-20200822124328-c89045814202 golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c golang.org/x/text v0.3.3 + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.5 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/square/go-jose.v2 v2.5.1 ) diff --git a/go.sum b/go.sum index eee02f9..b1658e8 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo= github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= @@ -52,16 +52,16 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1 h1:anGSYQpPhQwXlwsu5wmfq0nWkCNaMEMUwAv13Y92hd8= -golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933 h1:e6HwijUxhDe+hPNjZQQn9bA5PW3vNmnN64U2ZW759Lk= -golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c h1:HjRaKPaiWks0f5tA6ELVF7ZfqSppfPwOEEAvsrKUTO4= golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -72,6 +72,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab h1:FvshnhkKW+LO3HWHodML8kuVX8rnJTxKm9dFPuI68UM= golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -81,14 +83,16 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= diff --git a/pkg/oidc/grants/tokenexchange/tokenexchange.go b/pkg/oidc/grants/tokenexchange/tokenexchange.go index 02a9808..4df0e80 100644 --- a/pkg/oidc/grants/tokenexchange/tokenexchange.go +++ b/pkg/oidc/grants/tokenexchange/tokenexchange.go @@ -22,6 +22,10 @@ type TokenExchangeRequest struct { requestedTokenType string `schema:"requested_token_type"` } +type JWTProfileRequest struct { + assertion string `schema:"assertion"` +} + func NewTokenExchangeRequest(subjectToken, subjectTokenType string, opts ...TokenExchangeOption) *TokenExchangeRequest { t := &TokenExchangeRequest{ grantType: TokenExchangeGrantType, diff --git a/pkg/oidc/token.go b/pkg/oidc/token.go index 61267d7..2e4cf9c 100644 --- a/pkg/oidc/token.go +++ b/pkg/oidc/token.go @@ -59,6 +59,30 @@ type IDTokenClaims struct { Signature jose.SignatureAlgorithm //TODO: ??? } +type JWTProfileAssertion struct { + PrivateKeyID string + PrivateKey []byte + Scopes []string + Issuer string + Subject string + Audience []string + Expiration time.Time + IssuedAt time.Time +} + +func NewJWTProfileAssertion(userID, keyID string, audience []string, key []byte) *JWTProfileAssertion { + return &JWTProfileAssertion{ + PrivateKey: key, + PrivateKeyID: keyID, + Issuer: userID, + Scopes: []string{ScopeOpenID}, + Subject: userID, + IssuedAt: time.Now().UTC(), + Expiration: time.Now().Add(1 * time.Hour).UTC(), + Audience: audience, + } +} + type jsonToken struct { Issuer string `json:"iss,omitempty"` Subject string `json:"sub,omitempty"` @@ -213,6 +237,34 @@ func (t *IDTokenClaims) SetSignature(alg jose.SignatureAlgorithm) { t.Signature = alg } +func (t *JWTProfileAssertion) MarshalJSON() ([]byte, error) { + j := jsonToken{ + Issuer: t.Issuer, + Subject: t.Subject, + Audiences: t.Audience, + Expiration: timeToJSON(t.Expiration), + IssuedAt: timeToJSON(t.IssuedAt), + Scopes: strings.Join(t.Scopes, " "), + } + return json.Marshal(j) +} + +func (t *JWTProfileAssertion) UnmarshalJSON(b []byte) error { + var j jsonToken + if err := json.Unmarshal(b, &j); err != nil { + return err + } + + t.Issuer = j.Issuer + t.Subject = j.Subject + t.Audience = audienceFromJSON(j.Audiences) + t.Expiration = time.Unix(j.Expiration, 0).UTC() + t.IssuedAt = time.Unix(j.IssuedAt, 0).UTC() + t.Scopes = strings.Split(j.Scopes, " ") + + return nil +} + func (j *jsonToken) UnmarshalUserinfoProfile() UserinfoProfile { locale, _ := language.Parse(j.Locale) return UserinfoProfile{ diff --git a/pkg/oidc/userinfo.go b/pkg/oidc/userinfo.go index d0fe4a8..eb670fb 100644 --- a/pkg/oidc/userinfo.go +++ b/pkg/oidc/userinfo.go @@ -105,7 +105,7 @@ func (i *Userinfo) UnmmarshalJSON(data []byte) error { if err := json.Unmarshal(data, i); err != nil { return err } - return json.Unmarshal(data, i.claims) + return json.Unmarshal(data, &i.claims) } type jsonUserinfo struct { diff --git a/pkg/rp/relaying_party.go b/pkg/rp/relaying_party.go index 43d0c97..f3eac94 100644 --- a/pkg/rp/relaying_party.go +++ b/pkg/rp/relaying_party.go @@ -14,9 +14,10 @@ import ( ) const ( - idTokenKey = "id_token" - stateParam = "state" - pkceCode = "pkce" + idTokenKey = "id_token" + stateParam = "state" + pkceCode = "pkce" + jwtProfileKey = "urn:ietf:params:oauth:grant-type:jwt-bearer" ) //RelayingParty declares the minimal interface for oidc clients @@ -346,6 +347,24 @@ func CallTokenEndpoint(request interface{}, rp RelayingParty) (newToken *oauth2. return token, nil } +func CallJWTProfileEndpoint(assertion string, rp RelayingParty) (*oauth2.Token, error) { + form := make(map[string][]string) + form["assertion"] = []string{assertion} + form["grant_type"] = []string{jwtProfileKey} + req, err := http.NewRequest("POST", rp.OAuthConfig().Endpoint.TokenURL, nil) + if err != nil { + return nil, err + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + token := new(oauth2.Token) + if err := utils.HttpRequest(rp.HttpClient(), req, token); err != nil { + return nil, err + } + return token, nil +} + func trySetStateCookie(w http.ResponseWriter, state string, rp RelayingParty) error { if rp.CookieHandler() != nil { if err := rp.CookieHandler().SetCookie(w, stateParam, state); err != nil { diff --git a/pkg/rp/tockenexchange.go b/pkg/rp/tockenexchange.go index 29929b4..62913e0 100644 --- a/pkg/rp/tockenexchange.go +++ b/pkg/rp/tockenexchange.go @@ -2,9 +2,15 @@ package rp import ( "context" + "crypto/rsa" + "crypto/x509" + "encoding/json" + "encoding/pem" "golang.org/x/oauth2" + "gopkg.in/square/go-jose.v2" + "github.com/caos/oidc/pkg/oidc" "github.com/caos/oidc/pkg/oidc/grants/tokenexchange" ) @@ -37,3 +43,54 @@ func TokenExchange(ctx context.Context, request *tokenexchange.TokenExchangeRequ func DelegationTokenExchange(ctx context.Context, subjectToken string, rp RelayingParty, reqOpts ...tokenexchange.TokenExchangeOption) (newToken *oauth2.Token, err error) { return TokenExchange(ctx, DelegationTokenRequest(subjectToken, reqOpts...), rp) } + +func JWTProfileExchange(ctx context.Context, assertion *oidc.JWTProfileAssertion, rp RelayingParty) (*oauth2.Token, error) { + token, err := generateJWTProfileToken(assertion) + if err != nil { + return nil, err + } + return CallJWTProfileEndpoint(token, rp) +} + +func generateJWTProfileToken(assertion *oidc.JWTProfileAssertion) (string, error) { + privateKey, err := bytesToPrivateKey(assertion.PrivateKey) + if err != nil { + return "", err + } + key := jose.SigningKey{ + Algorithm: jose.RS256, + Key: &jose.JSONWebKey{Key: privateKey, KeyID: assertion.PrivateKeyID}, + } + signer, err := jose.NewSigner(key, &jose.SignerOptions{}) + if err != nil { + return "", err + } + + jsonadsk, err := json.Marshal(assertion) + if err != nil { + return "", err + } + signiert, err := signer.Sign(jsonadsk) + if err != nil { + return "", err + } + return signiert.CompactSerialize() +} + +func bytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(priv) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil, err + } + } + key, err := x509.ParsePKCS1PrivateKey(b) + if err != nil { + return nil, err + } + return key, nil +} diff --git a/pkg/rp/tockenexchange_test.go b/pkg/rp/tockenexchange_test.go new file mode 100644 index 0000000..d84eb88 --- /dev/null +++ b/pkg/rp/tockenexchange_test.go @@ -0,0 +1,72 @@ +package rp + +import ( + "testing" + + "github.com/caos/oidc/pkg/oidc" +) + +func TestGenerateJWTProfileToken(t *testing.T) { + type args struct { + assertion *oidc.JWTProfileAssertion + } + type res struct { + wantErr bool + // token string + } + tests := []struct { + name string + args args + res res + }{ + { + name: "valid", + args: args{ + assertion: oidc.NewJWTProfileAssertion("service-account-id", "key-id", []string{"http://localhost:50002/oauth/v2/"}, []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAsqxKigKty6jBIuDtO9AIGdTNo0VMe/QoYlHPxDQtgKhdXjD7 +GNVLlr4qy+28Slo/Nph5/UFIc6BhXUGCK0JSRDoXukB36UnZblT/xyjz9NLzAEsk +HKCBhkJL7uuSRDvj9L367/02QhSzYh00vi6sG+d4cUuD3n4oZwf0IifZy4OJBX2R +SX2sV8Lh3eR39UrnA2qiwRPQmToVPu1x18BphvE9kZtVzTvy/d0VXtEcNJDvYNuH +kYM3DLzzR0+DCDS8bo7IaX8i1TQoO8y5rXlZ5C7+FdAa15lt5N+A0Lfz7hu45s+r +OCcp2s6IvsRZKV4HWhEhnQuoRdXQmpnQGlFnFQIDAQABAoIBABY41YB6utDkqTjE +Tt0sj4Ve8UCIQu37vPYVhMi7UJl61zn6z5AUHzWda0c3xz5cIRaSOkHkV7WB0fo+ +RolI02CG9SKGGCPcun09dx53GnhtsCluLwycbd+b6UPK6sMvy7dJ1ab5kEEBwBnI +1iF9Poyt6k30/W6ztCS0WYnR+QWVnhtMPBRtzeSAb8OdKRQsNRKWgN+BK7VzCFls +jr4tvwdq/5WWLmYYqeteVK8nt9muJGUdmqS8UBf0D1Qo2/Ob+UKIE3ff/VlaEW+g +YhVkKspUYkuOWERk4awEkExZ0zoTkEKv4BgL53a41KO3UV8GIkSW8W8SfIL1aIEt +aPvm6XUCgYEA57HtG2GWJIozBbBlxT1UC2I0hFW37+JETx7ingcsjNxobQZftWZc +36PwZ4kmLxLJIinuFdEK7ghfm4123PUaKxH4gNXMzO7rzF2pskD902uaDijpkd1c +asXSIzy7MnG2ipEmxbqD3wPa7Lm9RCwl1ldCfOkZpkilsgBEAkWGtosCgYEAxWp7 +F4GlcI1S6/lUdxDeem5QTEYLuE45prQhT0jiFzxDT3kuX4mK/4A7wryPif+UCksf +U5cbo65l+IYc3JUx2DtZARHALdg7BHiaYqsx3qWVM0OokwEstbSrLT6+jSolegSf ++9LghTS5ZowkighyiW5OsJMIehuHowdSH9NZrN8CgYA6XHsZNo+XTKhlenVoJXaS +F36bBux6JEiIlYMHw07ZfHthWwWor8wdGTJpIgbYPKclT+KE5E8Yfkt25z9VkPey +eaha63/W7ye+JqmkGPLW2nfHsU6ES3oH+yRfc+DDaBlO9hkKHV0yQ8pVbsPZ9DTj +tL8ur5iiZhI2sBJxcAnq2QKBgQC4DnTBD8DdVQXQuF9Fu1aRszPuSQg4R8Z8ZEkC +EKOqoibne8X+kNAlMruE7iSttrmhdzS3zJSaYMj1kqRqDDeysHJlCtWwaH9txbu6 +7n3KZXrbluMeW+QBbXaC8pLaLkdOoe0+7fciemu47kRK5WFUPKHlAtDOd8hX+UVa +IsTi5QKBgCCfYiuTdesjMKAc3UQ0zjVYAxS1HqJh7V5McqscFx3D3uxg1JJcojwc +QOsG4gLgcCbr3kBkQLDHC+ZTjKgJ7OTVUf6To5yz2WlrDL+0YN+TmA8fpQR/rL2y +VgGFLpjDn3JtxGFwhV2CCwrC/ZCSut2L8IGi5+KtwMUW8clN9skR +-----END RSA PRIVATE KEY----- +`)), + }, + res: res{ + wantErr: false, + // token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZCJ9.eyJpc3MiOiJzZXJ2aWNlLWFjY291bnQtaWQiLCJzdWIiOiJzZXJ2aWNlLWFjY291bnQtaWQiLCJhdWQiOlsiaHR0cDovL2xvY2FsaG9zdDo1MDAwMi9vYXV0aC92Mi8iXSwiZXhwIjoxNjAwMjYxNDQyLCJpYXQiOjE2MDAyNTc4NDIsInNjb3BlIjoib3BlbmlkIn0.c9w4al8NfWboMbp9U4j34SnMFei_RH7ajowE-B6GT0mTZRoSRR5lldti6aFObbyraYbpEbTmrH3LalSVTeQwkD0tRKMll3pNyHZ0OtsZQEVLKLtFZG5F3lmB5sbuRLkIRmh7lRad1o9NR2PVqCMJjbBqPRaUADhUaWnY5oTHt5xdt_T--VJfo871TG_Hcp8J-uAvyDqzccX6jrx4jG0t_q1ps1EUwkdzILb_ezv3PTb3YF9sj1lNuDs4dOJGKjBJNdHvhO_ofNMfb6wewmXF5hzZgO72PC7h1Pr__xRcuemO4VIpC1lb24lyYbM1Yg3m5z_e0ByU4dI0ePh-FPBsWQ", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := generateJWTProfileToken(tt.args.assertion) + if (err != nil) != tt.res.wantErr { + t.Errorf("generateJWTProfileToken() error = %v, wantErr %v", err, tt.res.wantErr) + return + } + // if !reflect.DeepEqual(got, tt.res.token) { + // t.Errorf("generateJWTProfileToken() = %q, want %q", got, tt.res.token) + // } + }) + } +}