Skip to main content

coil_auth/
service.rs

1use super::*;
2
3#[derive(Clone)]
4pub struct CoilAuth<E> {
5    engine: E,
6    tenant_id: i64,
7}
8
9impl<E> CoilAuth<E> {
10    pub fn new(engine: E, tenant_id: i64) -> Self {
11        Self { engine, tenant_id }
12    }
13
14    pub fn tenant_id(&self) -> i64 {
15        self.tenant_id
16    }
17
18    pub fn engine(&self) -> &E {
19        &self.engine
20    }
21
22    pub fn into_inner(self) -> E {
23        self.engine
24    }
25}
26
27impl<E> CoilAuth<E>
28where
29    E: RebacEngine,
30{
31    pub async fn apply_default_schema(&self) -> Result<(), RebacError> {
32        self.apply_model_package(&DefaultAuthModelPackage::default())
33            .await
34    }
35
36    pub async fn apply_model_package<P>(&self, package: &P) -> Result<(), RebacError>
37    where
38        P: AuthModelPackage + ?Sized,
39    {
40        self.engine
41            .apply_schema(self.tenant_id, package.schema().clone())
42            .await
43    }
44
45    pub async fn write(
46        &self,
47        updates: impl IntoIterator<Item = DefaultTupleUpdate>,
48    ) -> Result<(), RebacError> {
49        self.engine
50            .write_tuples(
51                self.tenant_id,
52                updates.into_iter().map(Into::into).collect(),
53            )
54            .await
55    }
56
57    pub async fn check(
58        &self,
59        subject: &DefaultSubject,
60        relation: Relation,
61        object: &Entity,
62    ) -> Result<bool, RebacError> {
63        let subject = subject.to_subject();
64        let object = object.to_object();
65
66        self.engine
67            .check(self.tenant_id, &subject, relation.as_str(), &object)
68            .await
69    }
70
71    pub async fn check_capability<P>(
72        &self,
73        package: &P,
74        subject: &DefaultSubject,
75        capability: Capability,
76        object: &Entity,
77    ) -> Result<bool, CoilAuthError>
78    where
79        P: AuthModelPackage + ?Sized,
80    {
81        let binding = package.resolve_binding(capability, object)?;
82        let subject = subject.to_subject();
83        let object = object.to_object();
84
85        Ok(self
86            .engine
87            .check(self.tenant_id, &subject, binding.relation.as_str(), &object)
88            .await?)
89    }
90
91    pub async fn check_default_capability(
92        &self,
93        subject: &DefaultSubject,
94        capability: Capability,
95        object: &Entity,
96    ) -> Result<bool, CoilAuthError> {
97        self.check_capability(
98            &DefaultAuthModelPackage::default(),
99            subject,
100            capability,
101            object,
102        )
103        .await
104    }
105
106    pub async fn explain_capability<P>(
107        &self,
108        package: &P,
109        subject: &DefaultSubject,
110        capability: Capability,
111        object: &Entity,
112    ) -> Result<CapabilityExplanation, CoilAuthError>
113    where
114        P: AuthModelPackage + ?Sized,
115    {
116        self.explain_capability_with_options(
117            package,
118            subject,
119            capability,
120            object,
121            ExplainOptions::default(),
122        )
123        .await
124    }
125
126    pub async fn explain_capability_with_options<P>(
127        &self,
128        package: &P,
129        subject: &DefaultSubject,
130        capability: Capability,
131        object: &Entity,
132        options: ExplainOptions,
133    ) -> Result<CapabilityExplanation, CoilAuthError>
134    where
135        P: AuthModelPackage + ?Sized,
136    {
137        let tuples = self
138            .engine
139            .read_tuples(self.tenant_id, None, None, None)
140            .await?;
141
142        build_capability_explanation(package, &tuples, subject, capability, object, options)
143    }
144
145    pub async fn explain_default_capability(
146        &self,
147        subject: &DefaultSubject,
148        capability: Capability,
149        object: &Entity,
150    ) -> Result<CapabilityExplanation, CoilAuthError> {
151        self.explain_default_capability_with_options(
152            subject,
153            capability,
154            object,
155            ExplainOptions::default(),
156        )
157        .await
158    }
159
160    pub async fn explain_default_capability_with_options(
161        &self,
162        subject: &DefaultSubject,
163        capability: Capability,
164        object: &Entity,
165        options: ExplainOptions,
166    ) -> Result<CapabilityExplanation, CoilAuthError> {
167        self.explain_capability_with_options(
168            &DefaultAuthModelPackage::default(),
169            subject,
170            capability,
171            object,
172            options,
173        )
174        .await
175    }
176
177    pub async fn check_many(
178        &self,
179        requests: impl IntoIterator<Item = AccessCheck>,
180    ) -> Result<Vec<bool>, RebacError> {
181        self.engine
182            .check_many(
183                self.tenant_id,
184                requests.into_iter().map(Into::into).collect(),
185            )
186            .await
187    }
188
189    pub async fn list_objects(
190        &self,
191        subject: &DefaultSubject,
192        relation: Relation,
193        namespace: Namespace,
194    ) -> Result<Vec<String>, RebacError> {
195        let subject = subject.to_subject();
196
197        self.engine
198            .list_objects(
199                self.tenant_id,
200                &subject,
201                relation.as_str(),
202                namespace.as_str(),
203            )
204            .await
205    }
206
207    pub async fn list_subject_ids(
208        &self,
209        object: &Entity,
210        relation: Relation,
211        namespace: Namespace,
212    ) -> Result<Vec<String>, RebacError> {
213        let object = object.to_object();
214
215        self.engine
216            .list_subjects(
217                self.tenant_id,
218                &object,
219                relation.as_str(),
220                namespace.as_str(),
221            )
222            .await
223    }
224}