apisix_admin_client/models/plugins/
consumer_restriction.rs

1use serde::{Deserialize, Serialize};
2use strum_macros::{Display, EnumString};
3use validator::Validate;
4use crate::{Result};
5use crate::models::Plugin;
6
7/// Builder pattern to create a ConsumerRestriction
8#[serde_with::skip_serializing_none]
9#[derive(Validate, Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct ConsumerRestrictionBuilder {
11    pub type_field: Option<ConsumerRestrictionType>,
12    pub whitelist: Option<Vec<String>>,
13    pub blacklist: Option<Vec<String>>,
14    pub rejected_code: Option<i32>,
15    pub rejected_msg: Option<String>,
16    pub allowed_by_methods: Option<Vec<AllowedByMethods>>,
17}
18
19impl ConsumerRestrictionBuilder {
20    pub fn new() -> Self {
21        ConsumerRestriction::default().into()
22    }
23
24    /// Type of object to base the restriction on.
25    pub fn with_type(mut self, type_field: ConsumerRestrictionType) -> Self {
26        self.type_field = Some(type_field);
27        self
28    }
29
30    /// List of objects to whitelist. Has a higher priority than allowed_by_methods.
31    pub fn with_whitelist(mut self, whitelist: Vec<String>) -> Self {
32        self.whitelist = Some(whitelist);
33        self
34    }
35
36    /// List of objects to blacklist. Has a higher priority than whitelist.
37    pub fn with_blacklist(mut self, blacklist: Vec<String>) -> Self {
38        self.blacklist = Some(blacklist);
39        self
40    }
41
42    /// HTTP status code returned when the request is rejected.
43    pub fn with_rejected_code(mut self, rejected_code: i32) -> Self {
44        self.rejected_code = Some(rejected_code);
45        self
46    }
47
48    /// Message returned when the request is rejected.
49    pub fn with_rejected_msg(mut self, rejected_msg: impl Into<String>) -> Self {
50        self.rejected_msg = Some(rejected_msg.into());
51        self
52    }
53
54    /// List of allowed configurations for Consumer settings, including a username of the Consumer and a list of allowed HTTP methods.
55    pub fn with_allowed_by_methods(mut self, allowed_by_methods: Vec<AllowedByMethods>) -> Self {
56        self.allowed_by_methods = Some(allowed_by_methods);
57        self
58    }
59
60    pub fn build(self) -> Result<ConsumerRestriction> {
61        Ok(ConsumerRestriction {
62            type_field: self.type_field,
63            whitelist: self.whitelist,
64            blacklist: self.blacklist,
65            rejected_code: self.rejected_code,
66            rejected_msg: self.rejected_msg,
67            allowed_by_methods: self.allowed_by_methods,
68        })
69    }
70}
71
72
73
74/// The consumer-restriction Plugin allows users to configure access restrictions on
75/// Consumer, Route, Service, or Consumer Group.
76#[serde_with::skip_serializing_none]
77#[derive(Validate, Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
78pub struct ConsumerRestriction {
79    #[serde(rename = "type")]
80    pub type_field: Option<ConsumerRestrictionType>,
81    pub whitelist: Option<Vec<String>>,
82    pub blacklist: Option<Vec<String>>,
83    #[validate(range(min = 200, max = 999))]
84    pub rejected_code: Option<i32>,
85    pub rejected_msg: Option<String>,
86    pub allowed_by_methods: Option<Vec<AllowedByMethods>>,
87}
88
89impl Plugin for ConsumerRestriction {}
90
91impl From<ConsumerRestriction> for ConsumerRestrictionBuilder {
92    fn from(consumer_restriction: ConsumerRestriction) -> Self {
93        ConsumerRestrictionBuilder {
94            type_field: consumer_restriction.type_field,
95            whitelist: consumer_restriction.whitelist,
96            blacklist: consumer_restriction.blacklist,
97            rejected_code: consumer_restriction.rejected_code,
98            rejected_msg: consumer_restriction.rejected_msg,
99            allowed_by_methods: consumer_restriction.allowed_by_methods,
100        }
101    }
102}
103
104/// List of allowed configurations for Consumer settings, including a username of the Consumer and a list of allowed HTTP methods
105/// `user` - A username for a Consumer.
106/// `methods` - A list of allowed HTTP methods for a Consumer.
107#[serde_with::skip_serializing_none]
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
109pub struct AllowedByMethods {
110    pub user: Option<String>,
111    pub methods: Option<Vec<AllowedMethodsType>>,
112}
113
114/// Type of user specified key to use
115/// `consumer_name` - Username of the Consumer to restrict access to a Route or a Service
116/// `consumer_group_id` - ID of the Consumer Group to restrict access to a Route or a Service
117/// `service_id` - ID of the Service to restrict access from a Consumer. Need to be used with an Authentication Plugin
118/// `route_id` - ID of the Route to restrict access from a Consumer
119#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, EnumString)]
120#[allow(non_camel_case_types)]
121#[strum(ascii_case_insensitive)]
122#[non_exhaustive]
123pub enum ConsumerRestrictionType {
124    consumer_name,
125    consumer_group_id,
126    service_id,
127    route_id,
128}
129
130/// List of allowed HTTP methods for a Consumer
131#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, Display, EnumString)]
132#[allow(non_camel_case_types)]
133#[strum(ascii_case_insensitive)]
134#[non_exhaustive]
135pub enum AllowedMethodsType {
136    GET,
137    POST,
138    PUT,
139    HEAD,
140    DELETE,
141    PATH,
142    OPTIONS,
143    CONNECT,
144    PURGE,
145    TRACE,
146}
147
148// region: tests
149#[cfg(test)]
150mod tests {
151    use serde_json::{to_string, to_string_pretty};
152    use super::*;
153    use tracing::{error, info};
154    use tracing_test::traced_test;
155    use crate::models::admin_upstream_requests::UpstreamType;
156    use crate::models::common::TypedItem;
157
158    #[traced_test]
159    #[tokio::test]
160    async fn test_parse_consumer_restriction_empty_response() {
161        let nodes = r#"{}"#;
162        let nodes: ConsumerRestriction = serde_json::from_str(nodes).unwrap();
163        assert_eq!(nodes.type_field, None);
164        assert_eq!(nodes.whitelist, None);
165        assert_eq!(nodes.blacklist, None);
166        assert_eq!(nodes.rejected_code, None);
167        assert_eq!(nodes.rejected_msg, None);
168        assert_eq!(nodes.allowed_by_methods, None);
169    }
170
171    #[traced_test]
172    #[tokio::test]
173    async fn test_parse_consumer_restriction_response() {
174        let nodes = r#"
175        {
176            "whitelist": [
177                "jack1"
178            ]
179        }"#;
180        let nodes: ConsumerRestriction = serde_json::from_str(nodes).unwrap();
181        assert_eq!(nodes.whitelist.unwrap(), vec!["jack1"]);
182    }
183}
184// endregion: tests