diff --git a/Cargo.lock b/Cargo.lock index 78f522d33..c4953850c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,6 +396,19 @@ dependencies = [ "syn", ] +[[package]] +name = "actix-web-httpauth" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "536a75d767c5c2b3e64d3f569621f38ed7609359a0c82d149c88290a6ba41b22" +dependencies = [ + "actix-service", + "actix-web", + "base64 0.12.3", + "bytes 0.5.6", + "futures-util", +] + [[package]] name = "actix_derive" version = "0.5.0" @@ -418,9 +431,9 @@ dependencies = [ [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" @@ -509,6 +522,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -564,9 +583,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byteorder" @@ -612,9 +631,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" @@ -768,7 +787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", ] [[package]] @@ -779,18 +798,17 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", ] [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ "cfg-if 1.0.0", - "const_fn", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", "lazy_static", "memoffset", "scopeguard", @@ -809,9 +827,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -997,9 +1015,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding", @@ -1023,9 +1041,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" dependencies = [ "futures-channel", "futures-core", @@ -1038,9 +1056,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846" +checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939" dependencies = [ "futures-core", "futures-sink", @@ -1048,15 +1066,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65" +checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94" [[package]] name = "futures-executor" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9" +checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1" dependencies = [ "futures-core", "futures-task", @@ -1065,15 +1083,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500" +checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59" [[package]] name = "futures-macro" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd" +checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1083,24 +1101,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6" +checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3" [[package]] name = "futures-task" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86" -dependencies = [ - "once_cell", -] +checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80" [[package]] name = "futures-util" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b" +checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ "futures-channel", "futures-core", @@ -1334,13 +1349,28 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtokens" +version = "1.0.0-alpha.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "454b5b99a0c14d6fc1cb7b5ca031adfe2935c922b0232be9a8143c8b542daa94" +dependencies = [ + "base64 0.11.0", + "pem", + "regex", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1419,10 +1449,12 @@ dependencies = [ "actix-cors", "actix-rt", "actix-web", + "actix-web-httpauth", "cargo-husky", "criterion", "docopt", "env_logger", + "jsonwebtokens", "log", "native-tls", "num_cpus", @@ -1485,9 +1517,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -1564,6 +1596,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -1601,9 +1644,9 @@ checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" -version = "1.5.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +checksum = "10acf907b94fc1b1a152d08ef97e7759650268cf986bf127f387e602b02c7e5a" [[package]] name = "oorandom" @@ -1699,6 +1742,17 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "pem" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1581760c757a756a41f0ee3ff01256227bdf64cb752839779b95ffb01c59793" +dependencies = [ + "base64 0.11.0", + "lazy_static", + "regex", +] + [[package]] name = "percent-encoding" version = "2.1.0" @@ -2049,7 +2103,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel 0.5.0", "crossbeam-deque", - "crossbeam-utils 0.8.1", + "crossbeam-utils 0.8.3", "lazy_static", "num_cpus", ] @@ -2125,6 +2179,21 @@ dependencies = [ "quick-error", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rustc-demangle" version = "0.1.18" @@ -2182,9 +2251,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +checksum = "2dfd318104249865096c8da1dfabf09ddbb6d0330ea176812a62ec75e40c4166" dependencies = [ "bitflags", "core-foundation", @@ -2195,9 +2264,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +checksum = "dee48cdde5ed250b0d3252818f646e174ab414036edb884dde62d80a3ac6082d" dependencies = [ "core-foundation-sys", "libc", @@ -2354,6 +2423,17 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_asn1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" +dependencies = [ + "chrono", + "num-bigint", + "num-traits", +] + [[package]] name = "siphasher" version = "0.3.3" @@ -2383,6 +2463,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "standback" version = "0.2.15" @@ -2520,18 +2606,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" dependencies = [ "proc-macro2", "quote", @@ -2723,9 +2809,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77d3842f76ca899ff2dbcf231c5c65813dea431301d6eb686279c15c4464f12" +checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" dependencies = [ "cfg-if 1.0.0", "log", @@ -2879,11 +2965,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5909f2b0817350449ed73e8bcd81c8c3c8d9a7a5d8acba4b27db277f1868976e" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" dependencies = [ "form_urlencoded", "idna", @@ -2934,9 +3026,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2944,9 +3036,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" dependencies = [ "bumpalo", "lazy_static", @@ -2959,9 +3051,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2969,9 +3061,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2", "quote", @@ -2982,15 +3074,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b9ed63b2a..75aae23c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ actix = "0.9" actix-cors = "0.5.4" actix-rt = "1.1" actix-web = "3.3.2" +actix-web-httpauth = "0.5.0" docopt = "1" env_logger = "0.8" log = "0.4" @@ -32,6 +33,7 @@ serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.8" tilejson = "0.2" +jsonwebtokens = "1.0.0-alpha.13" [dev-dependencies] criterion = "0.3" diff --git a/README.md b/README.md index aff2f5861..75bfc4d0b 100755 --- a/README.md +++ b/README.md @@ -303,6 +303,10 @@ Options: --watch Scan for new sources on sources list requests. --workers= Number of web server workers. --danger-accept-invalid-certs Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort. + --jwt Enable secure endpoints with JWT. + --jwt-secret= A secret to verify signature (need JWT enabled). + --jwt-algorithm= Algorithm can be: empty (autodetect from jwt token dangerous), HS256, HS384, HS512, ES256, ES384, RS256, RS384, RS512, PS256, PS384 or PS512. + --jwt-check-exp-time Enable check expiration time in claims, by default disabled. ``` ## Environment Variables diff --git a/src/bin/main.rs b/src/bin/main.rs index 65389a84a..3e392bf0f 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -33,6 +33,10 @@ Options: --watch Scan for new sources on sources list requests. --workers= Number of web server workers. --danger-accept-invalid-certs Trust invalid certificates. This introduces significant vulnerabilities, and should only be used as a last resort. + --jwt Enable secure endpoints with JWT. + --jwt-secret= A secret to verify signature (need JWT enabled). + --jwt-algorithm= Algorithm can be: empty (autodetect from jwt token dangerous), HS256, HS384, HS512, ES256, ES384, RS256, RS384, RS512, PS256, PS384 or PS512. + --jwt-check-exp-time Enable check expiration time in claims, by default disabled. "; #[derive(Debug, Deserialize)] @@ -47,6 +51,10 @@ pub struct Args { pub flag_version: bool, pub flag_workers: Option, pub flag_danger_accept_invalid_certs: bool, + pub flag_jwt: bool, + pub flag_jwt_secret: Option, + pub flag_jwt_algorithm: Option, + pub flag_jwt_check_exp_time: bool, } pub fn generate_config(args: Args, pool: &Pool) -> io::Result { @@ -71,6 +79,10 @@ pub fn generate_config(args: Args, pool: &Pool) -> io::Result { table_sources: Some(table_sources), function_sources: Some(function_sources), danger_accept_invalid_certs: Some(args.flag_danger_accept_invalid_certs), + jwt: Some(args.flag_jwt), + jwt_secret: args.flag_jwt_secret, + jwt_algorithm: args.flag_jwt_algorithm, + jwt_check_exp_time: Some(args.flag_jwt_check_exp_time), }; let config = config.finalize(); diff --git a/src/config.rs b/src/config.rs index 24bc88fea..711427b0e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,10 @@ pub struct Config { pub table_sources: Option, pub function_sources: Option, pub danger_accept_invalid_certs: bool, + pub jwt: bool, + pub jwt_secret: String, + pub jwt_algorithm: String, + pub jwt_check_exp_time: bool, } #[derive(Deserialize)] @@ -30,6 +34,10 @@ pub struct ConfigBuilder { pub table_sources: Option, pub function_sources: Option, pub danger_accept_invalid_certs: Option, + pub jwt: Option, + pub jwt_secret: Option, + pub jwt_algorithm: Option, + pub jwt_check_exp_time: Option, } impl ConfigBuilder { @@ -46,6 +54,10 @@ impl ConfigBuilder { table_sources: self.table_sources, function_sources: self.function_sources, danger_accept_invalid_certs: self.danger_accept_invalid_certs.unwrap_or(false), + jwt: self.jwt.unwrap_or(false), + jwt_secret: self.jwt_secret.unwrap_or_else(|| "".to_owned()), + jwt_algorithm: self.jwt_algorithm.unwrap_or_else(|| "".to_owned()), + jwt_check_exp_time: self.jwt_check_exp_time.unwrap_or(false), } } } diff --git a/src/server.rs b/src/server.rs index 03ed70ab6..945a5a4cd 100755 --- a/src/server.rs +++ b/src/server.rs @@ -6,8 +6,9 @@ use std::rc::Rc; use actix::{Actor, Addr, SyncArbiter, SystemRunner}; use actix_cors::Cors; use actix_web::{ - error, http, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, + dev, error, http, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Result, }; +use actix_web_httpauth::{extractors::bearer::BearerAuth, middleware::HttpAuthentication}; use crate::config::Config; use crate::coordinator_actor::CoordinatorActor; @@ -19,6 +20,18 @@ use crate::source::{Source, XYZ}; use crate::table_source::TableSources; use crate::worker_actor::WorkerActor; +// For JWT +use jsonwebtokens as jwt; +use jwt::{raw, Algorithm, AlgorithmID, Verifier}; +use std::str::FromStr; +use std::time::SystemTime; + +pub struct JWTConfig { + pub jwt_secret: String, + pub jwt_algorithm: String, + pub jwt_check_exp_time: bool, +} + pub struct AppState { pub db: Addr, pub coordinator: Addr, @@ -323,6 +336,75 @@ fn create_state( } } +async fn bearer_auth_validator( + req: dev::ServiceRequest, + credentials: BearerAuth, +) -> Result { + let jwt_config = req.app_data::().unwrap(); + + let try_catch_block = || -> Result<(Verifier, Algorithm, bool), jwt::error::Error> { + let header_json; + let raw::TokenSlices { header, claims, .. } = raw::split_token(credentials.token())?; + let claims_json = raw::decode_json_token_slice(claims)?; + let alg_name = if jwt_config.jwt_algorithm.is_empty() { + header_json = raw::decode_json_token_slice(header)?; + header_json["alg"].as_str().unwrap_or("") + } else { + jwt_config.jwt_algorithm.as_str() + }; + let alg_id = AlgorithmID::from_str(alg_name)?; + + Ok(( + Verifier::create().build()?, + Algorithm::new_hmac(alg_id, jwt_config.jwt_secret.as_str())?, + claims_json["exp"].is_null(), + )) + }; + + match try_catch_block() { + Ok((verifier, alg, exp_is_null)) => { + let result = if jwt_config.jwt_check_exp_time { + if exp_is_null { + return Err(error::ErrorForbidden("Claim exp does not exist.")); + } + + let now_unixtimestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + match verifier.verify_for_time(&credentials.token(), &alg, now_unixtimestamp) { + Ok(_) => Ok(true), + Err(e) => Err(e), + } + } else { + match verifier.verify(&credentials.token(), &alg) { + Ok(_) => Ok(true), + Err(e) => Err(e), + } + }; + match result { + Ok(_) => Ok(req), + Err(e) => { + info!( + "Error verify JWT: token \"{}\" error \"{}\".", + credentials.token(), + e.to_string() + ); + Err(error::ErrorForbidden(e.to_string())) + } + } + } + Err(e) => { + info!( + "Error generate algorith and verifier JWT: token \"{}\" error \"{}\".", + credentials.token(), + e.to_string() + ); + Err(error::ErrorForbidden(e.to_string())) + } + } +} + pub fn new(pool: Pool, config: Config) -> SystemRunner { let sys = actix_rt::System::new("server"); @@ -336,9 +418,17 @@ pub fn new(pool: Pool, config: Config) -> SystemRunner { HttpServer::new(move || { let state = create_state(db.clone(), coordinator.clone(), config.clone()); + let jwt_config = JWTConfig { + jwt_secret: config.jwt_secret.clone(), + jwt_algorithm: config.jwt_algorithm.clone(), + jwt_check_exp_time: config.jwt_check_exp_time, + }; + let cors_middleware = Cors::default().allow_any_origin(); + let auth = HttpAuthentication::bearer(bearer_auth_validator); App::new() + .app_data(jwt_config) .data(state) .wrap(cors_middleware) .wrap(middleware::NormalizePath::new( @@ -346,6 +436,7 @@ pub fn new(pool: Pool, config: Config) -> SystemRunner { )) .wrap(middleware::Logger::default()) .wrap(middleware::Compress::default()) + .wrap(middleware::Condition::new(config.jwt, auth)) .configure(router) }) .bind(listen_addresses.clone()) diff --git a/tests/config.yaml b/tests/config.yaml index dbfa788f2..4b706e7b5 100644 --- a/tests/config.yaml +++ b/tests/config.yaml @@ -20,6 +20,18 @@ danger_accept_invalid_certs: false # Number of web server workers worker_processes: 8 +# Enable secure endpoints with JWT. +jwt: false + +# A secret to verify signature (need JWT enabled). +jwt_secret: "" + +# Algorithm can be: empty (autodetect from jwt token dangerous), HS256, HS384, HS512, ES256, ES384, RS256, RS384, RS512, PS256, PS384 or PS512. +jwt_algorithm: "" + +# Enable check expiration time in claims, by default disabled. +jwt_check_exp_time: false + # associative arrays of table sources table_sources: public.table_source: