Skip to main content

alibi_plugins/oauth_provider/
rate_limit.rs

1//! Protocol quotas registered with the application's canonical rate limiter.
2use alibi_core::{EndpointRateLimit, PluginRateLimit};
3
4/// A provider rule can inherit its endpoint default, replace it, or be omitted.
5/// `Disabled` omits only the plugin rule: global/application policy still applies.
6#[derive(Debug, Clone, Default)]
7pub enum OAuthEndpointRateLimit {
8    #[default]
9    Default,
10    Disabled,
11    /// Both values are supplied, including zero, as in the published provider API.
12    Limit(EndpointRateLimit),
13}
14
15/// OAuth protocol endpoint policies, in seconds and requests per client/path.
16/// Rules are effective only when application rate limiting is enabled; its
17/// storage and ordered custom rules remain authoritative.
18#[derive(Debug, Clone, Default)]
19pub struct OAuthProviderRateLimits {
20    /// Defaults to 20 requests per 60 seconds.
21    pub token: OAuthEndpointRateLimit,
22    /// Defaults to 30 requests per 60 seconds.
23    pub authorize: OAuthEndpointRateLimit,
24    /// Defaults to 100 requests per 60 seconds.
25    pub introspect: OAuthEndpointRateLimit,
26    /// Defaults to 30 requests per 60 seconds.
27    pub revoke: OAuthEndpointRateLimit,
28    /// Defaults to 5 requests per 60 seconds.
29    pub register: OAuthEndpointRateLimit,
30    /// Defaults to 60 requests per 60 seconds, shared by GET and POST.
31    pub userinfo: OAuthEndpointRateLimit,
32}
33
34type RoutePolicy<'a> = (fn(&str) -> bool, &'a OAuthEndpointRateLimit, f64);
35
36impl OAuthProviderRateLimits {
37    pub(super) fn rules(&self) -> Vec<PluginRateLimit> {
38        let routes: [RoutePolicy<'_>; 6] = [
39            (|path| path == "/oauth2/token", &self.token, 20.0),
40            (|path| path == "/oauth2/authorize", &self.authorize, 30.0),
41            (|path| path == "/oauth2/introspect", &self.introspect, 100.0),
42            (|path| path == "/oauth2/revoke", &self.revoke, 30.0),
43            (|path| path == "/oauth2/register", &self.register, 5.0),
44            (|path| path == "/oauth2/userinfo", &self.userinfo, 60.0),
45        ];
46        routes
47            .into_iter()
48            .filter_map(|(matches, policy, max)| {
49                let limit = match policy {
50                    OAuthEndpointRateLimit::Disabled => return None,
51                    OAuthEndpointRateLimit::Default => EndpointRateLimit {
52                        window_seconds: 60.0,
53                        max_requests: max,
54                    },
55                    OAuthEndpointRateLimit::Limit(limit) => limit.clone(),
56                };
57                Some(PluginRateLimit { matches, limit })
58            })
59            .collect()
60    }
61}