api/pkg/modules/auth/identityawareproxy/middleware_test.go

131 lines
3.9 KiB
Go

// 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 <https://www.gnu.org/licenses/>.
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)
})
}