Skip to main content

rocketmq_auth/
provider_ports.rs

1// Copyright 2026 The RocketMQ Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::future::Future;
16use std::pin::Pin;
17use std::sync::Arc;
18
19use crate::authentication::enums::subject_type::SubjectType;
20use crate::authentication::model::subject::Subject;
21use crate::authentication::model::user::User;
22use crate::authentication::provider::AuthenticationMetadataProvider;
23use crate::authorization::metadata_provider::AuthorizationMetadataProvider;
24use crate::authorization::metadata_provider::LocalAuthorizationMetadataProvider;
25use crate::authorization::model::acl::Acl;
26use crate::AuthServiceResult;
27
28pub type ProviderFuture<'a, T> = Pin<Box<dyn Future<Output = AuthServiceResult<T>> + Send + 'a>>;
29
30/// Owned subject identity at the dynamic metadata boundary.
31#[derive(Clone, PartialEq, Eq, Hash)]
32pub struct SubjectKey {
33    subject_type: SubjectType,
34    key: String,
35}
36
37impl SubjectKey {
38    pub fn new(subject_type: SubjectType, key: impl Into<String>) -> Self {
39        Self {
40            subject_type,
41            key: key.into(),
42        }
43    }
44
45    pub fn from_subject(subject: &(impl Subject + ?Sized)) -> Self {
46        Self::new(subject.subject_type(), subject.subject_key())
47    }
48}
49
50impl Subject for SubjectKey {
51    fn subject_key(&self) -> &str {
52        &self.key
53    }
54    fn subject_type(&self) -> SubjectType {
55        self.subject_type
56    }
57}
58
59/// User lookup capability without mutation or provider lifecycle access.
60pub trait UserMetadataRead: Send + Sync {
61    fn lookup_user<'a>(&'a self, username: &'a str) -> ProviderFuture<'a, User>;
62}
63
64impl<T: AuthenticationMetadataProvider + ?Sized> UserMetadataRead for T {
65    fn lookup_user<'a>(&'a self, username: &'a str) -> ProviderFuture<'a, User> {
66        AuthenticationMetadataProvider::get_user(self, username)
67    }
68}
69
70pub(crate) struct LegacyUserReader(pub(crate) Arc<dyn AuthenticationMetadataProvider>);
71
72impl UserMetadataRead for LegacyUserReader {
73    fn lookup_user<'a>(&'a self, username: &'a str) -> ProviderFuture<'a, User> {
74        self.0.get_user(username)
75    }
76}
77
78/// Concurrent user metadata operations owned by an Auth runtime.
79pub trait UserMetadataPort: UserMetadataRead {
80    fn create_user(&self, user: User) -> ProviderFuture<'_, ()>;
81    fn update_user(&self, user: User) -> ProviderFuture<'_, ()>;
82    fn delete_user<'a>(&'a self, username: &'a str) -> ProviderFuture<'a, ()>;
83    fn list_user<'a>(&'a self, filter: Option<&'a str>) -> ProviderFuture<'a, Vec<User>>;
84}
85
86impl<T: AuthenticationMetadataProvider + ?Sized> UserMetadataPort for T {
87    fn create_user(&self, user: User) -> ProviderFuture<'_, ()> {
88        AuthenticationMetadataProvider::create_user(self, user)
89    }
90
91    fn update_user(&self, user: User) -> ProviderFuture<'_, ()> {
92        AuthenticationMetadataProvider::update_user(self, user)
93    }
94
95    fn delete_user<'a>(&'a self, username: &'a str) -> ProviderFuture<'a, ()> {
96        AuthenticationMetadataProvider::delete_user(self, username)
97    }
98
99    fn list_user<'a>(&'a self, filter: Option<&'a str>) -> ProviderFuture<'a, Vec<User>> {
100        AuthenticationMetadataProvider::list_user(self, filter)
101    }
102}
103
104/// ACL lookup capability without mutation or provider lifecycle access.
105pub trait AclMetadataRead: Send + Sync {
106    fn lookup_acl<'a>(&'a self, subject: &'a SubjectKey) -> ProviderFuture<'a, Option<Acl>>;
107}
108
109impl<T: AuthorizationMetadataProvider + ?Sized> AclMetadataRead for T {
110    fn lookup_acl<'a>(&'a self, subject: &'a SubjectKey) -> ProviderFuture<'a, Option<Acl>> {
111        Box::pin(AuthorizationMetadataProvider::get_acl(self, subject))
112    }
113}
114
115/// Concurrent ACL metadata operations, independent of lifecycle control.
116pub trait AclMetadataPort: AclMetadataRead {
117    fn create_acl(&self, acl: Acl) -> ProviderFuture<'_, ()>;
118    fn update_acl(&self, acl: Acl) -> ProviderFuture<'_, ()>;
119    fn delete_acl<'a>(&'a self, subject: &'a SubjectKey) -> ProviderFuture<'a, ()>;
120    fn list_acl<'a>(
121        &'a self,
122        subject_filter: Option<&'a str>,
123        resource_filter: Option<&'a str>,
124    ) -> ProviderFuture<'a, Vec<Acl>>;
125}
126
127impl AclMetadataPort for LocalAuthorizationMetadataProvider {
128    fn create_acl(&self, acl: Acl) -> ProviderFuture<'_, ()> {
129        Box::pin(AuthorizationMetadataProvider::create_acl(self, acl))
130    }
131
132    fn update_acl(&self, acl: Acl) -> ProviderFuture<'_, ()> {
133        Box::pin(AuthorizationMetadataProvider::update_acl(self, acl))
134    }
135
136    fn delete_acl<'a>(&'a self, subject: &'a SubjectKey) -> ProviderFuture<'a, ()> {
137        Box::pin(AuthorizationMetadataProvider::delete_acl(self, subject))
138    }
139
140    fn list_acl<'a>(
141        &'a self,
142        subject_filter: Option<&'a str>,
143        resource_filter: Option<&'a str>,
144    ) -> ProviderFuture<'a, Vec<Acl>> {
145        Box::pin(AuthorizationMetadataProvider::list_acl(
146            self,
147            subject_filter,
148            resource_filter,
149        ))
150    }
151}