github.com/avenga/couper@v1.12.2/eval/lib/jwt_test.go (about) 1 package lib_test 2 3 import ( 4 "context" 5 "encoding/base64" 6 "encoding/json" 7 "fmt" 8 "net/http" 9 "net/http/httptest" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/zclconf/go-cty/cty" 15 "github.com/zclconf/go-cty/cty/function/stdlib" 16 17 "github.com/avenga/couper/config/configload" 18 "github.com/avenga/couper/config/request" 19 "github.com/avenga/couper/errors" 20 "github.com/avenga/couper/eval" 21 "github.com/avenga/couper/eval/lib" 22 "github.com/avenga/couper/internal/test" 23 ) 24 25 func TestJwtSignStatic(t *testing.T) { 26 tests := []struct { 27 name string 28 hcl string 29 jspLabel string 30 claims string 31 want string 32 }{ 33 { 34 "HS256 / key", 35 ` 36 server "test" { 37 } 38 definitions { 39 jwt_signing_profile "MyToken" { 40 signature_algorithm = "HS256" 41 key = "$3cRe4" 42 ttl = "0" 43 claims = { 44 iss = to_lower("The_Issuer") 45 aud = to_upper("The_Audience") 46 } 47 } 48 } 49 `, 50 "MyToken", 51 `{"sub":"12345"}`, 52 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.Hf-ZtIlsxR2bDOdAEMaDHaOBmfVWTQi9U68yV4YHW9w", 53 }, 54 { 55 "HS256 / key_file", 56 ` 57 server "test" { 58 } 59 definitions { 60 jwt_signing_profile "MyToken" { 61 signature_algorithm = "HS256" 62 key_file = "testdata/secret.txt" 63 ttl = "0" 64 claims = { 65 iss = to_lower("The_Issuer") 66 aud = to_upper("The_Audience") 67 } 68 } 69 } 70 `, 71 "MyToken", 72 `{"sub":"12345"}`, 73 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.Hf-ZtIlsxR2bDOdAEMaDHaOBmfVWTQi9U68yV4YHW9w", 74 }, 75 { 76 "HS384 / key", 77 ` 78 server "test" { 79 } 80 definitions { 81 jwt_signing_profile "MyToken" { 82 signature_algorithm = "HS384" 83 key = "$3cRe4" 84 ttl = "0" 85 claims = { 86 iss = to_lower("The_Issuer") 87 aud = to_upper("The_Audience") 88 } 89 } 90 } 91 `, 92 "MyToken", 93 `{"sub":"12345"}`, 94 "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.fYh9VOfe9jv926lwyjNMHr98zqesELs-2v0feqqDByor7rlnHHUdWdZXkTcPRaDa", 95 }, 96 { 97 "HS384 / key_file", 98 ` 99 server "test" { 100 } 101 definitions { 102 jwt_signing_profile "MyToken" { 103 signature_algorithm = "HS384" 104 key_file = "testdata/secret.txt" 105 ttl = "0" 106 claims = { 107 iss = to_lower("The_Issuer") 108 aud = to_upper("The_Audience") 109 } 110 } 111 } 112 `, 113 "MyToken", 114 `{"sub":"12345"}`, 115 "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.fYh9VOfe9jv926lwyjNMHr98zqesELs-2v0feqqDByor7rlnHHUdWdZXkTcPRaDa", 116 }, 117 { 118 "HS512 / key", 119 ` 120 server "test" { 121 } 122 definitions { 123 jwt_signing_profile "MyToken" { 124 signature_algorithm = "HS512" 125 key = "$3cRe4" 126 ttl = "0" 127 claims = { 128 iss = to_lower("The_Issuer") 129 aud = to_upper("The_Audience") 130 } 131 } 132 } 133 `, 134 "MyToken", 135 `{"sub":"12345"}`, 136 "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.LCzGZMYxwLAra2tHNDFBCSKVzMdZeZGxhgGuVr0e9mHDXMqpyOiCBWN2JB-9aDUNPHobwxEWofPY8M9icL3YXQ", 137 }, 138 { 139 "HS512 / key_file", 140 ` 141 server "test" { 142 } 143 definitions { 144 jwt_signing_profile "MyToken" { 145 signature_algorithm = "HS512" 146 key_file = "testdata/secret.txt" 147 ttl = "0" 148 claims = { 149 iss = to_lower("The_Issuer") 150 aud = to_upper("The_Audience") 151 } 152 } 153 } 154 `, 155 "MyToken", 156 `{"sub":"12345"}`, 157 "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.LCzGZMYxwLAra2tHNDFBCSKVzMdZeZGxhgGuVr0e9mHDXMqpyOiCBWN2JB-9aDUNPHobwxEWofPY8M9icL3YXQ", 158 }, 159 { 160 "RS256 / PKCS#8 key", 161 ` 162 server "test" { 163 } 164 definitions { 165 jwt_signing_profile "MyToken" { 166 signature_algorithm = "RS256" 167 key = <<EOF 168 -----BEGIN PRIVATE KEY----- 169 MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMZJ36xJOyza465U 170 kqm6akUBqaW3UJYsxMBk0BpsXvVSvQ/q7zfdGEAiNcNID9B5WK3O+q8Jmk21s4lV 171 6BpESoswmq8U5SQV0s1E/d/1eNgUW+5ujT21yNfqgYREQoOosbYx9nZnwtXO4lzp 172 LBkyBUWT/ret0A5yLdb27fM5IaPhAgMBAAECgYAzMjWvDQVbUnTAuRNZAUmY4ZIE 173 uGz1KT/vkNfuSpbF7oPkDTuQh+RQAsUw03VJ1VrhHXS6JteRQt3FEsonpgQ8sYA3 174 dSZ1ucEbFn58cApjc/EzmUv13sRPTwDS7/zq8H4ZnzDR6qyngQXOZcjktLrdxGj0 175 YDmKWIakpa13YhQDZQJBAOdkclMdbbW+te8apeg/E6hAB+XG+cdgOA1BxEnGUSiQ 176 WZIrjTmfsbb/82uxKddiZSwD/B2H1iwBhnfjHLqEoTcCQQDbYDDnwWfKlxEAoFOo 177 RYe/3nuzMCbP1HqYsmobvbzdhZcvRUYM65Gp0LhCMyuLHc7xZsnEY1pUKu9gpW0o 178 R8+nAkAYZbDgLpQou4j3QvoHOM9byBSNF6Oyb+S5ERwfIzffbQjkro7faoUUZHxH 179 +JAO06MTNwBYJMBiN270KRAYYm+VAkAekJFfyN+YJ2IUD0J4oG9geTQM7DmMHVOT 180 cNA92zq0Noew61ruM+gQm+cAOjbn5BhQI/0aoqkULwM5GPNTeGXjAkAITOarMByj 181 YziZVz4/E9fRvcsdpETJdRF359oVdR5zFIUFKFwYdmX2fNYO0RnOB1ftxsbmdFSj 182 X7CHMFB1ihCa 183 -----END PRIVATE KEY----- 184 EOF 185 ttl = "0" 186 claims = { 187 iss = to_lower("The_Issuer") 188 aud = to_upper("The_Audience") 189 } 190 } 191 } 192 `, 193 "MyToken", 194 `{"sub":"12345"}`, 195 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.oSS8rC1KonyZ-JZTZhkqZb5bN0_2Lrbl4J33nLgWroc5vDvmLW0KnX0RQfXy0OjX4uBBYTThActqqqM6vidaXmBfsQ77uB9narWeAptRnKqEPlY-onTHDmTMCz7vQ9wbLT7Aa6MYlhRqKX5adpPPbwBUuhm2I-yMF80nSmFpSk0", 196 }, 197 { 198 "RS256 / PKCS#1 key_file", 199 ` 200 server "test" { 201 } 202 definitions { 203 jwt_signing_profile "MyToken" { 204 signature_algorithm = "RS256" 205 key_file = "testdata/rsa_priv.pem" 206 ttl = "0" 207 claims = { 208 iss = to_lower("The_Issuer") 209 aud = to_upper("The_Audience") 210 } 211 } 212 } 213 `, 214 "MyToken", 215 `{"sub":"12345"}`, 216 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.oSS8rC1KonyZ-JZTZhkqZb5bN0_2Lrbl4J33nLgWroc5vDvmLW0KnX0RQfXy0OjX4uBBYTThActqqqM6vidaXmBfsQ77uB9narWeAptRnKqEPlY-onTHDmTMCz7vQ9wbLT7Aa6MYlhRqKX5adpPPbwBUuhm2I-yMF80nSmFpSk0", 217 }, 218 { 219 "RS384 / PKCS#1 key", 220 ` 221 server "test" { 222 } 223 definitions { 224 jwt_signing_profile "MyToken" { 225 signature_algorithm = "RS384" 226 key = <<EOF 227 -----BEGIN RSA PRIVATE KEY----- 228 MIICWwIBAAKBgQDGSd+sSTss2uOuVJKpumpFAamlt1CWLMTAZNAabF71Ur0P6u83 229 3RhAIjXDSA/QeVitzvqvCZpNtbOJVegaREqLMJqvFOUkFdLNRP3f9XjYFFvubo09 230 tcjX6oGEREKDqLG2MfZ2Z8LVzuJc6SwZMgVFk/63rdAOci3W9u3zOSGj4QIDAQAB 231 AoGAMzI1rw0FW1J0wLkTWQFJmOGSBLhs9Sk/75DX7kqWxe6D5A07kIfkUALFMNN1 232 SdVa4R10uibXkULdxRLKJ6YEPLGAN3UmdbnBGxZ+fHAKY3PxM5lL9d7ET08A0u/8 233 6vB+GZ8w0eqsp4EFzmXI5LS63cRo9GA5iliGpKWtd2IUA2UCQQDnZHJTHW21vrXv 234 GqXoPxOoQAflxvnHYDgNQcRJxlEokFmSK405n7G2//NrsSnXYmUsA/wdh9YsAYZ3 235 4xy6hKE3AkEA22Aw58FnypcRAKBTqEWHv957szAmz9R6mLJqG7283YWXL0VGDOuR 236 qdC4QjMrix3O8WbJxGNaVCrvYKVtKEfPpwJAGGWw4C6UKLuI90L6BzjPW8gUjRej 237 sm/kuREcHyM3320I5K6O32qFFGR8R/iQDtOjEzcAWCTAYjdu9CkQGGJvlQJAHpCR 238 X8jfmCdiFA9CeKBvYHk0DOw5jB1Tk3DQPds6tDaHsOta7jPoEJvnADo25+QYUCP9 239 GqKpFC8DORjzU3hl4wJACEzmqzAco2M4mVc+PxPX0b3LHaREyXURd+faFXUecxSF 240 BShcGHZl9nzWDtEZzgdX7cbG5nRUo1+whzBQdYoQmg== 241 -----END RSA PRIVATE KEY----- 242 EOF 243 ttl = "0" 244 claims = { 245 iss = to_lower("The_Issuer") 246 aud = to_upper("The_Audience") 247 } 248 } 249 } 250 `, 251 "MyToken", 252 `{"sub":"12345"}`, 253 "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.GaKMl5KxXXTlOUgfZy-Cs81jvVhp-2TjEZIg58qnjIbHH7P0YtIr8p4ikTHQhie7oXs5iwzQPdPqwJSUYHlia3t118mv1ie0IWjqmXhOcWsEODQYHfshIfKaqfIZaF7WFBZXfNdXX4g-8_aUrNPevZ_6vVhHq2844cjaKH-XGl4", 254 }, 255 { 256 "RS384 / PKCS#8 key_file", 257 ` 258 server "test" { 259 } 260 definitions { 261 jwt_signing_profile "MyToken" { 262 signature_algorithm = "RS384" 263 key_file = "testdata/rsa_pkcs8_priv.pem" 264 ttl = "0" 265 claims = { 266 iss = to_lower("The_Issuer") 267 aud = to_upper("The_Audience") 268 } 269 } 270 } 271 `, 272 "MyToken", 273 `{"sub":"12345"}`, 274 "eyJhbGciOiJSUzM4NCIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.GaKMl5KxXXTlOUgfZy-Cs81jvVhp-2TjEZIg58qnjIbHH7P0YtIr8p4ikTHQhie7oXs5iwzQPdPqwJSUYHlia3t118mv1ie0IWjqmXhOcWsEODQYHfshIfKaqfIZaF7WFBZXfNdXX4g-8_aUrNPevZ_6vVhHq2844cjaKH-XGl4", 275 }, 276 { 277 "RS512 / PKCS#1 key", 278 ` 279 server "test" { 280 } 281 definitions { 282 jwt_signing_profile "MyToken" { 283 signature_algorithm = "RS512" 284 key = <<EOF 285 -----BEGIN RSA PRIVATE KEY----- 286 MIICWwIBAAKBgQDGSd+sSTss2uOuVJKpumpFAamlt1CWLMTAZNAabF71Ur0P6u83 287 3RhAIjXDSA/QeVitzvqvCZpNtbOJVegaREqLMJqvFOUkFdLNRP3f9XjYFFvubo09 288 tcjX6oGEREKDqLG2MfZ2Z8LVzuJc6SwZMgVFk/63rdAOci3W9u3zOSGj4QIDAQAB 289 AoGAMzI1rw0FW1J0wLkTWQFJmOGSBLhs9Sk/75DX7kqWxe6D5A07kIfkUALFMNN1 290 SdVa4R10uibXkULdxRLKJ6YEPLGAN3UmdbnBGxZ+fHAKY3PxM5lL9d7ET08A0u/8 291 6vB+GZ8w0eqsp4EFzmXI5LS63cRo9GA5iliGpKWtd2IUA2UCQQDnZHJTHW21vrXv 292 GqXoPxOoQAflxvnHYDgNQcRJxlEokFmSK405n7G2//NrsSnXYmUsA/wdh9YsAYZ3 293 4xy6hKE3AkEA22Aw58FnypcRAKBTqEWHv957szAmz9R6mLJqG7283YWXL0VGDOuR 294 qdC4QjMrix3O8WbJxGNaVCrvYKVtKEfPpwJAGGWw4C6UKLuI90L6BzjPW8gUjRej 295 sm/kuREcHyM3320I5K6O32qFFGR8R/iQDtOjEzcAWCTAYjdu9CkQGGJvlQJAHpCR 296 X8jfmCdiFA9CeKBvYHk0DOw5jB1Tk3DQPds6tDaHsOta7jPoEJvnADo25+QYUCP9 297 GqKpFC8DORjzU3hl4wJACEzmqzAco2M4mVc+PxPX0b3LHaREyXURd+faFXUecxSF 298 BShcGHZl9nzWDtEZzgdX7cbG5nRUo1+whzBQdYoQmg== 299 -----END RSA PRIVATE KEY----- 300 EOF 301 ttl = "0" 302 claims = { 303 iss = to_lower("The_Issuer") 304 aud = to_upper("The_Audience") 305 } 306 } 307 } 308 `, 309 "MyToken", 310 `{"sub":"12345"}`, 311 "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.flU1adXUEaZuqkFwhcgJ8U3OXYOTC6RQCWw9rb7nkTNzt7XrU13EPtlxH5_7lpAvyBn4iyOCiJd19y1paupyeYbHEgUGsVXa4Iu1jQ8I7C41ejLNybdg7XpRzf3zt6tMC3W9Bp0TYRqrykTiQ0W4pg0sGJCV-e30dSDgkfuS_TM", 312 }, 313 { 314 "RS512 / PKCS#8 key_file", 315 ` 316 server "test" { 317 } 318 definitions { 319 jwt_signing_profile "MyToken" { 320 signature_algorithm = "RS512" 321 key_file = "testdata/rsa_pkcs8_priv.pem" 322 ttl = "0" 323 claims = { 324 iss = to_lower("The_Issuer") 325 aud = to_upper("The_Audience") 326 } 327 } 328 } 329 `, 330 "MyToken", 331 `{"sub":"12345"}`, 332 "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.flU1adXUEaZuqkFwhcgJ8U3OXYOTC6RQCWw9rb7nkTNzt7XrU13EPtlxH5_7lpAvyBn4iyOCiJd19y1paupyeYbHEgUGsVXa4Iu1jQ8I7C41ejLNybdg7XpRzf3zt6tMC3W9Bp0TYRqrykTiQ0W4pg0sGJCV-e30dSDgkfuS_TM", 333 }, 334 { 335 "ES256 / key_file", 336 ` 337 server {} 338 definitions { 339 jwt_signing_profile "MyToken" { 340 signature_algorithm = "ES256" 341 key_file = "testdata/ecdsa_256_priv.pem" 342 ttl = "0" 343 claims = { 344 iss = to_lower("The_Issuer") 345 aud = to_upper("The_Audience") 346 } 347 } 348 } 349 `, 350 "MyToken", 351 `{"sub":"12345"}`, 352 "", 353 }, 354 { 355 "ES384 / key w/ 'EC'", 356 ` 357 server {} 358 definitions { 359 jwt_signing_profile "MyToken" { 360 signature_algorithm = "ES384" 361 key =<<-EOF 362 -----BEGIN EC PRIVATE KEY----- 363 ME4CAQAwEAYHKoZIzj0CAQYFK4EEACIENzA1AgEBBDBq1TvCPgzWTeRiI4Aj0CqN 364 MduYWGwc4gZcHCj07O1H36z5MGdd4pj0T2B/QrY7D20= 365 -----END EC PRIVATE KEY----- 366 EOF 367 ttl = "0" 368 claims = { 369 iss = to_lower("The_Issuer") 370 aud = to_upper("The_Audience") 371 } 372 } 373 } 374 `, 375 "MyToken", 376 `{"sub":"12345"}`, 377 "", 378 }, 379 { 380 "jwt / HS256 / key", 381 ` 382 server "test" { 383 } 384 definitions { 385 jwt "MySelfSignedToken" { 386 signature_algorithm = "HS256" 387 key = "$3cRe4" 388 signing_ttl = "0" 389 claims = { 390 iss = to_lower("The_Issuer") 391 aud = to_upper("The_Audience") 392 } 393 } 394 } 395 `, 396 "MySelfSignedToken", 397 `{"sub":"12345"}`, 398 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.Hf-ZtIlsxR2bDOdAEMaDHaOBmfVWTQi9U68yV4YHW9w", 399 }, 400 { 401 "jwt / HS256 / key_file", 402 ` 403 server "test" { 404 } 405 definitions { 406 jwt "MySelfSignedToken" { 407 signature_algorithm = "HS256" 408 key_file = "testdata/secret.txt" 409 signing_ttl = "0" 410 claims = { 411 iss = to_lower("The_Issuer") 412 aud = to_upper("The_Audience") 413 } 414 } 415 } 416 `, 417 "MySelfSignedToken", 418 `{"sub":"12345"}`, 419 "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.Hf-ZtIlsxR2bDOdAEMaDHaOBmfVWTQi9U68yV4YHW9w", 420 }, 421 { 422 "jwt / RS256 / PKCS#1 key", 423 ` 424 server "test" { 425 } 426 definitions { 427 jwt "MySelfSignedToken" { 428 signature_algorithm = "RS256" 429 signing_key = <<EOF 430 -----BEGIN RSA PRIVATE KEY----- 431 MIICWwIBAAKBgQDGSd+sSTss2uOuVJKpumpFAamlt1CWLMTAZNAabF71Ur0P6u83 432 3RhAIjXDSA/QeVitzvqvCZpNtbOJVegaREqLMJqvFOUkFdLNRP3f9XjYFFvubo09 433 tcjX6oGEREKDqLG2MfZ2Z8LVzuJc6SwZMgVFk/63rdAOci3W9u3zOSGj4QIDAQAB 434 AoGAMzI1rw0FW1J0wLkTWQFJmOGSBLhs9Sk/75DX7kqWxe6D5A07kIfkUALFMNN1 435 SdVa4R10uibXkULdxRLKJ6YEPLGAN3UmdbnBGxZ+fHAKY3PxM5lL9d7ET08A0u/8 436 6vB+GZ8w0eqsp4EFzmXI5LS63cRo9GA5iliGpKWtd2IUA2UCQQDnZHJTHW21vrXv 437 GqXoPxOoQAflxvnHYDgNQcRJxlEokFmSK405n7G2//NrsSnXYmUsA/wdh9YsAYZ3 438 4xy6hKE3AkEA22Aw58FnypcRAKBTqEWHv957szAmz9R6mLJqG7283YWXL0VGDOuR 439 qdC4QjMrix3O8WbJxGNaVCrvYKVtKEfPpwJAGGWw4C6UKLuI90L6BzjPW8gUjRej 440 sm/kuREcHyM3320I5K6O32qFFGR8R/iQDtOjEzcAWCTAYjdu9CkQGGJvlQJAHpCR 441 X8jfmCdiFA9CeKBvYHk0DOw5jB1Tk3DQPds6tDaHsOta7jPoEJvnADo25+QYUCP9 442 GqKpFC8DORjzU3hl4wJACEzmqzAco2M4mVc+PxPX0b3LHaREyXURd+faFXUecxSF 443 BShcGHZl9nzWDtEZzgdX7cbG5nRUo1+whzBQdYoQmg== 444 -----END RSA PRIVATE KEY----- 445 EOF 446 signing_ttl = "0" 447 claims = { 448 iss = to_lower("The_Issuer") 449 aud = to_upper("The_Audience") 450 } 451 } 452 } 453 `, 454 "MySelfSignedToken", 455 `{"sub":"12345"}`, 456 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.oSS8rC1KonyZ-JZTZhkqZb5bN0_2Lrbl4J33nLgWroc5vDvmLW0KnX0RQfXy0OjX4uBBYTThActqqqM6vidaXmBfsQ77uB9narWeAptRnKqEPlY-onTHDmTMCz7vQ9wbLT7Aa6MYlhRqKX5adpPPbwBUuhm2I-yMF80nSmFpSk0", 457 }, 458 { 459 "jwt / RS256 / PKCS#8 key_file", 460 ` 461 server "test" { 462 } 463 definitions { 464 jwt "MySelfSignedToken" { 465 signature_algorithm = "RS256" 466 signing_key_file = "testdata/rsa_pkcs8_priv.pem" 467 signing_ttl = "0" 468 claims = { 469 iss = to_lower("The_Issuer") 470 aud = to_upper("The_Audience") 471 } 472 } 473 } 474 `, 475 "MySelfSignedToken", 476 `{"sub":"12345"}`, 477 "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJUSEVfQVVESUVOQ0UiLCJpc3MiOiJ0aGVfaXNzdWVyIiwic3ViIjoiMTIzNDUifQ.oSS8rC1KonyZ-JZTZhkqZb5bN0_2Lrbl4J33nLgWroc5vDvmLW0KnX0RQfXy0OjX4uBBYTThActqqqM6vidaXmBfsQ77uB9narWeAptRnKqEPlY-onTHDmTMCz7vQ9wbLT7Aa6MYlhRqKX5adpPPbwBUuhm2I-yMF80nSmFpSk0", 478 }, 479 { 480 "jwt / ES512 / key", 481 ` 482 server {} 483 definitions { 484 jwt "MySelfSignedToken" { 485 signature_algorithm = "ES512" 486 signing_key =<<-EOF 487 -----BEGIN PRIVATE KEY----- 488 MGACAQAwEAYHKoZIzj0CAQYFK4EEACMESTBHAgEBBEIBm9HVgPAxvAzYy5q6+DNM 489 4CQuGWaiBcwQSRSlLCVkfRclRf8BvTFRT8GATBsdSP/wl5xBFVeo/G7xu0t9wKK/ 490 Cno= 491 -----END PRIVATE KEY----- 492 EOF 493 signing_ttl = "0" 494 claims = { 495 iss = to_lower("The_Issuer") 496 aud = to_upper("The_Audience") 497 } 498 } 499 } 500 `, 501 "MySelfSignedToken", 502 `{"sub":"12345"}`, 503 "", 504 }, 505 } 506 507 for _, tt := range tests { 508 t.Run(tt.name, func(subT *testing.T) { 509 cf, err := configload.LoadBytes([]byte(tt.hcl), "couper.hcl") 510 if err != nil { 511 subT.Fatal(err) 512 } 513 claims, err := stdlib.JSONDecode(cty.StringVal(tt.claims)) 514 if err != nil { 515 subT.Fatal(err) 516 } 517 518 hclContext := cf.Context.Value(request.ContextType).(*eval.Context).HCLContext() 519 520 token, err := hclContext.Functions[lib.FnJWTSign].Call([]cty.Value{cty.StringVal(tt.jspLabel), claims}) 521 if err != nil { 522 subT.Fatal(err) 523 } 524 if tt.want != "" && token.AsString() != tt.want { 525 subT.Errorf("Expected %q, got: %#v", tt.want, token.AsString()) 526 } 527 }) 528 } 529 } 530 531 func TestJwtSignDynamic(t *testing.T) { 532 tests := []struct { 533 name string 534 hcl string 535 jspLabel string 536 headers map[string]interface{} 537 claims string 538 wantTTL int64 539 wantMeth string 540 }{ 541 { 542 "ttl 1h", 543 ` 544 server "test" { 545 } 546 definitions { 547 jwt_signing_profile "MyToken" { 548 signature_algorithm = "HS256" 549 key = "$3cRe4" 550 ttl = "1h" 551 claims = { 552 x-method = request.method 553 x-status = backend_responses.default.status 554 exp = 1234567890 555 } 556 } 557 } 558 `, 559 "MyToken", 560 map[string]interface{}{"alg": "HS256", "typ": "JWT"}, 561 `{"sub": "12345"}`, 562 3600, 563 http.MethodPost, 564 }, 565 { 566 "ttl 60.6s", 567 ` 568 server "test" { 569 } 570 definitions { 571 jwt_signing_profile "MyToken" { 572 signature_algorithm = "HS256" 573 key = "$3cRe4" 574 ttl = "60.6s" 575 claims = { 576 x-method = request.method 577 x-status = backend_responses.default.status 578 } 579 } 580 } 581 `, 582 "MyToken", 583 map[string]interface{}{"alg": "HS256", "typ": "JWT"}, 584 `{"sub": "12345"}`, 585 60, 586 http.MethodPost, 587 }, 588 { 589 "user-defined header", 590 ` 591 server "test" { 592 } 593 definitions { 594 jwt_signing_profile "MyToken" { 595 signature_algorithm = "HS256" 596 key = "$3cRe4" 597 ttl = "1h" 598 headers = { 599 kid = "key-id" 600 foo = [request.method, backend_responses.default.status] 601 typ = "at+jwt" 602 } 603 claims = { 604 x-method = "GET" 605 x-status = 200 606 } 607 } 608 } 609 `, 610 "MyToken", 611 map[string]interface{}{"alg": "HS256", "typ": "at+jwt", "kid": "key-id", "foo": []interface{}{"GET", 200}}, 612 `{"sub": "12345"}`, 613 3600, 614 http.MethodGet, 615 }, 616 } 617 618 for _, tt := range tests { 619 t.Run(tt.name, func(subT *testing.T) { 620 helper := test.New(subT) 621 622 cf, err := configload.LoadBytes([]byte(tt.hcl), "couper.hcl") 623 helper.Must(err) 624 625 claims, err := stdlib.JSONDecode(cty.StringVal(tt.claims)) 626 helper.Must(err) 627 628 req := httptest.NewRequest(tt.wantMeth, "http://1.2.3.4/", nil) 629 *req = *req.WithContext(context.Background()) 630 beresp := &http.Response{ 631 Request: req, 632 StatusCode: http.StatusOK, 633 } 634 635 evalCtx, _, _, _ := cf.Context.Value(request.ContextType).(*eval.Context). 636 WithClientRequest(req). 637 WithBeresp(beresp, cty.NilVal) 638 639 now := time.Now().Unix() 640 token, err := evalCtx.HCLContext().Functions[lib.FnJWTSign].Call([]cty.Value{cty.StringVal(tt.jspLabel), claims}) 641 helper.Must(err) 642 643 tokenParts := strings.Split(token.AsString(), ".") 644 if len(tokenParts) != 3 { 645 subT.Errorf("Needs 3 parts, got: %d", len(tokenParts)) 646 } 647 648 joseHeader, err := base64.RawURLEncoding.DecodeString(tokenParts[0]) 649 helper.Must(err) 650 651 var resultHeaders map[string]interface{} 652 err = json.Unmarshal(joseHeader, &resultHeaders) 653 helper.Must(err) 654 655 if fmt.Sprint(tt.headers) != fmt.Sprint(resultHeaders) { 656 subT.Errorf("Headers:\n\tWant: %#v\n\tGot: %#v", tt.headers, resultHeaders) 657 } 658 659 body, err := base64.RawURLEncoding.DecodeString(tokenParts[1]) 660 helper.Must(err) 661 662 var resultClaims map[string]interface{} 663 err = json.Unmarshal(body, &resultClaims) 664 helper.Must(err) 665 666 if resultClaims["exp"] == nil { 667 subT.Errorf("Expected exp claim, got: %s", body) 668 } 669 exp, _ := resultClaims["exp"].(float64) 670 if !fuzzyEqual(int64(exp)-now, tt.wantTTL, 1) { 671 subT.Error(string(body)) 672 subT.Errorf("Expected %d, got: %d", tt.wantTTL, int64(exp)-now) 673 } 674 if resultClaims["x-method"] == nil { 675 subT.Errorf("Expected x-method claim, got: %s", body) 676 } 677 if resultClaims["x-method"] != tt.wantMeth { 678 subT.Errorf("Expected: %s, got: %s", tt.wantMeth, resultClaims["x-method"]) 679 } 680 681 if resultClaims["x-status"] == nil { 682 subT.Errorf("Expected x-status claim, got: %s", body) 683 } 684 status, _ := resultClaims["x-status"].(float64) 685 if status != 200 { 686 subT.Errorf("Expected: %d, got: %d", http.StatusOK, int64(status)) 687 } 688 }) 689 } 690 } 691 692 func TestJwtSignConfigError(t *testing.T) { 693 tests := []struct { 694 name string 695 hcl string 696 jspLabel string 697 claims string 698 wantErr string 699 }{ 700 { 701 "unsupported signature algorithm", 702 ` 703 server "test" { 704 } 705 definitions { 706 jwt_signing_profile "MyToken" { 707 signature_algorithm = "invalid" 708 key = "$3cRe4" 709 ttl = "0" 710 } 711 } 712 `, 713 "MyToken", 714 `{"sub": "12345"}`, 715 "configuration error: MyToken: algorithm is not supported", 716 }, 717 { 718 "missing signing key or key_file", 719 ` 720 server "test" { 721 } 722 definitions { 723 jwt_signing_profile "MyToken" { 724 signature_algorithm = "RS256" 725 ttl = "0" 726 } 727 } 728 `, 729 "MyToken", 730 `{"sub": "12345"}`, 731 "configuration error: MyToken: jwt_signing_profile key: read error: required: configured attribute or file", 732 }, 733 { 734 "Invalid ttl value", 735 ` 736 server "test" { 737 } 738 definitions { 739 jwt_signing_profile "MyToken" { 740 signature_algorithm = "HS256" 741 key = "$3cRe4" 742 ttl = "invalid" 743 } 744 } 745 `, 746 "MyToken", 747 `{"sub": "12345"}`, 748 "configuration error: MyToken: time: invalid duration \"invalid\"", 749 }, 750 { 751 "invalid PEM key format", 752 ` 753 server "test" { 754 } 755 definitions { 756 jwt_signing_profile "MyToken" { 757 signature_algorithm = "RS256" 758 key = "invalid" 759 ttl = 0 760 } 761 } 762 `, 763 "MyToken", 764 `{"sub": "12345"}`, 765 "configuration error: MyToken: invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key", 766 }, 767 { 768 "jwt / missing signing key or key_file", 769 ` 770 server "test" { 771 } 772 definitions { 773 jwt "MySelfSignedToken" { 774 signature_algorithm = "RS256" 775 key_file = "testdata/rsa_priv.pem" 776 signing_ttl = "0" 777 } 778 } 779 `, 780 "MySelfSignedToken", 781 `{"sub": "12345"}`, 782 "configuration error: MySelfSignedToken: jwt signing key: read error: required: configured attribute or file", 783 }, 784 { 785 "jwt / Invalid signing_ttl value", 786 ` 787 server "test" { 788 } 789 definitions { 790 jwt "MySelfSignedToken" { 791 signature_algorithm = "HS256" 792 signing_key = "$3cRe4" 793 signing_ttl = "invalid" 794 } 795 } 796 `, 797 "MySelfSignedToken", 798 `{"sub": "12345"}`, 799 "configuration error: MySelfSignedToken: time: invalid duration \"invalid\"", 800 }, 801 { 802 "jwt / invalid PEM key format", 803 ` 804 server "test" { 805 } 806 definitions { 807 jwt "MySelfSignedToken" { 808 signature_algorithm = "RS256" 809 signing_key = "invalid" 810 signing_ttl = "0" 811 } 812 } 813 `, 814 "MySelfSignedToken", 815 `{"sub": "12345"}`, 816 "configuration error: MySelfSignedToken: invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key", 817 }, 818 { 819 "user-defined alg header", 820 ` 821 server "test" { 822 } 823 definitions { 824 jwt_signing_profile "MyToken" { 825 signature_algorithm = "HS256" 826 key = "$3cRe4" 827 ttl = "1h" 828 headers = { 829 alg = "none" 830 } 831 } 832 } 833 `, 834 "MyToken", 835 `{"sub": "12345"}`, 836 `configuration error: MyToken: "alg" cannot be set via "headers"`, 837 }, 838 } 839 840 for _, tt := range tests { 841 t.Run(tt.name, func(subT *testing.T) { 842 _, err := configload.LoadBytes([]byte(tt.hcl), "couper.hcl") 843 if err == nil { 844 subT.Fatalf("expected an error '%s', got nothing", tt.wantErr) 845 } 846 logErr, _ := err.(errors.GoError) 847 if logErr == nil { 848 subT.Error("logErr should not be nil") 849 } else if logErr.LogError() != tt.wantErr { 850 subT.Errorf("\nwant:\t%s\ngot:\t%v", tt.wantErr, logErr.LogError()) 851 } 852 }) 853 } 854 } 855 856 func TestJwtSignError(t *testing.T) { 857 tests := []struct { 858 name string 859 hcl string 860 jspLabel string 861 claims string 862 wantErr string 863 }{ 864 { 865 "missing signing profile definitions", 866 ` 867 server {} 868 definitions { 869 jwt "MyToken" { 870 signature_algorithm = "HS256" 871 key = "$3cRe4" 872 } 873 } 874 `, 875 "MyToken", 876 `{"sub": "12345"}`, 877 `missing jwt_signing_profile or jwt (with signing_ttl) block with referenced label "MyToken"`, 878 }, 879 { 880 "No profile for label", 881 ` 882 server {} 883 definitions { 884 jwt_signing_profile "MyToken" { 885 signature_algorithm = "HS256" 886 key = "$3cRe4" 887 ttl = "0" 888 } 889 } 890 `, 891 "NoProfileForThisLabel", 892 `{"sub":"12345"}`, 893 `missing jwt_signing_profile or jwt (with signing_ttl) block with referenced label "NoProfileForThisLabel"`, 894 }, 895 { 896 "argument claims no object", 897 ` 898 server {} 899 definitions { 900 jwt_signing_profile "MyToken" { 901 signature_algorithm = "HS256" 902 key = "$3cRe4" 903 ttl = "0" 904 } 905 } 906 `, 907 "MyToken", 908 `"no object"`, 909 "json: cannot unmarshal string into Go value of type map[string]interface {}", 910 }, 911 { 912 "jwt / No profile for label", 913 ` 914 server {} 915 definitions { 916 jwt "MySelfSignedToken" { 917 signature_algorithm = "HS256" 918 key = "$3cRe4" 919 signing_ttl = "0" 920 } 921 } 922 `, 923 "NoProfileForThisLabel", 924 `{"sub": "12345"}`, 925 `missing jwt_signing_profile or jwt (with signing_ttl) block with referenced label "NoProfileForThisLabel"`, 926 }, 927 { 928 "jwt / bad curve for algorithm", 929 ` 930 server {} 931 definitions { 932 jwt_signing_profile "MyToken" { 933 signature_algorithm = "ES512" 934 key =<<-EOF 935 -----BEGIN EC PRIVATE KEY----- 936 MHcCAQEEIPhFjEWy9WowuN52bmIdbSD4gMKdBjFplPhU/jUf8GFyoAoGCCqGSM49 937 AwEHoUQDQgAEgPxsi3Y2J1FWrjXjacAWmbB+GIuzKPLrW5KikaxLtwuoDE61oaWM 938 M4H99mGPN7k4Bmamle8ne9Pr7rQhXuk8Iw== 939 -----END EC PRIVATE KEY----- 940 EOF 941 ttl = 0 942 } 943 } 944 `, 945 "MyToken", 946 `{"sub":"12345"}`, 947 "key is invalid", 948 }, 949 } 950 951 for _, tt := range tests { 952 t.Run(tt.name, func(subT *testing.T) { 953 helper := test.New(subT) 954 cf, err := configload.LoadBytes([]byte(tt.hcl), "couper.hcl") 955 helper.Must(err) 956 claims, err := stdlib.JSONDecode(cty.StringVal(tt.claims)) 957 helper.Must(err) 958 959 hclContext := cf.Context.Value(request.ContextType).(*eval.Context).HCLContext() 960 961 _, err = hclContext.Functions[lib.FnJWTSign].Call([]cty.Value{cty.StringVal(tt.jspLabel), claims}) 962 if err == nil { 963 subT.Error("expected an error, got nothing") 964 return 965 } 966 if err.Error() != tt.wantErr { 967 subT.Errorf("\nWant:\t%q\nGot:\t%q", tt.wantErr, err.Error()) 968 } 969 }) 970 } 971 }