Skip to main content

security/
authorization.rs

1use bitflags::bitflags;
2use serde_json::Value;
3
4use crate::bridge;
5use crate::error::Result;
6
7bitflags! {
8    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9    /// Mirrors Authorization Services option bits used with `AuthorizationCreate`.
10    pub struct AuthorizationOptions: u32 {
11        /// Mirrors an Authorization Services option bit.
12        const DEFAULTS = 0;
13        /// Mirrors an Authorization Services option bit.
14        const INTERACTION_ALLOWED = 1 << 0;
15        /// Mirrors an Authorization Services option bit.
16        const EXTEND_RIGHTS = 1 << 1;
17        /// Mirrors an Authorization Services option bit.
18        const PARTIAL_RIGHTS = 1 << 2;
19        /// Mirrors an Authorization Services option bit.
20        const DESTROY_RIGHTS = 1 << 3;
21        /// Mirrors an Authorization Services option bit.
22        const PREAUTHORIZE = 1 << 4;
23        /// Mirrors an Authorization Services option bit.
24        const SKIP_INTERNAL_AUTH = 1 << 9;
25        /// Mirrors an Authorization Services option bit.
26        const NO_DATA = 1 << 20;
27    }
28}
29
30#[derive(Debug)]
31/// Wraps `AuthorizationRef`.
32pub struct Authorization {
33    handle: bridge::Handle,
34}
35
36impl Authorization {
37    #[cfg(feature = "async")]
38    pub(crate) fn as_ptr(&self) -> *mut std::ffi::c_void {
39        self.handle.as_ptr()
40    }
41
42    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
43    pub fn new() -> Result<Self> {
44        Self::with_options(AuthorizationOptions::DEFAULTS)
45    }
46
47    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
48    pub fn with_options(options: AuthorizationOptions) -> Result<Self> {
49        let mut status = 0;
50        let mut error = std::ptr::null_mut();
51        let raw = unsafe {
52            bridge::security_authorization_create(options.bits(), &mut status, &mut error)
53        };
54        bridge::required_handle("security_authorization_create", raw, status, error)
55            .map(|handle| Self { handle })
56    }
57
58    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
59    pub fn external_form(&self) -> Result<Vec<u8>> {
60        let mut status = 0;
61        let mut error = std::ptr::null_mut();
62        let raw = unsafe {
63            bridge::security_authorization_make_external_form(
64                self.handle.as_ptr(),
65                &mut status,
66                &mut error,
67            )
68        };
69        bridge::required_data(
70            "security_authorization_make_external_form",
71            raw,
72            status,
73            error,
74        )
75    }
76
77    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
78    pub fn from_external_form(external_form: &[u8]) -> Result<Self> {
79        let mut status = 0;
80        let mut error = std::ptr::null_mut();
81        let raw = unsafe {
82            bridge::security_authorization_create_from_external_form(
83                external_form.as_ptr().cast(),
84                bridge::len_to_isize(external_form.len())?,
85                &mut status,
86                &mut error,
87            )
88        };
89        bridge::required_handle(
90            "security_authorization_create_from_external_form",
91            raw,
92            status,
93            error,
94        )
95        .map(|handle| Self { handle })
96    }
97
98    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
99    pub fn copy_info(&self, tag: Option<&str>) -> Result<Value> {
100        let tag = tag.map(bridge::cstring).transpose()?;
101        let mut status = 0;
102        let mut error = std::ptr::null_mut();
103        let raw = unsafe {
104            bridge::security_authorization_copy_info(
105                self.handle.as_ptr(),
106                tag.as_ref()
107                    .map_or(std::ptr::null(), |value| value.as_ptr()),
108                &mut status,
109                &mut error,
110            )
111        };
112        bridge::required_json("security_authorization_copy_info", raw, status, error)
113    }
114
115    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
116    pub fn copy_rights(&self, rights: &[&str], options: AuthorizationOptions) -> Result<Value> {
117        let rights_json = bridge::json_cstring(&rights)?;
118        let mut status = 0;
119        let mut error = std::ptr::null_mut();
120        let raw = unsafe {
121            bridge::security_authorization_copy_rights(
122                self.handle.as_ptr(),
123                rights_json.as_ptr(),
124                options.bits(),
125                &mut status,
126                &mut error,
127            )
128        };
129        bridge::required_json("security_authorization_copy_rights", raw, status, error)
130    }
131
132    /// Wraps the corresponding Authorization Services operation for `AuthorizationRef`.
133    pub fn copy_rights_async(
134        &self,
135        rights: &[&str],
136        options: AuthorizationOptions,
137    ) -> Result<Value> {
138        let rights_json = bridge::json_cstring(&rights)?;
139        let mut status = 0;
140        let mut error = std::ptr::null_mut();
141        let raw = unsafe {
142            bridge::security_authorization_copy_rights_async(
143                self.handle.as_ptr(),
144                rights_json.as_ptr(),
145                options.bits(),
146                &mut status,
147                &mut error,
148            )
149        };
150        bridge::required_json(
151            "security_authorization_copy_rights_async",
152            raw,
153            status,
154            error,
155        )
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn defaults_are_empty() {
165        assert!(AuthorizationOptions::DEFAULTS.is_empty());
166        assert_eq!(AuthorizationOptions::DEFAULTS.bits(), 0);
167    }
168
169    #[test]
170    fn authorization_options_round_trip_through_bits() {
171        let options = AuthorizationOptions::INTERACTION_ALLOWED
172            | AuthorizationOptions::EXTEND_RIGHTS
173            | AuthorizationOptions::PREAUTHORIZE;
174
175        assert_eq!(
176            AuthorizationOptions::from_bits(options.bits()),
177            Some(options)
178        );
179    }
180
181    #[test]
182    fn authorization_options_keep_sparse_bits() {
183        let options = AuthorizationOptions::SKIP_INTERNAL_AUTH | AuthorizationOptions::NO_DATA;
184
185        assert!(options.contains(AuthorizationOptions::SKIP_INTERNAL_AUTH));
186        assert!(options.contains(AuthorizationOptions::NO_DATA));
187        assert_eq!(options.bits(), (1 << 9) | (1 << 20));
188    }
189}