mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-03-29 23:39:40 -06:00
Add SMTP OAuth2 configuration options and improve error handling
This commit is contained in:
parent
8bd2a0b26c
commit
c17837fa2a
@ -624,6 +624,17 @@
|
||||
## Multiple options need to be separated by a comma ','.
|
||||
# SMTP_AUTH_MECHANISM=
|
||||
|
||||
## SMTP OAuth2 settings
|
||||
## These are required if SMTP_AUTH_MECHANISM includes "Xoauth2".
|
||||
## After configuring these, you'll need to use the admin panel to complete the authorization flow.
|
||||
# SMTP_OAUTH2_CLIENT_ID=
|
||||
# SMTP_OAUTH2_CLIENT_SECRET=
|
||||
# SMTP_OAUTH2_AUTH_URL=
|
||||
# SMTP_OAUTH2_TOKEN_URL=
|
||||
# SMTP_OAUTH2_SCOPES=
|
||||
## The refresh token is typically obtained automatically during the authorization flow in the admin panel.
|
||||
# SMTP_OAUTH2_REFRESH_TOKEN=
|
||||
|
||||
## Server name sent during the SMTP HELO
|
||||
## By default this value should be the machine's hostname,
|
||||
## but might need to be changed in case it trips some anti-spam filters
|
||||
|
||||
@ -352,7 +352,7 @@ async fn test_smtp(data: Json<InviteData>, _token: AdminToken) -> EmptyResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/test/oauth2")]
|
||||
#[post("/oauth2/test")]
|
||||
async fn refresh_oauth2_token_endpoint(_token: AdminToken) -> EmptyResult {
|
||||
if CONFIG.smtp_oauth2_client_id().is_none() {
|
||||
err!("OAuth2 is not configured")
|
||||
@ -384,7 +384,7 @@ fn oauth2_authorize(_token: AdminToken) -> Result<Redirect, Error> {
|
||||
let redirect_uri = format!("{}/admin/oauth2/callback", CONFIG.domain());
|
||||
|
||||
// Build authorization URL using url crate to ensure proper encoding
|
||||
let mut url = Url::parse(&auth_url).map_err(|e| Error::new("Invalid OAuth2 Authorization URL", e.to_string()))?;
|
||||
let mut url = Url::parse(&auth_url).map_err(|e| err!(format!("Invalid OAuth2 Authorization URL: {e}")))?;
|
||||
{
|
||||
let mut qp = url.query_pairs_mut();
|
||||
qp.append_pair("client_id", &client_id);
|
||||
@ -414,7 +414,7 @@ async fn oauth2_callback(params: OAuth2CallbackParams) -> Result<Html<String>, E
|
||||
// Check for errors from OAuth2 provider
|
||||
if let Some(error) = params.error {
|
||||
let description = params.error_description.unwrap_or_else(|| "Unknown error".to_string());
|
||||
return Err(Error::new("OAuth2 Authorization Failed", format!("{}: {}", error, description)));
|
||||
err!("OAuth2 Authorization Failed", format!("{error}: {description}"));
|
||||
}
|
||||
|
||||
// Validate required parameters
|
||||
@ -429,7 +429,7 @@ async fn oauth2_callback(params: OAuth2CallbackParams) -> Result<Html<String>, E
|
||||
};
|
||||
|
||||
if !valid_state {
|
||||
return Err(Error::new("OAuth2 State Validation Failed", "Invalid or expired state token"));
|
||||
err!("OAuth2 State Validation Failed", "Invalid or expired state token");
|
||||
}
|
||||
|
||||
// Remove used state
|
||||
@ -453,16 +453,16 @@ async fn oauth2_callback(params: OAuth2CallbackParams) -> Result<Html<String>, E
|
||||
.form(&form_params)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| Error::new("OAuth2 Token Exchange Error", e.to_string()))?;
|
||||
.map_err(|e| err!(format!("OAuth2 Token Exchange Error: {e}")))?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
let status = response.status();
|
||||
let body = response.text().await.unwrap_or_else(|_| String::from("Unable to read response body"));
|
||||
return Err(Error::new("OAuth2 Token Exchange Failed", format!("HTTP {}: {}", status, body)));
|
||||
err!("OAuth2 Token Exchange Failed", format!("HTTP {status}: {body}"));
|
||||
}
|
||||
|
||||
let token_response: Value =
|
||||
response.json().await.map_err(|e| Error::new("OAuth2 Token Parse Error", e.to_string()))?;
|
||||
response.json().await.map_err(|e| err!(format!("OAuth2 Token Parse Error: {e}")))?;
|
||||
|
||||
// Extract refresh_token from response
|
||||
let refresh_token =
|
||||
@ -472,7 +472,7 @@ async fn oauth2_callback(params: OAuth2CallbackParams) -> Result<Html<String>, E
|
||||
let config_builder: ConfigBuilder = serde_json::from_value(json!({
|
||||
"smtp_oauth2_refresh_token": refresh_token
|
||||
}))
|
||||
.map_err(|e| Error::new("ConfigBuilder serialization error", e.to_string()))?;
|
||||
.map_err(|e| err!(format!("ConfigBuilder serialization error: {e}")))?;
|
||||
CONFIG.update_config_partial(config_builder).await?;
|
||||
|
||||
// Return success page via template
|
||||
|
||||
@ -898,7 +898,7 @@ make_config! {
|
||||
/// SMTP OAuth2 Refresh Token |> OAuth2 Refresh Token for obtaining new access tokens
|
||||
smtp_oauth2_refresh_token: Pass, true, option;
|
||||
/// SMTP OAuth2 Scopes |> Comma-separated list of OAuth2 scopes
|
||||
smtp_oauth2_scopes: String, true, def, "https://mail.google.com/".to_string();
|
||||
smtp_oauth2_scopes: String, true, def, "".to_string();
|
||||
/// SMTP connection timeout |> Number of seconds when to stop trying to connect to the SMTP server
|
||||
smtp_timeout: u64, true, def, 15;
|
||||
/// Server name sent during HELO |> By default this value should be the machine's hostname, but might need to be changed in case it trips some anti-spam filters
|
||||
|
||||
@ -60,16 +60,16 @@ pub async fn refresh_oauth2_token() -> Result<OAuth2Token, Error> {
|
||||
.form(&form_params)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| Error::new("OAuth2 Token Refresh Error", e.to_string()))?;
|
||||
.map_err(|e| err!(format!("OAuth2 Token Refresh Error: {e}")))?;
|
||||
|
||||
if !response.status().is_success() {
|
||||
let status = response.status();
|
||||
let body = response.text().await.unwrap_or_else(|_| String::from("Unable to read response body"));
|
||||
return Err(Error::new("OAuth2 Token Refresh Failed", format!("HTTP {status}: {body}")));
|
||||
err!("OAuth2 Token Refresh Failed", format!("HTTP {status}: {body}"));
|
||||
}
|
||||
|
||||
let token_response: TokenRefreshResponse =
|
||||
response.json().await.map_err(|e| Error::new("OAuth2 Token Parse Error", e.to_string()))?;
|
||||
response.json().await.map_err(|e| err!(format!("OAuth2 Token Parse Error: {e}")))?;
|
||||
|
||||
let expires_at = token_response
|
||||
.expires_in
|
||||
|
||||
2
src/static/scripts/admin_settings.js
vendored
2
src/static/scripts/admin_settings.js
vendored
@ -34,7 +34,7 @@ function oauth2RefreshToken(event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_post(`${BASE_URL}/admin/test/oauth2`,
|
||||
_post(`${BASE_URL}/admin/oauth2/test`,
|
||||
"OAuth2 token refreshed successfully",
|
||||
"Error refreshing OAuth2 token",
|
||||
null, false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user