// Vikunja is a to-do list application to facilitate your life. // Copyright 2018-2021 Vikunja and contributors. All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public Licensee as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public Licensee for more details. // // You should have received a copy of the GNU Affero General Public Licensee // along with this program. If not, see . package identityawareproxy import ( "testing" "time" "github.com/dgrijalva/jwt-go" "github.com/lestrrat-go/jwx/jwk" "github.com/stretchr/testify/assert" ) /* Valid token with kid "sig-1606406403" and the following claims: { "aud": "vikunja-url", "email": "test@example.com", "exp": 1000, "iat": 1, "iss": "proxy-url", "sub": "12345", "user": "12345" }*/ var validToken = "eyJhbGciOiJFUzI1NiIsImtpZCI6InNpZy0xNjA2NDA2NDAzIiwidHlwIjoiSldUIn0.eyJhdWQiOiJ2aWt1bmphLXVybCIsImVtYWlsIjoidGVzdEBleGFtcGxlLmNvbSIsImV4cCI6MTAwMCwiaWF0IjoxLCJpc3MiOiJwcm94eS11cmwiLCJzdWIiOiIxMjM0NSIsInVzZXIiOiIxMjM0NSJ9.Shh0wxVaojGV2U2FQpgWgMjvU8QbjQSZcN062Qd-WShyyPG_vZsJwbBV6EVM5v_HdN2uMJN0HtEELEPBEM7Hiw" var validJwks = `{"keys":[{ "crv":"P-256", "kty":"EC", "use":"sig", "kid": "sig-1606406403", "x":"vejjjK-FfBOLU_Vz0t12dx1zmfdR2GseEnverHOKJKk", "y":"09pkYKAr51w8-k5s37_M9oBDU8nI4ALkLufTEumO-r4", "alg": "ES256" }]}` // Override time value for tests. Restore default value after. func at(t time.Time, f func()) { TimeFunc = func() time.Time { return t } f() TimeFunc = time.Now } func TestParseAndValidateJwt(t *testing.T) { // Run the test at a valid time for the JWT expiration at(time.Unix(50, 0), func() { t.Run("valid jwt and key within expiration", func(t *testing.T) { validKeySet, _ := jwk.ParseString(validJwks) cl, err := parseAndValidateJwt(validToken, validKeySet) assert.NoError(t, err) assert.Equal(t, &IAPClaims{ Email: "test@example.com", Name: "", PreferredUsername: "", StandardClaims: jwt.StandardClaims{ Audience: "vikunja-url", ExpiresAt: 1000, Id: "", IssuedAt: 1, Issuer: "proxy-url", NotBefore: 0, Subject: "12345", }, }, cl) }) }) // Run the test within the skew of the the expiration at(time.Unix(1059, 0), func() { t.Run("valid jwt and key past expiration within skew", func(t *testing.T) { validKeySet, _ := jwk.ParseString(validJwks) cl, err := parseAndValidateJwt(validToken, validKeySet) assert.NoError(t, err) assert.Equal(t, &IAPClaims{ Email: "test@example.com", Name: "", PreferredUsername: "", StandardClaims: jwt.StandardClaims{ Audience: "vikunja-url", ExpiresAt: 1000, Id: "", IssuedAt: 1, Issuer: "proxy-url", NotBefore: 0, Subject: "12345", }, }, cl) }) }) // Run the test outside the skew of the the expiration at(time.Unix(1061, 0), func() { t.Run("expired jwt", func(t *testing.T) { validKeySet, _ := jwk.ParseString(validJwks) cl, err := parseAndValidateJwt(validToken, validKeySet) assert.Nil(t, cl) assert.EqualError(t, err, "token is expired by 1m1s") }) }) t.Run("missing key", func(t *testing.T) { keySet, _ := jwk.ParseString(`{"keys":[{ "crv":"P-256", "kty":"EC", "use":"sig", "kid": "non-matching-sig", "x":"vejjjK-FfBOLU_Vz0t12dx1zmfdR2GseEnverHOKJKk", "y":"09pkYKAr51w8-k5s37_M9oBDU8nI4ALkLufTEumO-r4", "alg": "ES256" }]}`) cl, err := parseAndValidateJwt(validToken, keySet) assert.EqualError(t, err, "JWT missing KID") assert.Nil(t, cl) }) }