@@ -1756,3 +1756,387 @@ describe('microsoft graph auth adapter', () => {
17561756 } ) ;
17571757 } ) ;
17581758} ) ;
1759+
1760+ describe ( 'facebook limited auth adapter' , ( ) => {
1761+ const facebook = require ( '../lib/Adapters/Auth/facebook' ) ;
1762+ const jwt = require ( 'jsonwebtoken' ) ;
1763+ const util = require ( 'util' ) ;
1764+
1765+ // TODO: figure out a way to run this test alongside facebook classic tests
1766+ xit ( '(using client id as string) should throw error with missing id_token' , async ( ) => {
1767+ try {
1768+ await facebook . validateAuthData ( { } , { clientId : 'secret' } ) ;
1769+ fail ( ) ;
1770+ } catch ( e ) {
1771+ expect ( e . message ) . toBe ( 'Facebook auth is not configured.' ) ;
1772+ }
1773+ } ) ;
1774+
1775+ // TODO: figure out a way to run this test alongside facebook classic tests
1776+ xit ( '(using client id as array) should throw error with missing id_token' , async ( ) => {
1777+ try {
1778+ await facebook . validateAuthData ( { } , { clientId : [ 'secret' ] } ) ;
1779+ fail ( ) ;
1780+ } catch ( e ) {
1781+ expect ( e . message ) . toBe ( 'Facebook auth is not configured.' ) ;
1782+ }
1783+ } ) ;
1784+
1785+ it ( 'should not decode invalid id_token' , async ( ) => {
1786+ try {
1787+ await facebook . validateAuthData (
1788+ { id : 'the_user_id' , token : 'the_token' } ,
1789+ { clientId : 'secret' }
1790+ ) ;
1791+ fail ( ) ;
1792+ } catch ( e ) {
1793+ expect ( e . message ) . toBe ( 'provided token does not decode as JWT' ) ;
1794+ }
1795+ } ) ;
1796+
1797+ it ( 'should throw error if public key used to encode token is not available' , async ( ) => {
1798+ const fakeDecodedToken = {
1799+ header : { kid : '789' , alg : 'RS256' } ,
1800+ } ;
1801+ try {
1802+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1803+
1804+ await facebook . validateAuthData (
1805+ { id : 'the_user_id' , token : 'the_token' } ,
1806+ { clientId : 'secret' }
1807+ ) ;
1808+ fail ( ) ;
1809+ } catch ( e ) {
1810+ expect ( e . message ) . toBe (
1811+ `Unable to find matching key for Key ID: ${ fakeDecodedToken . header . kid } `
1812+ ) ;
1813+ }
1814+ } ) ;
1815+
1816+ it ( 'should use algorithm from key header to verify id_token' , async ( ) => {
1817+ const fakeClaim = {
1818+ iss : 'https://facebook.com' ,
1819+ aud : 'secret' ,
1820+ exp : Date . now ( ) ,
1821+ sub : 'the_user_id' ,
1822+ } ;
1823+ const fakeDecodedToken = {
1824+ header : { kid : '123' , alg : 'RS256' } ,
1825+ } ;
1826+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1827+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
1828+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1829+ return {
1830+ kid : '123' ,
1831+ rsaPublicKey : 'the_rsa_public_key' ,
1832+ } ;
1833+ } ;
1834+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1835+
1836+ const result = await facebook . validateAuthData (
1837+ { id : 'the_user_id' , token : 'the_token' } ,
1838+ { clientId : 'secret' }
1839+ ) ;
1840+ expect ( result ) . toEqual ( fakeClaim ) ;
1841+ expect ( jwt . verify . calls . first ( ) . args [ 2 ] . algorithms ) . toEqual ( fakeDecodedToken . header . alg ) ;
1842+ } ) ;
1843+
1844+ it ( 'should not verify invalid id_token' , async ( ) => {
1845+ const fakeDecodedToken = {
1846+ header : { kid : '123' , alg : 'RS256' } ,
1847+ } ;
1848+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1849+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1850+ return {
1851+ kid : '123' ,
1852+ rsaPublicKey : 'the_rsa_public_key' ,
1853+ } ;
1854+ } ;
1855+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1856+
1857+ try {
1858+ await facebook . validateAuthData (
1859+ { id : 'the_user_id' , token : 'the_token' } ,
1860+ { clientId : 'secret' }
1861+ ) ;
1862+ fail ( ) ;
1863+ } catch ( e ) {
1864+ expect ( e . message ) . toBe ( 'jwt malformed' ) ;
1865+ }
1866+ } ) ;
1867+
1868+ it ( '(using client id as array) should not verify invalid id_token' , async ( ) => {
1869+ try {
1870+ await facebook . validateAuthData (
1871+ { id : 'the_user_id' , token : 'the_token' } ,
1872+ { clientId : [ 'secret' ] }
1873+ ) ;
1874+ fail ( ) ;
1875+ } catch ( e ) {
1876+ expect ( e . message ) . toBe ( 'provided token does not decode as JWT' ) ;
1877+ }
1878+ } ) ;
1879+
1880+ it ( '(using client id as string) should verify id_token' , async ( ) => {
1881+ const fakeClaim = {
1882+ iss : 'https://facebook.com' ,
1883+ aud : 'secret' ,
1884+ exp : Date . now ( ) ,
1885+ sub : 'the_user_id' ,
1886+ } ;
1887+ const fakeDecodedToken = {
1888+ header : { kid : '123' , alg : 'RS256' } ,
1889+ } ;
1890+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1891+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1892+ return {
1893+ kid : '123' ,
1894+ rsaPublicKey : 'the_rsa_public_key' ,
1895+ } ;
1896+ } ;
1897+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1898+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
1899+
1900+ const result = await facebook . validateAuthData (
1901+ { id : 'the_user_id' , token : 'the_token' } ,
1902+ { clientId : 'secret' }
1903+ ) ;
1904+ expect ( result ) . toEqual ( fakeClaim ) ;
1905+ } ) ;
1906+
1907+ it ( '(using client id as array) should verify id_token' , async ( ) => {
1908+ const fakeClaim = {
1909+ iss : 'https://facebook.com' ,
1910+ aud : 'secret' ,
1911+ exp : Date . now ( ) ,
1912+ sub : 'the_user_id' ,
1913+ } ;
1914+ const fakeDecodedToken = {
1915+ header : { kid : '123' , alg : 'RS256' } ,
1916+ } ;
1917+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1918+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1919+ return {
1920+ kid : '123' ,
1921+ rsaPublicKey : 'the_rsa_public_key' ,
1922+ } ;
1923+ } ;
1924+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1925+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
1926+
1927+ const result = await facebook . validateAuthData (
1928+ { id : 'the_user_id' , token : 'the_token' } ,
1929+ { clientId : [ 'secret' ] }
1930+ ) ;
1931+ expect ( result ) . toEqual ( fakeClaim ) ;
1932+ } ) ;
1933+
1934+ it ( '(using client id as array with multiple items) should verify id_token' , async ( ) => {
1935+ const fakeClaim = {
1936+ iss : 'https://facebook.com' ,
1937+ aud : 'secret' ,
1938+ exp : Date . now ( ) ,
1939+ sub : 'the_user_id' ,
1940+ } ;
1941+ const fakeDecodedToken = {
1942+ header : { kid : '123' , alg : 'RS256' } ,
1943+ } ;
1944+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1945+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1946+ return {
1947+ kid : '123' ,
1948+ rsaPublicKey : 'the_rsa_public_key' ,
1949+ } ;
1950+ } ;
1951+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1952+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
1953+
1954+ const result = await facebook . validateAuthData (
1955+ { id : 'the_user_id' , token : 'the_token' } ,
1956+ { clientId : [ 'secret' , 'secret 123' ] }
1957+ ) ;
1958+ expect ( result ) . toEqual ( fakeClaim ) ;
1959+ } ) ;
1960+
1961+ it ( '(using client id as string) should throw error with with invalid jwt issuer' , async ( ) => {
1962+ const fakeClaim = {
1963+ iss : 'https://not.facebook.com' ,
1964+ sub : 'the_user_id' ,
1965+ } ;
1966+ const fakeDecodedToken = {
1967+ header : { kid : '123' , alg : 'RS256' } ,
1968+ } ;
1969+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
1970+ const fakeGetSigningKeyAsyncFunction = ( ) => {
1971+ return {
1972+ kid : '123' ,
1973+ rsaPublicKey : 'the_rsa_public_key' ,
1974+ } ;
1975+ } ;
1976+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
1977+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
1978+
1979+ try {
1980+ await facebook . validateAuthData (
1981+ { id : 'the_user_id' , token : 'the_token' } ,
1982+ { clientId : 'secret' }
1983+ ) ;
1984+ fail ( ) ;
1985+ } catch ( e ) {
1986+ expect ( e . message ) . toBe (
1987+ 'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
1988+ ) ;
1989+ }
1990+ } ) ;
1991+
1992+ // TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
1993+ // and a private key
1994+ xit ( '(using client id as array) should throw error with with invalid jwt issuer' , async ( ) => {
1995+ const fakeClaim = {
1996+ iss : 'https://not.facebook.com' ,
1997+ sub : 'the_user_id' ,
1998+ } ;
1999+ const fakeDecodedToken = {
2000+ header : { kid : '123' , alg : 'RS256' } ,
2001+ } ;
2002+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
2003+ const fakeGetSigningKeyAsyncFunction = ( ) => {
2004+ return {
2005+ kid : '123' ,
2006+ rsaPublicKey : 'the_rsa_public_key' ,
2007+ } ;
2008+ } ;
2009+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
2010+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
2011+
2012+ try {
2013+ await facebook . validateAuthData (
2014+ {
2015+ id : 'INSERT ID HERE' ,
2016+ token : 'INSERT FACEBOOK TOKEN HERE WITH INVALID JWT ISSUER' ,
2017+ } ,
2018+ { clientId : [ 'INSERT CLIENT ID HERE' ] }
2019+ ) ;
2020+ fail ( ) ;
2021+ } catch ( e ) {
2022+ expect ( e . message ) . toBe (
2023+ 'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
2024+ ) ;
2025+ }
2026+ } ) ;
2027+
2028+ it ( '(using client id as string) should throw error with with invalid jwt issuer' , async ( ) => {
2029+ const fakeClaim = {
2030+ iss : 'https://not.facebook.com' ,
2031+ sub : 'the_user_id' ,
2032+ } ;
2033+ const fakeDecodedToken = {
2034+ header : { kid : '123' , alg : 'RS256' } ,
2035+ } ;
2036+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
2037+ const fakeGetSigningKeyAsyncFunction = ( ) => {
2038+ return {
2039+ kid : '123' ,
2040+ rsaPublicKey : 'the_rsa_public_key' ,
2041+ } ;
2042+ } ;
2043+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
2044+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
2045+
2046+ try {
2047+ await facebook . validateAuthData (
2048+ {
2049+ id : 'INSERT ID HERE' ,
2050+ token : 'INSERT FACEBOOK TOKEN HERE WITH INVALID JWT ISSUER' ,
2051+ } ,
2052+ { clientId : 'INSERT CLIENT ID HERE' }
2053+ ) ;
2054+ fail ( ) ;
2055+ } catch ( e ) {
2056+ expect ( e . message ) . toBe (
2057+ 'id token not issued by correct OpenID provider - expected: https://facebook.com | from: https://not.facebook.com'
2058+ ) ;
2059+ }
2060+ } ) ;
2061+
2062+ // TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
2063+ // and a private key
2064+ xit ( '(using client id as string) should throw error with invalid jwt clientId' , async ( ) => {
2065+ try {
2066+ await facebook . validateAuthData (
2067+ {
2068+ id : 'INSERT ID HERE' ,
2069+ token : 'INSERT FACEBOOK TOKEN HERE' ,
2070+ } ,
2071+ { clientId : 'secret' }
2072+ ) ;
2073+ fail ( ) ;
2074+ } catch ( e ) {
2075+ expect ( e . message ) . toBe ( 'jwt audience invalid. expected: secret' ) ;
2076+ }
2077+ } ) ;
2078+
2079+ // TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
2080+ // and a private key
2081+ xit ( '(using client id as array) should throw error with invalid jwt clientId' , async ( ) => {
2082+ try {
2083+ await facebook . validateAuthData (
2084+ {
2085+ id : 'INSERT ID HERE' ,
2086+ token : 'INSERT FACEBOOK TOKEN HERE' ,
2087+ } ,
2088+ { clientId : [ 'secret' ] }
2089+ ) ;
2090+ fail ( ) ;
2091+ } catch ( e ) {
2092+ expect ( e . message ) . toBe ( 'jwt audience invalid. expected: secret' ) ;
2093+ }
2094+ } ) ;
2095+
2096+ // TODO: figure out a way to generate our own facebook signed tokens, perhaps with a parse facebook account
2097+ // and a private key
2098+ xit ( 'should throw error with invalid user id' , async ( ) => {
2099+ try {
2100+ await facebook . validateAuthData (
2101+ {
2102+ id : 'invalid user' ,
2103+ token : 'INSERT FACEBOOK TOKEN HERE' ,
2104+ } ,
2105+ { clientId : 'INSERT CLIENT ID HERE' }
2106+ ) ;
2107+ fail ( ) ;
2108+ } catch ( e ) {
2109+ expect ( e . message ) . toBe ( 'auth data is invalid for this user.' ) ;
2110+ }
2111+ } ) ;
2112+
2113+ it ( 'should throw error with with invalid user id' , async ( ) => {
2114+ const fakeClaim = {
2115+ iss : 'https://facebook.com' ,
2116+ aud : 'invalid_client_id' ,
2117+ sub : 'a_different_user_id' ,
2118+ } ;
2119+ const fakeDecodedToken = {
2120+ header : { kid : '123' , alg : 'RS256' } ,
2121+ } ;
2122+ spyOn ( jwt , 'decode' ) . and . callFake ( ( ) => fakeDecodedToken ) ;
2123+ const fakeGetSigningKeyAsyncFunction = ( ) => {
2124+ return {
2125+ kid : '123' ,
2126+ rsaPublicKey : 'the_rsa_public_key' ,
2127+ } ;
2128+ } ;
2129+ spyOn ( util , 'promisify' ) . and . callFake ( ( ) => fakeGetSigningKeyAsyncFunction ) ;
2130+ spyOn ( jwt , 'verify' ) . and . callFake ( ( ) => fakeClaim ) ;
2131+
2132+ try {
2133+ await facebook . validateAuthData (
2134+ { id : 'the_user_id' , token : 'the_token' } ,
2135+ { clientId : 'secret' }
2136+ ) ;
2137+ fail ( ) ;
2138+ } catch ( e ) {
2139+ expect ( e . message ) . toBe ( 'auth data is invalid for this user.' ) ;
2140+ }
2141+ } ) ;
2142+ } ) ;
0 commit comments