kanidm_cli/
oauth2.rs

1use crate::common::OpType;
2use crate::Oauth2ClaimMapJoin;
3use crate::{handle_client_error, Oauth2Opt, OutputMode};
4use anyhow::{Context, Error};
5use kanidm_proto::internal::{ImageValue, Oauth2ClaimMapJoin as ProtoOauth2ClaimMapJoin};
6use std::fs::read;
7use std::process::exit;
8
9impl Oauth2Opt {
10    pub fn debug(&self) -> bool {
11        match self {
12            Oauth2Opt::List(copt) => copt.debug,
13            Oauth2Opt::Get(nopt) => nopt.copt.debug,
14            Oauth2Opt::UpdateScopeMap(cbopt) => cbopt.nopt.copt.debug,
15            Oauth2Opt::DeleteScopeMap(cbopt) => cbopt.nopt.copt.debug,
16            Oauth2Opt::UpdateSupScopeMap(cbopt) => cbopt.nopt.copt.debug,
17            Oauth2Opt::DeleteSupScopeMap(cbopt) => cbopt.nopt.copt.debug,
18            Oauth2Opt::ResetSecrets(cbopt) => cbopt.copt.debug,
19            // Should this be renamed to show client id? client secrets?
20            Oauth2Opt::ShowBasicSecret(nopt) => nopt.copt.debug,
21            Oauth2Opt::Delete(nopt) => nopt.copt.debug,
22            Oauth2Opt::SetDisplayname(cbopt) => cbopt.nopt.copt.debug,
23            Oauth2Opt::SetName { nopt, .. } => nopt.copt.debug,
24            Oauth2Opt::SetLandingUrl { nopt, .. } => nopt.copt.debug,
25            Oauth2Opt::SetImage { nopt, .. } => nopt.copt.debug,
26            Oauth2Opt::RemoveImage(nopt) => nopt.copt.debug,
27            Oauth2Opt::EnablePkce(nopt) => nopt.copt.debug,
28            Oauth2Opt::DisablePkce(nopt) => nopt.copt.debug,
29            Oauth2Opt::EnableLegacyCrypto(nopt) => nopt.copt.debug,
30            Oauth2Opt::DisableLegacyCrypto(nopt) => nopt.copt.debug,
31            Oauth2Opt::PreferShortUsername(nopt) => nopt.copt.debug,
32            Oauth2Opt::PreferSPNUsername(nopt) => nopt.copt.debug,
33
34            #[cfg(feature = "dev-oauth2-device-flow")]
35            Oauth2Opt::DeviceFlowDisable(nopt) => nopt.copt.debug,
36
37            #[cfg(feature = "dev-oauth2-device-flow")]
38            Oauth2Opt::DeviceFlowEnable(nopt) => nopt.copt.debug,
39            Oauth2Opt::CreateBasic { copt, .. }
40            | Oauth2Opt::CreatePublic { copt, .. }
41            | Oauth2Opt::UpdateClaimMap { copt, .. }
42            | Oauth2Opt::UpdateClaimMapJoin { copt, .. }
43            | Oauth2Opt::DeleteClaimMap { copt, .. }
44            | Oauth2Opt::EnablePublicLocalhost { copt, .. }
45            | Oauth2Opt::DisablePublicLocalhost { copt, .. }
46            | Oauth2Opt::EnableStrictRedirectUri { copt, .. }
47            | Oauth2Opt::DisableStrictRedirectUri { copt, .. }
48            | Oauth2Opt::AddOrigin { copt, .. }
49            | Oauth2Opt::RemoveOrigin { copt, .. }
50            | Oauth2Opt::RotateCryptographicKeys { copt, .. }
51            | Oauth2Opt::RevokeCryptographicKey { copt, .. } => copt.debug,
52        }
53    }
54
55    pub async fn exec(&self) {
56        match self {
57            #[cfg(feature = "dev-oauth2-device-flow")]
58            Oauth2Opt::DeviceFlowDisable(nopt) => {
59                // TODO: finish the CLI bits for DeviceFlowDisable
60                let client = nopt.copt.to_client(OpType::Write).await;
61                match client
62                    .idm_oauth2_client_device_flow_update(&nopt.name, true)
63                    .await
64                {
65                    Ok(_) => println!("Success"),
66                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
67                }
68            }
69            #[cfg(feature = "dev-oauth2-device-flow")]
70            Oauth2Opt::DeviceFlowEnable(nopt) => {
71                // TODO: finish the CLI bits for DeviceFlowEnable
72                let client = nopt.copt.to_client(OpType::Write).await;
73                match client
74                    .idm_oauth2_client_device_flow_update(&nopt.name, true)
75                    .await
76                {
77                    Ok(_) => println!("Success"),
78                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
79                }
80            }
81            Oauth2Opt::List(copt) => {
82                let client = copt.to_client(OpType::Read).await;
83                match client.idm_oauth2_rs_list().await {
84                    Ok(r) => match copt.output_mode {
85                        OutputMode::Json => {
86                            let r_attrs: Vec<_> = r.iter().map(|entry| &entry.attrs).collect();
87                            println!(
88                                "{}",
89                                serde_json::to_string(&r_attrs).expect("Failed to serialise json")
90                            );
91                        }
92                        OutputMode::Text => r.iter().for_each(|ent| println!("{}", ent)),
93                    },
94                    Err(e) => handle_client_error(e, copt.output_mode),
95                }
96            }
97            Oauth2Opt::Get(nopt) => {
98                let client = nopt.copt.to_client(OpType::Read).await;
99                match client.idm_oauth2_rs_get(nopt.name.as_str()).await {
100                    Ok(Some(e)) => println!("{}", e),
101                    Ok(None) => println!("No matching entries"),
102                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
103                }
104            }
105            Oauth2Opt::CreateBasic {
106                name,
107                displayname,
108                origin,
109                copt,
110            } => {
111                let client = copt.to_client(OpType::Write).await;
112                match client
113                    .idm_oauth2_rs_basic_create(
114                        name.as_str(),
115                        displayname.as_str(),
116                        origin.as_str(),
117                    )
118                    .await
119                {
120                    Ok(_) => println!("Success"),
121                    Err(e) => handle_client_error(e, copt.output_mode),
122                }
123            }
124            Oauth2Opt::CreatePublic {
125                name,
126                displayname,
127                origin,
128                copt,
129            } => {
130                let client = copt.to_client(OpType::Write).await;
131                match client
132                    .idm_oauth2_rs_public_create(
133                        name.as_str(),
134                        displayname.as_str(),
135                        origin.as_str(),
136                    )
137                    .await
138                {
139                    Ok(_) => println!("Success"),
140                    Err(e) => handle_client_error(e, copt.output_mode),
141                }
142            }
143            Oauth2Opt::UpdateScopeMap(cbopt) => {
144                let client = cbopt.nopt.copt.to_client(OpType::Write).await;
145                match client
146                    .idm_oauth2_rs_update_scope_map(
147                        cbopt.nopt.name.as_str(),
148                        cbopt.group.as_str(),
149                        cbopt.scopes.iter().map(|s| s.as_str()).collect(),
150                    )
151                    .await
152                {
153                    Ok(_) => println!("Success"),
154                    Err(e) => handle_client_error(e, cbopt.nopt.copt.output_mode),
155                }
156            }
157            Oauth2Opt::DeleteScopeMap(cbopt) => {
158                let client = cbopt.nopt.copt.to_client(OpType::Write).await;
159                match client
160                    .idm_oauth2_rs_delete_scope_map(cbopt.nopt.name.as_str(), cbopt.group.as_str())
161                    .await
162                {
163                    Ok(_) => println!("Success"),
164                    Err(e) => handle_client_error(e, cbopt.nopt.copt.output_mode),
165                }
166            }
167            Oauth2Opt::UpdateSupScopeMap(cbopt) => {
168                let client = cbopt.nopt.copt.to_client(OpType::Write).await;
169                match client
170                    .idm_oauth2_rs_update_sup_scope_map(
171                        cbopt.nopt.name.as_str(),
172                        cbopt.group.as_str(),
173                        cbopt.scopes.iter().map(|s| s.as_str()).collect(),
174                    )
175                    .await
176                {
177                    Ok(_) => println!("Success"),
178                    Err(e) => {
179                        error!("Error -> {:?}", e);
180                        exit(1)
181                    }
182                }
183            }
184            Oauth2Opt::DeleteSupScopeMap(cbopt) => {
185                let client = cbopt.nopt.copt.to_client(OpType::Write).await;
186                match client
187                    .idm_oauth2_rs_delete_sup_scope_map(
188                        cbopt.nopt.name.as_str(),
189                        cbopt.group.as_str(),
190                    )
191                    .await
192                {
193                    Ok(_) => println!("Success"),
194                    Err(e) => handle_client_error(e, cbopt.nopt.copt.output_mode),
195                }
196            }
197            Oauth2Opt::ResetSecrets(cbopt) => {
198                let client = cbopt.copt.to_client(OpType::Write).await;
199                match client
200                    .idm_oauth2_rs_update(cbopt.name.as_str(), None, None, None, true)
201                    .await
202                {
203                    Ok(_) => println!("Success"),
204                    Err(e) => handle_client_error(e, cbopt.copt.output_mode),
205                }
206            }
207            Oauth2Opt::ShowBasicSecret(nopt) => {
208                let client = nopt.copt.to_client(OpType::Read).await;
209                match client
210                    .idm_oauth2_rs_get_basic_secret(nopt.name.as_str())
211                    .await
212                {
213                    Ok(Some(secret)) => {
214                        match nopt.copt.output_mode {
215                            OutputMode::Text => println!("{}", secret),
216                            OutputMode::Json => println!("{{\"secret\": \"{}\"}}", secret),
217                        }
218                        eprintln!("Success");
219                    }
220                    Ok(None) => {
221                        eprintln!("No secret configured");
222                    }
223                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
224                }
225            }
226            Oauth2Opt::Delete(nopt) => {
227                let client = nopt.copt.to_client(OpType::Write).await;
228                match client.idm_oauth2_rs_delete(nopt.name.as_str()).await {
229                    Ok(_) => println!("Success"),
230                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
231                }
232            }
233            Oauth2Opt::SetDisplayname(cbopt) => {
234                let client = cbopt.nopt.copt.to_client(OpType::Write).await;
235                match client
236                    .idm_oauth2_rs_update(
237                        cbopt.nopt.name.as_str(),
238                        None,
239                        Some(cbopt.displayname.as_str()),
240                        None,
241                        false,
242                    )
243                    .await
244                {
245                    Ok(_) => println!("Success"),
246                    Err(e) => handle_client_error(e, cbopt.nopt.copt.output_mode),
247                }
248            }
249            Oauth2Opt::SetName { nopt, name } => {
250                let client = nopt.copt.to_client(OpType::Write).await;
251                match client
252                    .idm_oauth2_rs_update(
253                        nopt.name.as_str(),
254                        Some(name.as_str()),
255                        None,
256                        None,
257                        false,
258                    )
259                    .await
260                {
261                    Ok(_) => println!("Success"),
262                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
263                }
264            }
265            Oauth2Opt::SetLandingUrl { nopt, url } => {
266                let client = nopt.copt.to_client(OpType::Write).await;
267                match client
268                    .idm_oauth2_rs_update(nopt.name.as_str(), None, None, Some(url.as_str()), false)
269                    .await
270                {
271                    Ok(_) => println!("Success"),
272                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
273                }
274            }
275            Oauth2Opt::SetImage {
276                nopt,
277                path,
278                image_type,
279            } => {
280                let img_res: Result<ImageValue, Error> = (move || {
281                    let file_name = path
282                        .file_name()
283                        .context("Please pass a file")?
284                        .to_str()
285                        .context("Path contains non utf-8")?
286                        .to_string();
287
288                    let image_type = match image_type {
289                        Some(val) => val.clone(),
290                        None => {
291                            path
292                                .extension().context("Path has no extension so we can't infer the imageType, or you could pass the optional imageType argument yourself.")?
293                                .to_str().context("Path contains invalid utf-8")?
294                                .try_into()
295                                .map_err(Error::msg)?
296                        }
297                    };
298
299                    let read_res = read(path);
300                    match read_res {
301                        Ok(data) => Ok(ImageValue::new(file_name, image_type, data)),
302                        Err(err) => {
303                            if nopt.copt.debug {
304                                eprintln!(
305                                    "{}",
306                                    kanidm_lib_file_permissions::diagnose_path(path.as_ref())
307                                );
308                            }
309                            Err(err).context(format!("Failed to read file at '{}'", path.display()))
310                        }
311                    }
312                })();
313
314                let img = match img_res {
315                    Ok(img) => img,
316                    Err(err) => {
317                        eprintln!("{:?}", err);
318                        return;
319                    }
320                };
321
322                let client = nopt.copt.to_client(OpType::Write).await;
323
324                match client
325                    .idm_oauth2_rs_update_image(nopt.name.as_str(), img)
326                    .await
327                {
328                    Ok(_) => println!("Success"),
329                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
330                }
331            }
332            Oauth2Opt::RemoveImage(nopt) => {
333                let client = nopt.copt.to_client(OpType::Write).await;
334
335                match client.idm_oauth2_rs_delete_image(nopt.name.as_str()).await {
336                    Ok(_) => println!("Success"),
337                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
338                }
339            }
340            Oauth2Opt::EnablePkce(nopt) => {
341                let client = nopt.copt.to_client(OpType::Write).await;
342                match client.idm_oauth2_rs_enable_pkce(nopt.name.as_str()).await {
343                    Ok(_) => println!("Success"),
344                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
345                }
346            }
347            Oauth2Opt::DisablePkce(nopt) => {
348                let client = nopt.copt.to_client(OpType::Write).await;
349                match client.idm_oauth2_rs_disable_pkce(nopt.name.as_str()).await {
350                    Ok(_) => println!("Success"),
351                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
352                }
353            }
354            Oauth2Opt::EnableLegacyCrypto(nopt) => {
355                let client = nopt.copt.to_client(OpType::Write).await;
356                match client
357                    .idm_oauth2_rs_enable_legacy_crypto(nopt.name.as_str())
358                    .await
359                {
360                    Ok(_) => println!("Success"),
361                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
362                }
363            }
364            Oauth2Opt::DisableLegacyCrypto(nopt) => {
365                let client = nopt.copt.to_client(OpType::Write).await;
366                match client
367                    .idm_oauth2_rs_disable_legacy_crypto(nopt.name.as_str())
368                    .await
369                {
370                    Ok(_) => println!("Success"),
371                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
372                }
373            }
374            Oauth2Opt::PreferShortUsername(nopt) => {
375                let client = nopt.copt.to_client(OpType::Write).await;
376                match client
377                    .idm_oauth2_rs_prefer_short_username(nopt.name.as_str())
378                    .await
379                {
380                    Ok(_) => println!("Success"),
381                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
382                }
383            }
384            Oauth2Opt::PreferSPNUsername(nopt) => {
385                let client = nopt.copt.to_client(OpType::Write).await;
386                match client
387                    .idm_oauth2_rs_prefer_spn_username(nopt.name.as_str())
388                    .await
389                {
390                    Ok(_) => println!("Success"),
391                    Err(e) => handle_client_error(e, nopt.copt.output_mode),
392                }
393            }
394
395            Oauth2Opt::AddOrigin { name, origin, copt } => {
396                let client = copt.to_client(OpType::Write).await;
397                match client.idm_oauth2_client_add_origin(name, origin).await {
398                    Ok(_) => println!("Success"),
399                    Err(e) => handle_client_error(e, copt.output_mode),
400                }
401            }
402            Oauth2Opt::RemoveOrigin { name, origin, copt } => {
403                let client = copt.to_client(OpType::Write).await;
404                match client.idm_oauth2_client_remove_origin(name, origin).await {
405                    Ok(_) => println!("Success"),
406                    Err(e) => handle_client_error(e, copt.output_mode),
407                }
408            }
409            Oauth2Opt::UpdateClaimMap {
410                copt,
411                name,
412                group,
413                claim_name,
414                values,
415            } => {
416                let client = copt.to_client(OpType::Write).await;
417                match client
418                    .idm_oauth2_rs_update_claim_map(
419                        name.as_str(),
420                        claim_name.as_str(),
421                        group.as_str(),
422                        values,
423                    )
424                    .await
425                {
426                    Ok(_) => println!("Success"),
427                    Err(e) => handle_client_error(e, copt.output_mode),
428                }
429            }
430            Oauth2Opt::UpdateClaimMapJoin {
431                copt,
432                name,
433                claim_name,
434                join,
435            } => {
436                let client = copt.to_client(OpType::Write).await;
437
438                let join = match join {
439                    Oauth2ClaimMapJoin::Csv => ProtoOauth2ClaimMapJoin::Csv,
440                    Oauth2ClaimMapJoin::Ssv => ProtoOauth2ClaimMapJoin::Ssv,
441                    Oauth2ClaimMapJoin::Array => ProtoOauth2ClaimMapJoin::Array,
442                };
443
444                match client
445                    .idm_oauth2_rs_update_claim_map_join(name.as_str(), claim_name.as_str(), join)
446                    .await
447                {
448                    Ok(_) => println!("Success"),
449                    Err(e) => handle_client_error(e, copt.output_mode),
450                }
451            }
452            Oauth2Opt::DeleteClaimMap {
453                copt,
454                name,
455                claim_name,
456                group,
457            } => {
458                let client = copt.to_client(OpType::Write).await;
459                match client
460                    .idm_oauth2_rs_delete_claim_map(
461                        name.as_str(),
462                        claim_name.as_str(),
463                        group.as_str(),
464                    )
465                    .await
466                {
467                    Ok(_) => println!("Success"),
468                    Err(e) => handle_client_error(e, copt.output_mode),
469                }
470            }
471
472            Oauth2Opt::EnablePublicLocalhost { copt, name } => {
473                let client = copt.to_client(OpType::Write).await;
474                match client
475                    .idm_oauth2_rs_enable_public_localhost_redirect(name.as_str())
476                    .await
477                {
478                    Ok(_) => println!("Success"),
479                    Err(e) => handle_client_error(e, copt.output_mode),
480                }
481            }
482
483            Oauth2Opt::DisablePublicLocalhost { copt, name } => {
484                let client = copt.to_client(OpType::Write).await;
485                match client
486                    .idm_oauth2_rs_disable_public_localhost_redirect(name.as_str())
487                    .await
488                {
489                    Ok(_) => println!("Success"),
490                    Err(e) => handle_client_error(e, copt.output_mode),
491                }
492            }
493            Oauth2Opt::EnableStrictRedirectUri { copt, name } => {
494                let client = copt.to_client(OpType::Write).await;
495                match client
496                    .idm_oauth2_rs_enable_strict_redirect_uri(name.as_str())
497                    .await
498                {
499                    Ok(_) => println!("Success"),
500                    Err(e) => handle_client_error(e, copt.output_mode),
501                }
502            }
503
504            Oauth2Opt::DisableStrictRedirectUri { copt, name } => {
505                let client = copt.to_client(OpType::Write).await;
506                match client
507                    .idm_oauth2_rs_disable_strict_redirect_uri(name.as_str())
508                    .await
509                {
510                    Ok(_) => println!("Success"),
511                    Err(e) => handle_client_error(e, copt.output_mode),
512                }
513            }
514            Oauth2Opt::RotateCryptographicKeys {
515                copt,
516                name,
517                rotate_at,
518            } => {
519                let client = copt.to_client(OpType::Write).await;
520                match client
521                    .idm_oauth2_rs_rotate_keys(name.as_str(), *rotate_at)
522                    .await
523                {
524                    Ok(_) => println!("Success"),
525                    Err(e) => handle_client_error(e, copt.output_mode),
526                }
527            }
528            Oauth2Opt::RevokeCryptographicKey { copt, name, key_id } => {
529                let client = copt.to_client(OpType::Write).await;
530                match client
531                    .idm_oauth2_rs_revoke_key(name.as_str(), key_id.as_str())
532                    .await
533                {
534                    Ok(_) => println!("Success"),
535                    Err(e) => handle_client_error(e, copt.output_mode),
536                }
537            }
538        }
539    }
540}