Skip to main content

junobuild_auth/openid/
impls.rs

1use crate::openid::jwt::types::cert::Jwks;
2use crate::openid::jwt::types::provider::JwtIssuers;
3use crate::openid::types::provider::{
4    OpenIdAutomationProvider, OpenIdCertificate, OpenIdDelegationProvider, OpenIdProvider,
5};
6use junobuild_shared::data::version::next_version;
7use junobuild_shared::ic::api::time;
8use junobuild_shared::types::state::{Version, Versioned};
9use std::fmt::{Display, Formatter, Result as FmtResult};
10
11impl OpenIdProvider {
12    pub fn jwks_url(&self) -> &'static str {
13        match self {
14            Self::Google => "https://www.googleapis.com/oauth2/v3/certs",
15            // Swap for local development with the Juno API:
16            // http://host.docker.internal:3000/v1/auth/certs
17            Self::GitHubAuth => "https://api.juno.build/v1/auth/certs",
18            Self::GitHubActions => "https://token.actions.githubusercontent.com/.well-known/jwks",
19        }
20    }
21
22    pub fn issuers(&self) -> &[&'static str] {
23        match self {
24            OpenIdProvider::Google => &["https://accounts.google.com", "accounts.google.com"],
25            OpenIdProvider::GitHubAuth => &["https://api.juno.build/auth/github"],
26            OpenIdProvider::GitHubActions => &["https://token.actions.githubusercontent.com"],
27        }
28    }
29}
30
31impl From<&OpenIdDelegationProvider> for OpenIdProvider {
32    fn from(delegation_provider: &OpenIdDelegationProvider) -> Self {
33        match delegation_provider {
34            OpenIdDelegationProvider::Google => OpenIdProvider::Google,
35            OpenIdDelegationProvider::GitHub => OpenIdProvider::GitHubAuth,
36        }
37    }
38}
39
40impl OpenIdDelegationProvider {
41    pub fn jwks_url(&self) -> &'static str {
42        match self {
43            Self::Google => OpenIdProvider::Google.jwks_url(),
44            Self::GitHub => OpenIdProvider::GitHubAuth.jwks_url(),
45        }
46    }
47
48    pub fn issuers(&self) -> &[&'static str] {
49        match self {
50            Self::Google => OpenIdProvider::Google.issuers(),
51            Self::GitHub => OpenIdProvider::GitHubAuth.issuers(),
52        }
53    }
54}
55
56impl JwtIssuers for OpenIdDelegationProvider {
57    fn issuers(&self) -> &[&'static str] {
58        self.issuers()
59    }
60}
61
62impl From<&OpenIdAutomationProvider> for OpenIdProvider {
63    fn from(automation_provider: &OpenIdAutomationProvider) -> Self {
64        match automation_provider {
65            OpenIdAutomationProvider::GitHub => OpenIdProvider::GitHubActions,
66        }
67    }
68}
69
70impl OpenIdAutomationProvider {
71    pub fn jwks_url(&self) -> &'static str {
72        match self {
73            Self::GitHub => OpenIdProvider::GitHubActions.jwks_url(),
74        }
75    }
76
77    pub fn issuers(&self) -> &[&'static str] {
78        match self {
79            Self::GitHub => OpenIdProvider::GitHubActions.issuers(),
80        }
81    }
82}
83
84impl JwtIssuers for OpenIdAutomationProvider {
85    fn issuers(&self) -> &[&'static str] {
86        self.issuers()
87    }
88}
89
90impl Display for OpenIdAutomationProvider {
91    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
92        match self {
93            OpenIdAutomationProvider::GitHub => write!(f, "GitHub"),
94        }
95    }
96}
97
98impl Versioned for OpenIdCertificate {
99    fn version(&self) -> Option<Version> {
100        self.version
101    }
102}
103
104impl OpenIdCertificate {
105    fn get_next_version(current_certificate: &Option<OpenIdCertificate>) -> Version {
106        next_version(current_certificate)
107    }
108
109    pub fn init(jwks: &Jwks) -> Self {
110        let now = time();
111
112        let version = Self::get_next_version(&None);
113
114        Self {
115            jwks: jwks.clone(),
116            created_at: now,
117            updated_at: now,
118            version: Some(version),
119        }
120    }
121
122    pub fn update(current_certificate: &OpenIdCertificate, jwks: &Jwks) -> Self {
123        let now = time();
124
125        let version = Self::get_next_version(&Some(current_certificate.clone()));
126
127        Self {
128            jwks: jwks.clone(),
129            updated_at: now,
130            version: Some(version),
131            ..current_certificate.clone()
132        }
133    }
134}
135
136impl Display for OpenIdProvider {
137    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
138        match self {
139            OpenIdProvider::Google => write!(f, "Google"),
140            OpenIdProvider::GitHubAuth => write!(f, "GitHub"),
141            OpenIdProvider::GitHubActions => write!(f, "GitHub Actions"),
142        }
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_openid_provider_jwks_urls() {
152        assert_eq!(
153            OpenIdProvider::Google.jwks_url(),
154            "https://www.googleapis.com/oauth2/v3/certs"
155        );
156        assert_eq!(
157            OpenIdProvider::GitHubAuth.jwks_url(),
158            "https://api.juno.build/v1/auth/certs"
159        );
160        assert_eq!(
161            OpenIdProvider::GitHubActions.jwks_url(),
162            "https://token.actions.githubusercontent.com/.well-known/jwks"
163        );
164    }
165
166    #[test]
167    fn test_openid_provider_issuers() {
168        assert_eq!(
169            OpenIdProvider::Google.issuers(),
170            &["https://accounts.google.com", "accounts.google.com"]
171        );
172        assert_eq!(
173            OpenIdProvider::GitHubAuth.issuers(),
174            &["https://api.juno.build/auth/github"]
175        );
176        assert_eq!(
177            OpenIdProvider::GitHubActions.issuers(),
178            &["https://token.actions.githubusercontent.com"]
179        );
180    }
181
182    #[test]
183    fn test_delegation_provider_to_openid_provider() {
184        assert_eq!(
185            OpenIdProvider::from(&OpenIdDelegationProvider::Google),
186            OpenIdProvider::Google
187        );
188        assert_eq!(
189            OpenIdProvider::from(&OpenIdDelegationProvider::GitHub),
190            OpenIdProvider::GitHubAuth
191        );
192    }
193
194    #[test]
195    fn test_delegation_provider_jwks_urls() {
196        assert_eq!(
197            OpenIdDelegationProvider::Google.jwks_url(),
198            "https://www.googleapis.com/oauth2/v3/certs"
199        );
200        assert_eq!(
201            OpenIdDelegationProvider::GitHub.jwks_url(),
202            "https://api.juno.build/v1/auth/certs"
203        );
204    }
205
206    #[test]
207    fn test_delegation_provider_issuers() {
208        assert_eq!(
209            OpenIdDelegationProvider::Google.issuers(),
210            &["https://accounts.google.com", "accounts.google.com"]
211        );
212        assert_eq!(
213            OpenIdDelegationProvider::GitHub.issuers(),
214            &["https://api.juno.build/auth/github"]
215        );
216    }
217
218    #[test]
219    fn test_automation_provider_to_openid_provider() {
220        assert_eq!(
221            OpenIdProvider::from(&OpenIdAutomationProvider::GitHub),
222            OpenIdProvider::GitHubActions
223        );
224    }
225
226    #[test]
227    fn test_automation_provider_jwks_urls() {
228        assert_eq!(
229            OpenIdAutomationProvider::GitHub.jwks_url(),
230            "https://token.actions.githubusercontent.com/.well-known/jwks"
231        );
232    }
233
234    #[test]
235    fn test_automation_provider_issuers() {
236        assert_eq!(
237            OpenIdAutomationProvider::GitHub.issuers(),
238            &["https://token.actions.githubusercontent.com"]
239        );
240    }
241
242    #[test]
243    fn test_openid_certificate_init() {
244        let jwks = Jwks { keys: vec![] };
245        let cert = OpenIdCertificate::init(&jwks);
246
247        assert_eq!(cert.version, Some(1));
248        assert_eq!(cert.created_at, cert.updated_at);
249    }
250
251    #[test]
252    fn test_openid_certificate_update() {
253        let jwks = Jwks { keys: vec![] };
254        let initial = OpenIdCertificate::init(&jwks);
255
256        let new_jwks = Jwks { keys: vec![] };
257        let updated = OpenIdCertificate::update(&initial, &new_jwks);
258
259        assert_eq!(updated.version, Some(2));
260        assert_eq!(updated.created_at, initial.created_at);
261        assert!(updated.updated_at >= initial.updated_at);
262    }
263
264    #[test]
265    fn test_openid_provider_display() {
266        assert_eq!(format!("{}", OpenIdProvider::Google), "Google");
267        assert_eq!(format!("{}", OpenIdProvider::GitHubAuth), "GitHub");
268        assert_eq!(
269            format!("{}", OpenIdProvider::GitHubActions),
270            "GitHub Actions"
271        );
272    }
273}