Skip to main content

openstack_keystone_core/token/backend/fernet/
unscoped.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
15use rmp::{decode::read_pfix, encode::write_pfix};
16use std::io::Write;
17
18use crate::token::{
19    backend::fernet::{FernetTokenProvider, MsgPackToken, utils},
20    error::TokenProviderError,
21    types::UnscopedPayload,
22};
23
24impl MsgPackToken for UnscopedPayload {
25    type Token = Self;
26
27    fn assemble<W: Write>(
28        &self,
29        wd: &mut W,
30        fernet_provider: &FernetTokenProvider,
31    ) -> Result<(), TokenProviderError> {
32        utils::write_uuid(wd, &self.user_id)?;
33        write_pfix(
34            wd,
35            fernet_provider.encode_auth_methods(self.methods.clone())?,
36        )
37        .map_err(|x| TokenProviderError::RmpEncode(x.to_string()))?;
38        utils::write_time(wd, self.expires_at)?;
39        utils::write_audit_ids(wd, self.audit_ids.clone())?;
40
41        Ok(())
42    }
43
44    fn disassemble(
45        rd: &mut &[u8],
46        fernet_provider: &FernetTokenProvider,
47    ) -> Result<Self::Token, TokenProviderError> {
48        // Order of writing is important
49        let user_id = utils::read_uuid(rd)?;
50        let methods: Vec<String> = fernet_provider
51            .decode_auth_methods(read_pfix(rd)?)?
52            .into_iter()
53            .collect();
54        let expires_at = utils::read_time(rd)?;
55        let audit_ids: Vec<String> = utils::read_audit_ids(rd)?.into_iter().collect();
56        Ok(Self::Token {
57            user_id,
58            methods,
59            expires_at,
60            audit_ids,
61            ..Default::default()
62        })
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use chrono::{Local, SubsecRound};
69    use uuid::Uuid;
70
71    use super::*;
72    use crate::token::tests::setup_config;
73
74    #[test]
75    fn test_roundtrip() {
76        let token = UnscopedPayload {
77            user_id: Uuid::new_v4().simple().to_string(),
78            methods: vec!["password".into()],
79            audit_ids: vec!["Zm9vCg".into()],
80            expires_at: Local::now().trunc_subsecs(0).into(),
81            ..Default::default()
82        };
83
84        let provider = FernetTokenProvider::new(setup_config());
85
86        let mut buf = vec![];
87        token.assemble(&mut buf, &provider).unwrap();
88        let encoded_buf = buf.clone();
89        let decoded = UnscopedPayload::disassemble(&mut encoded_buf.as_slice(), &provider).unwrap();
90        assert_eq!(token, decoded);
91    }
92}