openstack_keystone_core/token/
mod.rs1use async_trait::async_trait;
23
24pub mod backend;
25pub mod error;
26#[cfg(any(test, feature = "mock"))]
27mod mock;
28pub mod service;
29pub mod types;
31
32use crate::auth::{AuthenticatedInfo, AuthzInfo};
33use crate::config::Config;
34use crate::keystone::ServiceState;
35use crate::plugin_manager::PluginManagerApi;
36use crate::token::service::TokenService;
37pub use error::TokenProviderError;
38
39pub use crate::token::types::*;
40#[cfg(any(test, feature = "mock"))]
41pub use mock::MockTokenProvider;
42
43pub enum TokenProvider {
44 Service(TokenService),
45 #[cfg(any(test, feature = "mock"))]
46 Mock(MockTokenProvider),
47}
48
49impl TokenProvider {
50 pub fn new<P: PluginManagerApi>(
51 config: &Config,
52 plugin_manager: &P,
53 ) -> Result<Self, TokenProviderError> {
54 Ok(Self::Service(TokenService::new(config, plugin_manager)?))
55 }
56}
57
58#[async_trait]
59impl TokenApi for TokenProvider {
60 async fn authenticate_by_token<'a>(
62 &self,
63 state: &ServiceState,
64 credential: &'a str,
65 allow_expired: Option<bool>,
66 window_seconds: Option<i64>,
67 ) -> Result<AuthenticatedInfo, TokenProviderError> {
68 match self {
69 Self::Service(provider) => {
70 provider
71 .authenticate_by_token(state, credential, allow_expired, window_seconds)
72 .await
73 }
74 #[cfg(any(test, feature = "mock"))]
75 Self::Mock(provider) => {
76 provider
77 .authenticate_by_token(state, credential, allow_expired, window_seconds)
78 .await
79 }
80 }
81 }
82
83 async fn validate_token<'a>(
85 &self,
86 state: &ServiceState,
87 credential: &'a str,
88 allow_expired: Option<bool>,
89 window_seconds: Option<i64>,
90 ) -> Result<Token, TokenProviderError> {
91 match self {
92 Self::Service(provider) => {
93 provider
94 .validate_token(state, credential, allow_expired, window_seconds)
95 .await
96 }
97 #[cfg(any(test, feature = "mock"))]
98 Self::Mock(provider) => {
99 provider
100 .validate_token(state, credential, allow_expired, window_seconds)
101 .await
102 }
103 }
104 }
105
106 fn issue_token(
108 &self,
109 authentication_info: AuthenticatedInfo,
110 authz_info: AuthzInfo,
111 token_restrictions: Option<&TokenRestriction>,
112 ) -> Result<Token, TokenProviderError> {
113 match self {
114 Self::Service(provider) => {
115 provider.issue_token(authentication_info, authz_info, token_restrictions)
116 }
117 #[cfg(any(test, feature = "mock"))]
118 Self::Mock(provider) => {
119 provider.issue_token(authentication_info, authz_info, token_restrictions)
120 }
121 }
122 }
123
124 fn encode_token(&self, token: &Token) -> Result<String, TokenProviderError> {
128 match self {
129 Self::Service(provider) => provider.encode_token(token),
130 #[cfg(any(test, feature = "mock"))]
131 Self::Mock(provider) => provider.encode_token(token),
132 }
133 }
134
135 async fn populate_role_assignments(
137 &self,
138 state: &ServiceState,
139 token: &mut Token,
140 ) -> Result<(), TokenProviderError> {
141 match self {
142 Self::Service(provider) => provider.populate_role_assignments(state, token).await,
143 #[cfg(any(test, feature = "mock"))]
144 Self::Mock(provider) => provider.populate_role_assignments(state, token).await,
145 }
146 }
147
148 async fn expand_token_information(
153 &self,
154 state: &ServiceState,
155 token: &Token,
156 ) -> Result<Token, TokenProviderError> {
157 match self {
158 Self::Service(provider) => provider.expand_token_information(state, token).await,
159 #[cfg(any(test, feature = "mock"))]
160 Self::Mock(provider) => provider.expand_token_information(state, token).await,
161 }
162 }
163
164 async fn get_token_restriction<'a>(
166 &self,
167 state: &ServiceState,
168 id: &'a str,
169 expand_roles: bool,
170 ) -> Result<Option<TokenRestriction>, TokenProviderError> {
171 match self {
172 Self::Service(provider) => {
173 provider
174 .get_token_restriction(state, id, expand_roles)
175 .await
176 }
177 #[cfg(any(test, feature = "mock"))]
178 Self::Mock(provider) => {
179 provider
180 .get_token_restriction(state, id, expand_roles)
181 .await
182 }
183 }
184 }
185
186 async fn create_token_restriction<'a>(
188 &self,
189 state: &ServiceState,
190 restriction: TokenRestrictionCreate,
191 ) -> Result<TokenRestriction, TokenProviderError> {
192 match self {
193 Self::Service(provider) => provider.create_token_restriction(state, restriction).await,
194 #[cfg(any(test, feature = "mock"))]
195 Self::Mock(provider) => provider.create_token_restriction(state, restriction).await,
196 }
197 }
198
199 async fn list_token_restrictions<'a>(
201 &self,
202 state: &ServiceState,
203 params: &TokenRestrictionListParameters,
204 ) -> Result<Vec<TokenRestriction>, TokenProviderError> {
205 match self {
206 Self::Service(provider) => provider.list_token_restrictions(state, params).await,
207 #[cfg(any(test, feature = "mock"))]
208 Self::Mock(provider) => provider.list_token_restrictions(state, params).await,
209 }
210 }
211
212 async fn update_token_restriction<'a>(
214 &self,
215 state: &ServiceState,
216 id: &'a str,
217 restriction: TokenRestrictionUpdate,
218 ) -> Result<TokenRestriction, TokenProviderError> {
219 match self {
220 Self::Service(provider) => {
221 provider
222 .update_token_restriction(state, id, restriction)
223 .await
224 }
225 #[cfg(any(test, feature = "mock"))]
226 Self::Mock(provider) => {
227 provider
228 .update_token_restriction(state, id, restriction)
229 .await
230 }
231 }
232 }
233
234 async fn delete_token_restriction<'a>(
236 &self,
237 state: &ServiceState,
238 id: &'a str,
239 ) -> Result<(), TokenProviderError> {
240 match self {
241 Self::Service(provider) => provider.delete_token_restriction(state, id).await,
242 #[cfg(any(test, feature = "mock"))]
243 Self::Mock(provider) => provider.delete_token_restriction(state, id).await,
244 }
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use std::fs::File;
251 use std::io::Write;
252 use tempfile::tempdir;
253
254 use crate::config::Config;
255
256 pub(super) fn setup_config() -> Config {
257 let keys_dir = tempdir().unwrap();
258 let file_path = keys_dir.path().join("0");
260 let mut tmp_file = File::create(file_path).unwrap();
261 write!(tmp_file, "BFTs1CIVIBLTP4GOrQ26VETrJ7Zwz1O4wbEcCQ966eM=").unwrap();
262
263 let builder = config::Config::builder()
264 .set_override(
265 "auth.methods",
266 "password,token,openid,application_credential",
267 )
268 .unwrap()
269 .set_override("database.connection", "dummy")
270 .unwrap();
271 let mut config: Config = Config::try_from(builder).expect("can build a valid config");
272 config.fernet_tokens.key_repository = keys_dir.keep();
273 config
274 }
275}