Access token permissions
This commit is contained in:
@@ -7,6 +7,7 @@ resolver = "2"
|
||||
[dependencies]
|
||||
store = { path = "../store" }
|
||||
common = { path = "../common" }
|
||||
directory = { path = "../directory" }
|
||||
jmap = { path = "../jmap" }
|
||||
imap = { path = "../imap" }
|
||||
utils = { path = "../utils" }
|
||||
|
||||
@@ -9,7 +9,7 @@ use mail_send::Credentials;
|
||||
use trc::AddContext;
|
||||
|
||||
use crate::{
|
||||
protocol::{request::Error, response::Response, Command, Mechanism},
|
||||
protocol::{request::Error, Command, Mechanism},
|
||||
Session, State,
|
||||
};
|
||||
|
||||
@@ -117,54 +117,11 @@ impl<T: SessionStream> Session<T> {
|
||||
self.write_ok("NOOP").await.map(|_| SessionResult::Continue)
|
||||
}
|
||||
Command::Rset => self.handle_rset().await.map(|_| SessionResult::Continue),
|
||||
Command::Capa => {
|
||||
let mechanisms =
|
||||
if self.stream.is_tls() || self.jmap.core.imap.allow_plain_auth {
|
||||
vec![Mechanism::Plain, Mechanism::OAuthBearer]
|
||||
} else {
|
||||
vec![Mechanism::OAuthBearer]
|
||||
};
|
||||
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::Capabilities),
|
||||
SpanId = self.session_id,
|
||||
Tls = self.stream.is_tls(),
|
||||
Strict = !self.jmap.core.imap.allow_plain_auth,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_bytes(
|
||||
Response::Capability::<u32> {
|
||||
mechanisms,
|
||||
stls: !self.stream.is_tls(),
|
||||
}
|
||||
.serialize(),
|
||||
)
|
||||
.await
|
||||
.map(|_| SessionResult::Continue)
|
||||
}
|
||||
Command::Capa => self.handle_capa().await.map(|_| SessionResult::Continue),
|
||||
Command::Stls => {
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::StartTls),
|
||||
SpanId = self.session_id,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_ok("Begin TLS negotiation now")
|
||||
.await
|
||||
.map(|_| SessionResult::UpgradeTls)
|
||||
}
|
||||
Command::Utf8 => {
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::Utf8),
|
||||
SpanId = self.session_id,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_ok("UTF8 enabled")
|
||||
.await
|
||||
.map(|_| SessionResult::Continue)
|
||||
self.handle_stls().await.map(|_| SessionResult::UpgradeTls)
|
||||
}
|
||||
Command::Utf8 => self.handle_utf8().await.map(|_| SessionResult::Continue),
|
||||
Command::Auth { mechanism, params } => self
|
||||
.handle_sasl(mechanism, params)
|
||||
.await
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::{net::IpAddr, sync::Arc};
|
||||
|
||||
use common::listener::{limiter::InFlight, ServerInstance, SessionStream};
|
||||
use imap::core::{ImapInstance, Inner};
|
||||
use jmap::JMAP;
|
||||
use jmap::{auth::AccessToken, JMAP};
|
||||
use mailbox::Mailbox;
|
||||
use protocol::request::Parser;
|
||||
|
||||
@@ -51,6 +51,7 @@ pub enum State {
|
||||
Authenticated {
|
||||
mailbox: Mailbox,
|
||||
in_flight: Option<InFlight>,
|
||||
access_token: Arc<AccessToken>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -68,4 +69,11 @@ impl State {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn access_token(&self) -> &Arc<AccessToken> {
|
||||
match self {
|
||||
State::Authenticated { access_token, .. } => access_token,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
use common::listener::{limiter::ConcurrencyLimiter, SessionStream};
|
||||
use directory::Permission;
|
||||
use imap::op::authenticate::{decode_challenge_oauth, decode_challenge_plain};
|
||||
use jmap::auth::rate_limit::ConcurrencyLimiters;
|
||||
use mail_parser::decoders::base64::base64_decode;
|
||||
@@ -112,6 +113,9 @@ impl<T: SessionStream> Session<T> {
|
||||
}
|
||||
};
|
||||
|
||||
// Validate access
|
||||
access_token.assert_has_permission(Permission::Pop3Authenticate)?;
|
||||
|
||||
// Cache access token
|
||||
let access_token = Arc::new(access_token);
|
||||
self.jmap.cache_access_token(access_token.clone());
|
||||
@@ -120,7 +124,11 @@ impl<T: SessionStream> Session<T> {
|
||||
let mailbox = self.fetch_mailbox(access_token.primary_id()).await?;
|
||||
|
||||
// Create session
|
||||
self.state = State::Authenticated { in_flight, mailbox };
|
||||
self.state = State::Authenticated {
|
||||
in_flight,
|
||||
mailbox,
|
||||
access_token,
|
||||
};
|
||||
self.write_ok("Authentication successful").await
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use common::listener::SessionStream;
|
||||
use directory::Permission;
|
||||
use jmap_proto::types::{state::StateChange, type_state::DataType};
|
||||
use store::roaring::RoaringBitmap;
|
||||
use trc::AddContext;
|
||||
@@ -15,6 +16,11 @@ use crate::{protocol::response::Response, Session, State};
|
||||
|
||||
impl<T: SessionStream> Session<T> {
|
||||
pub async fn handle_dele(&mut self, msgs: Vec<u32>) -> trc::Result<()> {
|
||||
// Validate access
|
||||
self.state
|
||||
.access_token()
|
||||
.assert_has_permission(Permission::Pop3Dele)?;
|
||||
|
||||
let op_start = Instant::now();
|
||||
let mailbox = self.state.mailbox_mut();
|
||||
let mut response = Vec::new();
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use common::listener::SessionStream;
|
||||
use directory::Permission;
|
||||
use jmap::email::metadata::MessageMetadata;
|
||||
use jmap_proto::types::{collection::Collection, property::Property};
|
||||
use store::write::Bincode;
|
||||
@@ -16,6 +17,11 @@ use crate::{protocol::response::Response, Session};
|
||||
|
||||
impl<T: SessionStream> Session<T> {
|
||||
pub async fn handle_fetch(&mut self, msg: u32, lines: Option<u32>) -> trc::Result<()> {
|
||||
// Validate access
|
||||
self.state
|
||||
.access_token()
|
||||
.assert_has_permission(Permission::Pop3Retr)?;
|
||||
|
||||
let op_start = Instant::now();
|
||||
let mailbox = self.state.mailbox();
|
||||
if let Some(message) = mailbox.messages.get(msg.saturating_sub(1) as usize) {
|
||||
|
||||
@@ -7,11 +7,17 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use common::listener::SessionStream;
|
||||
use directory::Permission;
|
||||
|
||||
use crate::{protocol::response::Response, Session};
|
||||
|
||||
impl<T: SessionStream> Session<T> {
|
||||
pub async fn handle_list(&mut self, msg: Option<u32>) -> trc::Result<()> {
|
||||
// Validate access
|
||||
self.state
|
||||
.access_token()
|
||||
.assert_has_permission(Permission::Pop3List)?;
|
||||
|
||||
let op_start = Instant::now();
|
||||
let mailbox = self.state.mailbox();
|
||||
if let Some(msg) = msg {
|
||||
@@ -48,6 +54,11 @@ impl<T: SessionStream> Session<T> {
|
||||
}
|
||||
|
||||
pub async fn handle_uidl(&mut self, msg: Option<u32>) -> trc::Result<()> {
|
||||
// Validate access
|
||||
self.state
|
||||
.access_token()
|
||||
.assert_has_permission(Permission::Pop3Uidl)?;
|
||||
|
||||
let op_start = Instant::now();
|
||||
let mailbox = self.state.mailbox();
|
||||
if let Some(msg) = msg {
|
||||
@@ -92,6 +103,11 @@ impl<T: SessionStream> Session<T> {
|
||||
}
|
||||
|
||||
pub async fn handle_stat(&mut self) -> trc::Result<()> {
|
||||
// Validate access
|
||||
self.state
|
||||
.access_token()
|
||||
.assert_has_permission(Permission::Pop3Stat)?;
|
||||
|
||||
let op_start = Instant::now();
|
||||
let mailbox = self.state.mailbox();
|
||||
|
||||
|
||||
@@ -4,7 +4,61 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use common::listener::SessionStream;
|
||||
|
||||
use crate::{
|
||||
protocol::{response::Response, Mechanism},
|
||||
Session,
|
||||
};
|
||||
|
||||
pub mod authenticate;
|
||||
pub mod delete;
|
||||
pub mod fetch;
|
||||
pub mod list;
|
||||
|
||||
impl<T: SessionStream> Session<T> {
|
||||
pub async fn handle_capa(&mut self) -> trc::Result<()> {
|
||||
let mechanisms = if self.stream.is_tls() || self.jmap.core.imap.allow_plain_auth {
|
||||
vec![Mechanism::Plain, Mechanism::OAuthBearer]
|
||||
} else {
|
||||
vec![Mechanism::OAuthBearer]
|
||||
};
|
||||
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::Capabilities),
|
||||
SpanId = self.session_id,
|
||||
Tls = self.stream.is_tls(),
|
||||
Strict = !self.jmap.core.imap.allow_plain_auth,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_bytes(
|
||||
Response::Capability::<u32> {
|
||||
mechanisms,
|
||||
stls: !self.stream.is_tls(),
|
||||
}
|
||||
.serialize(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn handle_stls(&mut self) -> trc::Result<()> {
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::StartTls),
|
||||
SpanId = self.session_id,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_ok("Begin TLS negotiation now").await
|
||||
}
|
||||
|
||||
pub async fn handle_utf8(&mut self) -> trc::Result<()> {
|
||||
trc::event!(
|
||||
Pop3(trc::Pop3Event::Utf8),
|
||||
SpanId = self.session_id,
|
||||
Elapsed = trc::Value::Duration(0)
|
||||
);
|
||||
|
||||
self.write_ok("UTF8 enabled").await
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user