@@ -21,6 +21,7 @@ import (
2121 "net/http"
2222 "net/http/httptest"
2323 "strings"
24+ "sync"
2425 "testing"
2526 "time"
2627
@@ -1811,6 +1812,213 @@ func TestThatTheSDKFetchesJWKSFromAllCoreHostsUntilAValidResponse(t *testing.T)
18111812 assert .True (t , strings .Contains (urlsAttemptedForJWKSFetch [1 ], "http://localhost:8080" ))
18121813}
18131814
1815+ func TestSessionVerificationOfJWTBasedOnSessionPayload (t * testing.T ) {
1816+ configValue := supertokens.TypeInput {
1817+ Supertokens : & supertokens.ConnectionInfo {
1818+ ConnectionURI : "http://localhost:8080" ,
1819+ },
1820+ AppInfo : supertokens.AppInfo {
1821+ APIDomain : "api.supertokens.io" ,
1822+ AppName : "SuperTokens" ,
1823+ WebsiteDomain : "supertokens.io" ,
1824+ },
1825+ RecipeList : []supertokens.Recipe {
1826+ Init (nil ),
1827+ },
1828+ }
1829+ BeforeEach ()
1830+ unittesting .StartUpST ("localhost" , "8080" )
1831+ defer AfterEach ()
1832+ err := supertokens .Init (configValue )
1833+ if err != nil {
1834+ t .Error (err .Error ())
1835+ }
1836+
1837+ session , err := CreateNewSessionWithoutRequestResponse ("testing" , map [string ]interface {}{}, map [string ]interface {}{}, nil )
1838+ if err != nil {
1839+ t .Error (err .Error ())
1840+ }
1841+
1842+ payload := session .GetAccessTokenPayload ()
1843+ delete (payload , "iat" )
1844+ delete (payload , "exp" )
1845+
1846+ currentTimeInSeconds := time .Now ()
1847+ jwtExpiry := uint64 ((currentTimeInSeconds .Add (10 * time .Second )).Unix ())
1848+ False := false
1849+ jwt , err := CreateJWT (payload , & jwtExpiry , & False )
1850+ if err != nil {
1851+ t .Error (err .Error ())
1852+ }
1853+
1854+ session , err = GetSessionWithoutRequestResponse (jwt .OK .Jwt , nil , nil )
1855+ if err != nil {
1856+ t .Error (err .Error ())
1857+ }
1858+
1859+ assert .Equal (t , session .GetUserID (), "testing" )
1860+ }
1861+
1862+ func TestSessionVerificationOfJWTBasedOnSessionPayloadWithCheckDatabase (t * testing.T ) {
1863+ configValue := supertokens.TypeInput {
1864+ Supertokens : & supertokens.ConnectionInfo {
1865+ ConnectionURI : "http://localhost:8080" ,
1866+ },
1867+ AppInfo : supertokens.AppInfo {
1868+ APIDomain : "api.supertokens.io" ,
1869+ AppName : "SuperTokens" ,
1870+ WebsiteDomain : "supertokens.io" ,
1871+ },
1872+ RecipeList : []supertokens.Recipe {
1873+ Init (nil ),
1874+ },
1875+ }
1876+ BeforeEach ()
1877+ unittesting .StartUpST ("localhost" , "8080" )
1878+ defer AfterEach ()
1879+ err := supertokens .Init (configValue )
1880+ if err != nil {
1881+ t .Error (err .Error ())
1882+ }
1883+
1884+ session , err := CreateNewSessionWithoutRequestResponse ("testing" , map [string ]interface {}{}, map [string ]interface {}{}, nil )
1885+ if err != nil {
1886+ t .Error (err .Error ())
1887+ }
1888+
1889+ payload := session .GetAccessTokenPayload ()
1890+ delete (payload , "iat" )
1891+ delete (payload , "exp" )
1892+ payload ["tId" ] = "public"
1893+
1894+ currentTimeInSeconds := time .Now ()
1895+ jwtExpiry := uint64 ((currentTimeInSeconds .Add (10 * time .Second )).Unix ())
1896+ False := false
1897+ jwt , err := CreateJWT (payload , & jwtExpiry , & False )
1898+ if err != nil {
1899+ t .Error (err .Error ())
1900+ }
1901+
1902+ True := true
1903+ session , err = GetSessionWithoutRequestResponse (jwt .OK .Jwt , nil , & sessmodels.VerifySessionOptions {
1904+ CheckDatabase : & True ,
1905+ })
1906+ if err != nil {
1907+ t .Error (err .Error ())
1908+ }
1909+
1910+ assert .Equal (t , session .GetUserID (), "testing" )
1911+ }
1912+
1913+ func TestThatLockingForJWKSCacheWorksFine (t * testing.T ) {
1914+ originalRefreshlimit := JWKRefreshRateLimit
1915+ originalCacheAge := JWKCacheMaxAgeInMs
1916+
1917+ JWKRefreshRateLimit = 100
1918+ JWKCacheMaxAgeInMs = 2000
1919+
1920+ configValue := supertokens.TypeInput {
1921+ Supertokens : & supertokens.ConnectionInfo {
1922+ ConnectionURI : "http://localhost:8080" ,
1923+ },
1924+ AppInfo : supertokens.AppInfo {
1925+ APIDomain : "api.supertokens.io" ,
1926+ AppName : "SuperTokens" ,
1927+ WebsiteDomain : "supertokens.io" ,
1928+ },
1929+ RecipeList : []supertokens.Recipe {
1930+ Init (nil ),
1931+ },
1932+ }
1933+ BeforeEach ()
1934+ unittesting .SetKeyValueInConfig ("access_token_dynamic_signing_key_update_interval" , "0.0014" )
1935+ unittesting .StartUpST ("localhost" , "8080" )
1936+ defer AfterEach ()
1937+ err := supertokens .Init (configValue )
1938+ if err != nil {
1939+ t .Error (err .Error ())
1940+ }
1941+
1942+ differentKeyFoundCount := 0
1943+ notReturnFromCacheCount := 0
1944+ keys := []string {}
1945+ shouldStop := false
1946+
1947+ jwks , err := GetCombinedJWKS ()
1948+ if err != nil {
1949+ t .Error (err .Error ())
1950+ }
1951+
1952+ for _ , k := range jwks .KIDs () {
1953+ keys = append (keys , k )
1954+ }
1955+
1956+ go func () {
1957+ time .Sleep (11 * time .Second )
1958+ shouldStop = true
1959+ }()
1960+
1961+ threadCount := 10
1962+ var wg sync.WaitGroup
1963+ wg .Add (threadCount )
1964+
1965+ for i := 0 ; i < threadCount ; i ++ {
1966+ go jwksLockTestRoutine (t , & shouldStop , i , & wg , func (_keys []string ) {
1967+ if returnedFromCache == false {
1968+ notReturnFromCacheCount ++
1969+ }
1970+
1971+ newKeys := []string {}
1972+
1973+ for _ , _k2 := range _keys {
1974+ if ! supertokens .DoesSliceContainString (_k2 , keys ) {
1975+ newKeys = append (newKeys , _k2 )
1976+ }
1977+ }
1978+
1979+ if len (newKeys ) != 0 {
1980+ differentKeyFoundCount ++
1981+ keys = _keys
1982+ }
1983+ })
1984+ }
1985+
1986+ wg .Wait ()
1987+
1988+ // We test for both
1989+ // - The keys changing
1990+ // - The number of times the result is not returned from cache
1991+ //
1992+ // Because even if the keys change only twice it could still mean that the SDK's cache locking
1993+ // does not work correctly and that it tried to query the core more times than it should have
1994+ //
1995+ // Checking for both the key change count and the cache miss count verifies the locking behaviour properly
1996+ //
1997+ // With the signing key interval as 5 seconds, and the test making requests for 11 seconds
1998+ // You expect the keys to change twice
1999+ assert .Equal (t , differentKeyFoundCount , 2 )
2000+ // With cache lifetime as 2 seconds, you expect the cache to miss 5 times
2001+ assert .Equal (t , notReturnFromCacheCount , 5 )
2002+
2003+ JWKRefreshRateLimit = originalRefreshlimit
2004+ JWKCacheMaxAgeInMs = originalCacheAge
2005+ }
2006+
2007+ func jwksLockTestRoutine (t * testing.T , shouldStop * bool , index int , group * sync.WaitGroup , doPost func ([]string )) {
2008+ jwks , err := GetCombinedJWKS ()
2009+ if err != nil {
2010+ t .Error (err .Error ())
2011+ }
2012+
2013+ doPost (jwks .KIDs ())
2014+ time .Sleep (100 * time .Millisecond )
2015+ if * shouldStop == false {
2016+ jwksLockTestRoutine (t , shouldStop , index , group , doPost )
2017+ } else {
2018+ group .Done ()
2019+ }
2020+ }
2021+
18142022type MockResponseWriter struct {}
18152023
18162024func (mw MockResponseWriter ) Header () http.Header {
0 commit comments