Skip to main content

openstack_keystone_core/token/backend/fernet/
restricted.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5//     http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12//
13// SPDX-License-Identifier: Apache-2.0
14//! Restricted token Fernet implementation.
15
16use rmp::{decode::read_pfix, encode::write_pfix};
17use std::io::Write;
18
19use crate::token::{
20    backend::fernet::{FernetTokenProvider, MsgPackToken, utils},
21    error::TokenProviderError,
22    types::RestrictedPayload,
23};
24
25impl MsgPackToken for RestrictedPayload {
26    type Token = Self;
27
28    fn assemble<W: Write>(
29        &self,
30        wd: &mut W,
31        fernet_provider: &FernetTokenProvider,
32    ) -> Result<(), TokenProviderError> {
33        utils::write_uuid(wd, &self.user_id)?;
34        write_pfix(
35            wd,
36            fernet_provider.encode_auth_methods(self.methods.clone())?,
37        )
38        .map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
39        utils::write_uuid(wd, &self.token_restriction_id)?;
40        utils::write_time(wd, self.expires_at)?;
41        utils::write_uuid(wd, &self.project_id)?;
42        utils::write_bool(wd, self.allow_renew)?;
43        utils::write_bool(wd, self.allow_rescope)?;
44        utils::write_audit_ids(wd, self.audit_ids.clone())?;
45
46        Ok(())
47    }
48
49    fn disassemble(
50        rd: &mut &[u8],
51        fernet_provider: &FernetTokenProvider,
52    ) -> Result<Self::Token, TokenProviderError> {
53        // Order of reading is important
54        let user_id = utils::read_uuid(rd)?;
55        let methods: Vec<String> = fernet_provider
56            .decode_auth_methods(read_pfix(rd)?)?
57            .into_iter()
58            .collect();
59        let token_restriction_id = utils::read_uuid(rd)?;
60        let expires_at = utils::read_time(rd)?;
61        let project_id = utils::read_uuid(rd)?;
62        let allow_renew = utils::read_bool(rd)?;
63        let allow_rescope = utils::read_bool(rd)?;
64        let audit_ids: Vec<String> = utils::read_audit_ids(rd)?.into_iter().collect();
65        Ok(Self {
66            user_id,
67            methods,
68            expires_at,
69            audit_ids,
70            token_restriction_id,
71            project_id,
72            allow_renew,
73            allow_rescope,
74
75            ..Default::default()
76        })
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use chrono::{Local, SubsecRound};
83    use uuid::Uuid;
84
85    use super::*;
86    use crate::token::tests::setup_config;
87
88    #[test]
89    fn test_roundtrip() {
90        let token = RestrictedPayload {
91            user_id: Uuid::new_v4().simple().to_string(),
92            methods: vec!["openid".into()],
93            audit_ids: vec!["Zm9vCg".into()],
94            expires_at: Local::now().trunc_subsecs(0).into(),
95            token_restriction_id: "trid".into(),
96            project_id: "pid".into(),
97            allow_renew: true,
98            allow_rescope: true,
99            ..Default::default()
100        };
101
102        let provider = FernetTokenProvider::new(setup_config());
103
104        let mut buf = vec![];
105        token.assemble(&mut buf, &provider).unwrap();
106        let encoded_buf = buf.clone();
107        let decoded =
108            RestrictedPayload::disassemble(&mut encoded_buf.as_slice(), &provider).unwrap();
109        assert_eq!(token, decoded);
110    }
111}