kanidm_cli/
oauth2.rs

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