Add 'm.login.token' authentication
parent
3588dcd6d0
commit
d49911c5e0
|
@ -182,6 +182,19 @@ version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"time 0.1.44",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color_quant"
|
name = "color_quant"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -197,6 +210,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"image",
|
"image",
|
||||||
"js_int",
|
"js_int",
|
||||||
|
"jsonwebtoken",
|
||||||
"log",
|
"log",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -243,7 +257,7 @@ version = "0.15.0-dev"
|
||||||
source = "git+https://github.com/SergioBenitez/cookie-rs.git?rev=1c3ca83#1c3ca838543b60a4448d279dc4b903cc7a2bc22a"
|
source = "git+https://github.com/SergioBenitez/cookie-rs.git?rev=1c3ca83#1c3ca838543b60a4448d279dc4b903cc7a2bc22a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"time",
|
"time 0.2.23",
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -578,7 +592,7 @@ checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -850,6 +864,20 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jsonwebtoken"
|
||||||
|
version = "7.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.12.3",
|
||||||
|
"pem",
|
||||||
|
"ring",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"simple_asn1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kernel32-sys"
|
name = "kernel32-sys"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -1044,6 +1072,17 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"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]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.44"
|
version = "0.1.44"
|
||||||
|
@ -1204,6 +1243,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pem"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c220d01f863d13d96ca82359d1e81e64a7c6bf0637bcde7b2349630addf0c6"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.0",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1538,7 +1588,7 @@ dependencies = [
|
||||||
"rocket_http",
|
"rocket_http",
|
||||||
"serde",
|
"serde",
|
||||||
"state",
|
"state",
|
||||||
"time",
|
"time 0.2.23",
|
||||||
"tokio",
|
"tokio",
|
||||||
"ubyte",
|
"ubyte",
|
||||||
"version_check",
|
"version_check",
|
||||||
|
@ -1575,7 +1625,7 @@ dependencies = [
|
||||||
"ref-cast",
|
"ref-cast",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"state",
|
"state",
|
||||||
"time",
|
"time 0.2.23",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"uncased",
|
"uncased",
|
||||||
|
@ -1969,6 +2019,17 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -2168,6 +2229,17 @@ dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.2.23"
|
version = "0.2.23"
|
||||||
|
@ -2498,6 +2570,12 @@ version = "0.9.0+wasi-snapshot-preview1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.69"
|
version = "0.2.69"
|
||||||
|
|
|
@ -63,6 +63,8 @@ ring = "0.16.19"
|
||||||
trust-dns-resolver = "0.19.6"
|
trust-dns-resolver = "0.19.6"
|
||||||
# Used to find matching events for appservices
|
# Used to find matching events for appservices
|
||||||
regex = "1.4.2"
|
regex = "1.4.2"
|
||||||
|
# jwt jsonwebtokens
|
||||||
|
jsonwebtoken = "7.2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["conduit_bin"]
|
default = ["conduit_bin"]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{utils, Error, Result};
|
use crate::{utils, Error, Result};
|
||||||
use http::header::{HeaderValue, CONTENT_TYPE};
|
use http::header::{HeaderValue, CONTENT_TYPE};
|
||||||
use log::{info, warn};
|
use log::warn;
|
||||||
use ruma::api::OutgoingRequest;
|
use ruma::api::OutgoingRequest;
|
||||||
use std::{
|
use std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
|
|
|
@ -8,6 +8,13 @@ use ruma::{
|
||||||
},
|
},
|
||||||
UserId,
|
UserId,
|
||||||
};
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Claims {
|
||||||
|
sub: String,
|
||||||
|
exp: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "conduit_bin")]
|
#[cfg(feature = "conduit_bin")]
|
||||||
use rocket::{get, post};
|
use rocket::{get, post};
|
||||||
|
@ -40,40 +47,62 @@ pub async fn login_route(
|
||||||
body: Ruma<login::Request<'_>>,
|
body: Ruma<login::Request<'_>>,
|
||||||
) -> ConduitResult<login::Response> {
|
) -> ConduitResult<login::Response> {
|
||||||
// Validate login method
|
// Validate login method
|
||||||
let user_id =
|
// TODO: Other login methods
|
||||||
// TODO: Other login methods
|
let user_id = match &body.login_info {
|
||||||
if let (login::IncomingUserInfo::MatrixId(username), login::IncomingLoginInfo::Password { password }) =
|
login::IncomingLoginInfo::Password { password } => {
|
||||||
(&body.user, &body.login_info)
|
let username = if let login::IncomingUserInfo::MatrixId(matrix_id) = &body.user {
|
||||||
{
|
matrix_id
|
||||||
let user_id = UserId::parse_with_server_name(username.to_string(), db.globals.server_name())
|
} else {
|
||||||
.map_err(|_| Error::BadRequest(
|
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
||||||
ErrorKind::InvalidUsername,
|
};
|
||||||
"Username is invalid."
|
let user_id =
|
||||||
))?;
|
UserId::parse_with_server_name(username.to_owned(), db.globals.server_name())
|
||||||
let hash = db.users.password_hash(&user_id)?
|
.map_err(|_| {
|
||||||
.ok_or(Error::BadRequest(
|
Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid.")
|
||||||
ErrorKind::Forbidden,
|
})?;
|
||||||
"Wrong username or password."
|
let hash = db.users.password_hash(&user_id)?.ok_or(Error::BadRequest(
|
||||||
))?;
|
ErrorKind::Forbidden,
|
||||||
|
"Wrong username or password.",
|
||||||
|
))?;
|
||||||
|
|
||||||
if hash.is_empty() {
|
if hash.is_empty() {
|
||||||
return Err(Error::BadRequest(
|
return Err(Error::BadRequest(
|
||||||
ErrorKind::UserDeactivated,
|
ErrorKind::UserDeactivated,
|
||||||
"The user has been deactivated"
|
"The user has been deactivated",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash_matches =
|
let hash_matches = argon2::verify_encoded(&hash, password.as_bytes()).unwrap_or(false);
|
||||||
argon2::verify_encoded(&hash, password.as_bytes()).unwrap_or(false);
|
|
||||||
|
|
||||||
if !hash_matches {
|
if !hash_matches {
|
||||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Wrong username or password."));
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Forbidden,
|
||||||
|
"Wrong username or password.",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
user_id
|
user_id
|
||||||
} else {
|
}
|
||||||
return Err(Error::BadRequest(ErrorKind::Forbidden, "Bad login type."));
|
login::IncomingLoginInfo::Token { token } => {
|
||||||
};
|
if let Some(jwt_decoding_key) = db.globals.jwt_decoding_key() {
|
||||||
|
let token = jsonwebtoken::decode::<Claims>(
|
||||||
|
&token,
|
||||||
|
&jwt_decoding_key,
|
||||||
|
&jsonwebtoken::Validation::default(),
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::BadRequest(ErrorKind::InvalidUsername, "Token is invalid."))?;
|
||||||
|
let username = token.claims.sub;
|
||||||
|
UserId::parse_with_server_name(username, db.globals.server_name()).map_err(
|
||||||
|
|_| Error::BadRequest(ErrorKind::InvalidUsername, "Username is invalid."),
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::Unknown,
|
||||||
|
"Token login is not supported (server has no jwt decoding key).",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Generate new device id if the user didn't specify one
|
// Generate new device id if the user didn't specify one
|
||||||
let device_id = body
|
let device_id = body
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub struct Config {
|
||||||
allow_encryption: bool,
|
allow_encryption: bool,
|
||||||
#[serde(default = "false_fn")]
|
#[serde(default = "false_fn")]
|
||||||
allow_federation: bool,
|
allow_federation: bool,
|
||||||
|
jwt_secret: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn false_fn() -> bool {
|
fn false_fn() -> bool {
|
||||||
|
|
|
@ -11,12 +11,13 @@ pub const COUNTER: &str = "c";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Globals {
|
pub struct Globals {
|
||||||
|
pub actual_destination_cache: Arc<RwLock<HashMap<Box<ServerName>, (String, Option<String>)>>>, // actual_destination, host
|
||||||
pub(super) globals: sled::Tree,
|
pub(super) globals: sled::Tree,
|
||||||
config: Config,
|
config: Config,
|
||||||
keypair: Arc<ruma::signatures::Ed25519KeyPair>,
|
keypair: Arc<ruma::signatures::Ed25519KeyPair>,
|
||||||
reqwest_client: reqwest::Client,
|
reqwest_client: reqwest::Client,
|
||||||
pub actual_destination_cache: Arc<RwLock<HashMap<Box<ServerName>, (String, Option<String>)>>>, // actual_destination, host
|
|
||||||
dns_resolver: TokioAsyncResolver,
|
dns_resolver: TokioAsyncResolver,
|
||||||
|
jwt_decoding_key: Option<jsonwebtoken::DecodingKey<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Globals {
|
impl Globals {
|
||||||
|
@ -62,6 +63,11 @@ impl Globals {
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let jwt_decoding_key = config
|
||||||
|
.jwt_secret
|
||||||
|
.as_ref()
|
||||||
|
.map(|secret| jsonwebtoken::DecodingKey::from_secret(secret.as_bytes()).into_static());
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
globals,
|
globals,
|
||||||
config,
|
config,
|
||||||
|
@ -73,6 +79,7 @@ impl Globals {
|
||||||
Error::bad_config("Failed to set up trust dns resolver with system config.")
|
Error::bad_config("Failed to set up trust dns resolver with system config.")
|
||||||
})?,
|
})?,
|
||||||
actual_destination_cache: Arc::new(RwLock::new(HashMap::new())),
|
actual_destination_cache: Arc::new(RwLock::new(HashMap::new())),
|
||||||
|
jwt_decoding_key,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,4 +133,8 @@ impl Globals {
|
||||||
pub fn dns_resolver(&self) -> &TokioAsyncResolver {
|
pub fn dns_resolver(&self) -> &TokioAsyncResolver {
|
||||||
&self.dns_resolver
|
&self.dns_resolver
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn jwt_decoding_key(&self) -> Option<&jsonwebtoken::DecodingKey<'_>> {
|
||||||
|
self.jwt_decoding_key.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
||||||
|
|
||||||
use crate::{appservice_server, server_server, utils, Error, PduEvent, Result};
|
use crate::{appservice_server, server_server, utils, Error, PduEvent, Result};
|
||||||
use federation::transactions::send_transaction_message;
|
use federation::transactions::send_transaction_message;
|
||||||
use log::{error, info};
|
use log::info;
|
||||||
use rocket::futures::stream::{FuturesUnordered, StreamExt};
|
use rocket::futures::stream::{FuturesUnordered, StreamExt};
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::{appservice, federation, OutgoingRequest},
|
api::{appservice, federation, OutgoingRequest},
|
||||||
|
|
Loading…
Reference in New Issue