blob: 07d8df8bcf1d75c5ab834f656c8b9b23d4adadef [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
import (
"fmt"
"reflect"
"testing"
"time"
)
var (
// thirdPartyJwt is generated in a testing K8s cluster, using the "istio-token" projected volume.
// Token is issued at 2020-04-04 22:13:54 Pacific Daylight time.
// Expiration time is 2020-04-05 10:13:54 Pacific Daylight time.
thirdPartyJwt = "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9." +
"eyJhdWQiOlsieW9uZ2dhbmdsLWlzdGlvLTQuc3ZjLmlkLmdvb2ciXSwiZXhwIjoxNTg2MTA2ODM0LCJpYXQiOjE1" +
"ODYwNjM2MzQsImlzcyI6Imh0dHBzOi8vY29udGFpbmVyLmdvb2dsZWFwaXMuY29tL3YxL3Byb2plY3RzL3lvbmdn" +
"YW5nbC1pc3Rpby00L2xvY2F0aW9ucy91cy1jZW50cmFsMS1hL2NsdXN0ZXJzL2NsdXN0ZXItMyIsImt1YmVybmV0" +
"ZXMuaW8iOnsibmFtZXNwYWNlIjoiZm9vIiwicG9kIjp7Im5hbWUiOiJodHRwYmluLTY0Nzc2YmY3OGQtanFsNWIi" +
"LCJ1aWQiOiI5YWQ3NTcxYi03NjBhLTExZWEtODllNy00MjAxMGE4MDAxYzEifSwic2VydmljZWFjY291bnQiOnsi" +
"bmFtZSI6Imh0dHBiaW4iLCJ1aWQiOiI5OWY2NWY1MC03NjBhLTExZWEtODllNy00MjAxMGE4MDAxYzEifX0sIm5i" +
"ZiI6MTU4NjA2MzYzNCwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmZvbzpodHRwYmluIn0.XWSCdarBR0cx" +
"MlVV5X9pvgI9m0lyO-17B45aBKJBIQjvjluKXqxnCuIeD3X2ItLkCUzmKUa3ftTjUUov1MJ89MdBngNfUP7IfwnD" +
"2dBl7Jtju0-Ks7aTFOkgtoMYqNnQ1VSDTAOfNpdZVUnsR_oY8obXSQR_H4uMcaNOGED2RX5HLBWFlvymtn4JXuyg" +
"_rpOrJ8dv-snrmO3LT9y-zaUnZqSceDC8skzStrJIRvsRkO8GEcoQd5VwDn-UVgOcqWb-S-vgSjdtwBsnGPXsh_I" +
"NZCq3ftr0Qu8-IxsIjpMjhLmAGTH1bR324aqLTYhAXp6fk06Pe3T9stCY5acSeadKA"
// firstPartyJwt is generated in a testing K8s cluster. It is the default service account JWT.
// No expiration time.
firstPartyJwt = "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9." +
"eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9u" +
"YW1lc3BhY2UiOiJmb28iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiaHR0cGJp" +
"bi10b2tlbi14cWRncCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUi" +
"OiJodHRwYmluIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiOTlm" +
"NjVmNTAtNzYwYS0xMWVhLTg5ZTctNDIwMTBhODAwMWMxIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmZv" +
"bzpodHRwYmluIn0.4kIl9TRjXEw6DfhtR-LdpxsAlYjJgC6Ly1DY_rqYY4h0haxcXB3kYZ3b2He-3fqOBryz524W" +
"KkZscZgvs5L-sApmvlqdUG61TMAl7josB0x4IMHm1NS995LNEaXiI4driffwfopvqc_z3lVKfbF9j-mBgnCepxz3" +
"UyWo5irFa3qcwbOUB9kuuUNGBdtbFBN5yIYLpfa9E-MtTX_zJ9fQ9j2pi8Z4ljii0tEmPmRxokHkmG_xNJjUkxKU" +
"WZf4bLDdCEjVFyshNae-FdxiUVyeyYorTYzwZZYQch9MJeedg4keKKUOvCCJUlKixd2qAe-H7r15RPmo4AU5O5YL" +
"65xiNg"
// oneAudString includes one `aud` claim "abc" of type string.
oneAudString = "header.eyJhdWQiOiJhYmMiLCJleHAiOjQ3MzI5OTQ4MDEsImlhdCI6MTU3OTM5NDgwMSwiaXNzIjoidGVzdC1pc3N1ZXItMUBpc3Rpby5pbyIsInN1YiI6InN1Yi0xIn0.signature" // nolint: lll
// twoAudList includes two `aud` claims ["abc", "xyz"] of type []string.
twoAudList = "header.eyJhdWQiOlsiYWJjIiwieHl6Il0sImV4cCI6NDczMjk5NDgwMSwiaWF0IjoxNTc5Mzk0ODAxLCJpc3MiOiJ0ZXN0LWlzc3Vlci0xQGlzdGlvLmlvIiwic3ViIjoic3ViLTEifQ.signature" // nolint: lll
)
func TestGetExp(t *testing.T) {
testCases := map[string]struct {
jwt string
expectedExp time.Time
expectedErr error
}{
"jwt with expiration time": {
jwt: thirdPartyJwt,
expectedExp: time.Date(2020, time.April, 5, 10, 13, 54, 0, time.FixedZone("PDT", -int((7*time.Hour).Seconds()))),
expectedErr: nil,
},
"jwt with no expiration time": {
jwt: firstPartyJwt,
expectedExp: time.Time{},
expectedErr: nil,
},
"invalid jwt": {
jwt: "invalid-section1.invalid-section2.invalid-section3",
expectedExp: time.Time{},
expectedErr: fmt.Errorf("failed to decode the JWT claims"),
},
}
for id, tc := range testCases {
t.Run(id, func(t *testing.T) {
exp, err := GetExp(tc.jwt)
if err != nil && tc.expectedErr == nil || err == nil && tc.expectedErr != nil {
t.Errorf("%s: Got error \"%v\", expected error \"%v\"", id, err, tc.expectedErr)
} else if err != nil && tc.expectedErr != nil && err.Error() != tc.expectedErr.Error() {
t.Errorf("%s: Got error \"%v\", expected error \"%v\"", id, err, tc.expectedErr)
} else if err == nil && exp.Sub(tc.expectedExp) != time.Duration(0) {
t.Errorf("%s: Got expiration time: %s, expected expiration time: %s",
id, exp.String(), tc.expectedExp.String())
}
})
}
}
func TestGetAud(t *testing.T) {
testCases := map[string]struct {
jwt string
aud []string
}{
"no audience": {
jwt: firstPartyJwt,
},
"one audience string": {
jwt: oneAudString,
aud: []string{"abc"},
},
"one audience list": {
jwt: thirdPartyJwt,
aud: []string{"yonggangl-istio-4.svc.id.goog"},
},
"two audiences list": {
jwt: twoAudList,
aud: []string{"abc", "xyz"},
},
}
for id, tc := range testCases {
t.Run(id, func(t *testing.T) {
if got, _ := GetAud(tc.jwt); !reflect.DeepEqual(tc.aud, got) {
t.Errorf("want audience %v but got %v", tc.aud, got)
}
})
}
}
func Test3p(t *testing.T) {
for _, s := range []string{thirdPartyJwt, "InvalidToken"} {
if IsK8SUnbound(s) {
t.Error("Expecting bound token, detected unbound ", s)
}
}
for _, s := range []string{firstPartyJwt, ".bnVsbM."} {
if !IsK8SUnbound(s) {
t.Error("Expecting unbound, detected bound ", s)
}
}
}