Allow local access tokens to be used with OIDC backends (closes #1311 closes stalwartlabs/webadmin#52)
This commit is contained in:
@@ -4,16 +4,15 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use common::auth::AccessToken;
|
||||
use common::{HttpAuthCache, Server, auth::AuthRequest, listener::limiter::InFlight};
|
||||
use http_proto::{HttpRequest, HttpSessionData};
|
||||
use hyper::header;
|
||||
use mail_parser::decoders::base64::base64_decode;
|
||||
use mail_send::Credentials;
|
||||
|
||||
use common::auth::AccessToken;
|
||||
use std::future::Future;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub trait Authenticator: Sync + Send {
|
||||
fn authenticate_headers(
|
||||
@@ -34,19 +33,20 @@ impl Authenticator for Server {
|
||||
if let Some((mechanism, token)) = req.authorization() {
|
||||
// Check if the credentials are cached
|
||||
if let Some(http_cache) = self.inner.cache.http_auth.get(token) {
|
||||
let access_token = self.get_access_token(http_cache.account_id).await?;
|
||||
|
||||
// Make sure the revision is still valid
|
||||
if access_token.revision == http_cache.revision {
|
||||
// Enforce authenticated rate limit
|
||||
return self
|
||||
.is_http_authenticated_request_allowed(&access_token)
|
||||
.await
|
||||
.map(|in_flight| (in_flight, access_token));
|
||||
} else {
|
||||
// If the revision is not valid, remove the cached credentials
|
||||
self.inner.cache.http_auth.remove(token);
|
||||
if http_cache.expires <= Instant::now() {
|
||||
let access_token = self.get_access_token(http_cache.account_id).await?;
|
||||
if access_token.revision == http_cache.revision {
|
||||
// Enforce authenticated rate limit
|
||||
return self
|
||||
.is_http_authenticated_request_allowed(&access_token)
|
||||
.await
|
||||
.map(|in_flight| (in_flight, access_token));
|
||||
}
|
||||
}
|
||||
|
||||
// If the revision is not valid, remove the cached credentials
|
||||
self.inner.cache.http_auth.remove(token);
|
||||
}
|
||||
|
||||
let credentials = if mechanism.eq_ignore_ascii_case("basic") {
|
||||
@@ -100,6 +100,8 @@ impl Authenticator for Server {
|
||||
HttpAuthCache {
|
||||
account_id: access_token.primary_id(),
|
||||
revision: access_token.revision,
|
||||
expires: Instant::now()
|
||||
+ Duration::from_secs(self.core.oauth.oauth_expiry_token),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ use common::{
|
||||
};
|
||||
|
||||
use directory::{
|
||||
Permission, QueryBy, Type,
|
||||
Permission, QueryParams, Type,
|
||||
backend::internal::{
|
||||
PrincipalField, PrincipalSet, lookup::DirectoryStore, manage::ManageDirectory,
|
||||
},
|
||||
@@ -113,7 +113,7 @@ impl ClientRegistrationHandler for Server {
|
||||
// Fetch client registration
|
||||
let found_registration = if let Some(client) = self
|
||||
.store()
|
||||
.query(QueryBy::Name(client_id), false)
|
||||
.query(QueryParams::name(client_id).with_return_member_of(false))
|
||||
.await
|
||||
.caused_by(trc::location!())?
|
||||
.filter(|p| p.typ() == Type::OauthClient)
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
use common::{Server, manager::webadmin::Resource};
|
||||
|
||||
use directory::QueryBy;
|
||||
use directory::QueryParams;
|
||||
use http_proto::*;
|
||||
use quick_xml::Reader;
|
||||
use quick_xml::events::Event;
|
||||
use std::fmt::Write;
|
||||
use std::future::Future;
|
||||
use trc::AddContext;
|
||||
use utils::url_params::UrlParams;
|
||||
|
||||
use http_proto::*;
|
||||
use std::future::Future;
|
||||
|
||||
pub trait Autoconfig: Sync + Send {
|
||||
fn handle_autoconfig_request(
|
||||
&self,
|
||||
@@ -211,7 +208,7 @@ impl Autoconfig for Server {
|
||||
.core
|
||||
.storage
|
||||
.directory
|
||||
.query(QueryBy::Id(id), false)
|
||||
.query(QueryParams::id(id).with_return_member_of(false))
|
||||
.await
|
||||
{
|
||||
if principal
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use common::{KV_BAYES_MODEL_USER, Server, auth::AccessToken};
|
||||
use directory::{
|
||||
DirectoryInner, Permission, QueryBy, Type,
|
||||
DirectoryInner, Permission, QueryBy, QueryParams, Type,
|
||||
backend::internal::{
|
||||
PrincipalAction, PrincipalField, PrincipalSet, PrincipalUpdate, PrincipalValue,
|
||||
SpecialSecrets,
|
||||
@@ -476,7 +476,7 @@ impl PrincipalManager for Server {
|
||||
|
||||
let principal = self
|
||||
.store()
|
||||
.query(QueryBy::Id(account_id), true)
|
||||
.query(QueryParams::id(account_id).with_return_member_of(true))
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
|
||||
@@ -707,7 +707,7 @@ impl PrincipalManager for Server {
|
||||
if access_token.primary_id() != u32::MAX {
|
||||
let principal = self
|
||||
.directory()
|
||||
.query(QueryBy::Id(access_token.primary_id()), false)
|
||||
.query(QueryParams::id(access_token.primary_id()).with_return_member_of(false))
|
||||
.await?
|
||||
.ok_or_else(|| trc::ManageEvent::NotFound.into_err())?;
|
||||
|
||||
@@ -803,7 +803,16 @@ impl PrincipalManager for Server {
|
||||
}
|
||||
|
||||
// Make sure the current directory supports updates
|
||||
self.assert_supported_directory(false)?;
|
||||
if requests.iter().any(|r| {
|
||||
matches!(
|
||||
r,
|
||||
AccountAuthRequest::SetPassword { .. }
|
||||
| AccountAuthRequest::EnableOtpAuth { .. }
|
||||
| AccountAuthRequest::DisableOtpAuth { .. }
|
||||
)
|
||||
}) {
|
||||
self.assert_supported_directory(false)?;
|
||||
}
|
||||
|
||||
// Build actions
|
||||
let mut actions = Vec::with_capacity(requests.len());
|
||||
|
||||
Reference in New Issue
Block a user