1use clap::{builder::PossibleValue, Args, Subcommand, ValueEnum};
2use kanidm_proto::internal::ImageType;
3use std::fmt;
4
5#[derive(Debug, Args)]
6pub struct Named {
7 pub name: String,
8 #[clap(flatten)]
9 pub copt: CommonOpt,
10}
11
12#[derive(Debug, Args)]
13pub struct DebugOpt {
14 #[clap(short, long, env = "KANIDM_DEBUG")]
16 pub debug: bool,
17}
18
19#[derive(Debug, Clone, Copy)]
20pub enum OutputMode {
22 Text,
23 Json,
24}
25
26impl std::str::FromStr for OutputMode {
27 type Err = String;
28 fn from_str(s: &str) -> Result<OutputMode, std::string::String> {
29 match s.to_lowercase().as_str() {
30 "text" => Ok(OutputMode::Text),
31 "json" => Ok(OutputMode::Json),
32 _ => Ok(OutputMode::Text),
33 }
34 }
35}
36
37impl OutputMode {
38 pub fn print_message<T>(self, input: T)
39 where
40 T: serde::Serialize + fmt::Debug + fmt::Display,
41 {
42 match self {
43 OutputMode::Json => {
44 println!(
45 "{}",
46 serde_json::to_string(&input).unwrap_or(format!("{:?}", input))
47 );
48 }
49 OutputMode::Text => {
50 println!("{}", input);
51 }
52 }
53 }
54}
55
56#[derive(Debug, Args, Clone)]
57pub struct CommonOpt {
58 #[clap(short, long, env = "KANIDM_DEBUG")]
60 pub debug: bool,
61 #[clap(short = 'I', long = "instance", env = "KANIDM_INSTANCE",
63 value_parser = clap::builder::NonEmptyStringValueParser::new())]
64 pub instance: Option<String>,
65 #[clap(short = 'H', long = "url", env = "KANIDM_URL",
67 value_parser = clap::builder::NonEmptyStringValueParser::new())]
68 pub addr: Option<String>,
69 #[clap(
71 short = 'D',
72 long = "name",
73 env = "KANIDM_NAME",
74 value_parser = clap::builder::NonEmptyStringValueParser::new()
75 )]
76 pub username: Option<String>,
77 #[clap(value_parser, short = 'C', long = "ca", env = "KANIDM_CA_PATH")]
79 pub ca_path: Option<PathBuf>,
80 #[clap(short, long = "output", env = "KANIDM_OUTPUT", default_value = "text")]
82 output_mode: OutputMode,
83 #[clap(
85 long = "skip-hostname-verification",
86 env = "KANIDM_SKIP_HOSTNAME_VERIFICATION",
87 default_value_t = false
88 )]
89 skip_hostname_verification: bool,
90 #[clap(short, long, env = "KANIDM_TOKEN_CACHE_PATH", hide = true, default_value = None,
92 value_parser = clap::builder::NonEmptyStringValueParser::new())]
93 token_cache_path: Option<String>,
94}
95
96#[derive(Debug, Args)]
97pub struct GroupNamedMembers {
98 name: String,
99 #[clap(required = true, num_args(1..))]
100 members: Vec<String>,
101 #[clap(flatten)]
102 copt: CommonOpt,
103}
104
105#[derive(Debug, Args)]
106pub struct GroupPosixOpt {
107 name: String,
108 #[clap(long)]
109 gidnumber: Option<u32>,
110 #[clap(flatten)]
111 copt: CommonOpt,
112}
113
114#[derive(Debug, Subcommand)]
115pub enum GroupPosix {
116 #[clap(name = "show")]
118 Show(Named),
119 #[clap(name = "set")]
121 Set(GroupPosixOpt),
122 #[clap(name = "reset-gidnumber")]
124 ResetGidnumber {
125 group_id: String,
126 #[clap(flatten)]
127 copt: CommonOpt,
128 },
129}
130
131#[derive(Debug, Clone, Copy, Eq, PartialEq)]
132pub enum AccountPolicyCredentialType {
133 Any,
134 Mfa,
135 Passkey,
136 AttestedPasskey,
137}
138
139impl AccountPolicyCredentialType {
140 pub fn as_str(&self) -> &'static str {
141 match self {
142 Self::Any => "any",
143 Self::Mfa => "mfa",
144 Self::Passkey => "passkey",
145 Self::AttestedPasskey => "attested_passkey",
146 }
147 }
148}
149
150impl ValueEnum for AccountPolicyCredentialType {
151 fn value_variants<'a>() -> &'a [Self] {
152 &[Self::Any, Self::Mfa, Self::Passkey, Self::AttestedPasskey]
153 }
154
155 fn to_possible_value(&self) -> Option<PossibleValue> {
156 Some(match self {
157 Self::Any => PossibleValue::new("any"),
158 Self::Mfa => PossibleValue::new("mfa"),
159 Self::Passkey => PossibleValue::new("passkey"),
160 Self::AttestedPasskey => PossibleValue::new("attested_passkey"),
161 })
162 }
163}
164
165#[derive(Debug, Subcommand)]
166pub enum GroupAccountPolicyOpt {
167 #[clap(name = "enable")]
169 Enable {
170 name: String,
171 #[clap(flatten)]
172 copt: CommonOpt,
173 },
174 #[clap(name = "auth-expiry")]
176 AuthSessionExpiry {
177 name: String,
178 expiry: u32,
179 #[clap(flatten)]
180 copt: CommonOpt,
181 },
182 #[clap(name = "credential-type-minimum")]
185 CredentialTypeMinimum {
186 name: String,
187 #[clap(value_enum)]
188 value: AccountPolicyCredentialType,
189 #[clap(flatten)]
190 copt: CommonOpt,
191 },
192 #[clap(name = "password-minimum-length")]
194 PasswordMinimumLength {
195 name: String,
196 length: u32,
197 #[clap(flatten)]
198 copt: CommonOpt,
199 },
200
201
202 #[clap(name = "privilege-expiry")]
204 PrivilegedSessionExpiry {
205 name: String,
206 expiry: u32,
207 #[clap(flatten)]
208 copt: CommonOpt,
209 },
210
211
212 #[clap(name = "webauthn-attestation-ca-list")]
217 WebauthnAttestationCaList {
218 name: String,
219 attestation_ca_list_json_file: PathBuf,
220 #[clap(flatten)]
221 copt: CommonOpt,
222 },
223
224 #[clap(name = "limit-search-max-results")]
227 LimitSearchMaxResults {
228 name: String,
229 maximum: u32,
230 #[clap(flatten)]
231 copt: CommonOpt,
232 },
233 #[clap(name = "limit-search-max-filter-test")]
237 LimitSearchMaxFilterTest {
238 name: String,
239 maximum: u32,
240 #[clap(flatten)]
241 copt: CommonOpt,
242 },
243 #[clap(name = "allow-primary-cred-fallback")]
246 AllowPrimaryCredFallback {
247 name: String,
248 #[clap(name = "allow", action = clap::ArgAction::Set)]
249 allow: bool,
250 #[clap(flatten)]
251 copt: CommonOpt,
252 },
253
254 #[clap(name = "reset-auth-expiry")]
256 ResetAuthSessionExpiry {
257 name: String,
258 #[clap(flatten)]
259 copt: CommonOpt,
260 },
261 #[clap(name = "reset-password-minimum-length")]
263 ResetPasswordMinimumLength {
264 name: String,
265 #[clap(flatten)]
266 copt: CommonOpt,
267 },
268 #[clap(name = "reset-privilege-expiry")]
270 ResetPrivilegedSessionExpiry {
271 name: String,
272 #[clap(flatten)]
273 copt: CommonOpt,
274 },
275 #[clap(name = "reset-webauthn-attestation-ca-list")]
278 ResetWebauthnAttestationCaList {
279 name: String,
280 #[clap(flatten)]
281 copt: CommonOpt,
282 },
283 #[clap(name = "reset-limit-search-max-results")]
285 ResetLimitSearchMaxResults {
286 name: String,
287 #[clap(flatten)]
288 copt: CommonOpt,
289 },
290 #[clap(name = "reset-limit-search-max-filter-test")]
292 ResetLimitSearchMaxFilterTest {
293 name: String,
294 #[clap(flatten)]
295 copt: CommonOpt,
296 },
297
298}
299
300#[derive(Debug, Subcommand)]
301pub enum GroupOpt {
302 #[clap(name = "list")]
304 List(CommonOpt),
305 #[clap(name = "get")]
307 Get(Named),
308 #[clap(name = "search")]
310 Search {
311 name: String,
313 #[clap(flatten)]
314 copt: CommonOpt,
315 },
316 #[clap(name = "create")]
318 Create {
319 name: String,
321 #[clap(value_parser = clap::builder::NonEmptyStringValueParser::new())]
323 entry_managed_by: Option<String>,
324 #[clap(flatten)]
325 copt: CommonOpt,
326 },
327 #[clap(name = "delete")]
329 Delete(Named),
330 #[clap(name = "list-members")]
332 ListMembers(Named),
333 #[clap(name = "set-members")]
336 SetMembers(GroupNamedMembers),
337 #[clap(name = "set-mail")]
341 SetMail {
342 #[clap(flatten)]
343 copt: CommonOpt,
344 name: String,
345 mail: Vec<String>,
346 },
347 #[clap(name = "set-entry-manager")]
349 SetEntryManagedBy {
350 name: String,
352 entry_managed_by: String,
354 #[clap(flatten)]
355 copt: CommonOpt,
356 },
357 #[clap(name = "rename")]
359 Rename {
360 name: String,
362 new_name: String,
364 #[clap(flatten)]
365 copt: CommonOpt,
366 },
367 #[clap(name = "purge-members")]
369 PurgeMembers(Named),
370 #[clap(name = "add-members")]
372 AddMembers(GroupNamedMembers),
373 #[clap(name = "remove-members")]
375 RemoveMembers(GroupNamedMembers),
376 #[clap(name = "posix")]
378 Posix {
379 #[clap(subcommand)]
380 commands: GroupPosix,
381 },
382 #[clap(name = "account-policy")]
384 AccountPolicy {
385 #[clap(subcommand)]
386 commands: GroupAccountPolicyOpt,
387 },
388}
389
390#[derive(Clone, Debug, ValueEnum)]
391pub enum GraphType {
392 Graphviz,
393 Mermaid,
394 MermaidElk,
395}
396
397#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, ValueEnum)]
398pub enum ObjectType {
399 Group,
400 BuiltinGroup,
401 ServiceAccount,
402 Person,
403}
404
405#[derive(Debug, Args)]
406pub struct GraphCommonOpt {
407 #[arg(value_enum)]
408 pub graph_type: GraphType,
409 #[clap()]
410 pub filter: Vec<ObjectType>,
411 #[clap(flatten)]
412 pub copt: CommonOpt,
413}
414
415#[derive(Debug, Args)]
416pub struct AccountCommonOpt {
417 #[clap()]
418 account_id: String,
419}
420
421#[derive(Debug, Args)]
422pub struct AccountNamedOpt {
423 #[clap(flatten)]
424 aopts: AccountCommonOpt,
425 #[clap(flatten)]
426 copt: CommonOpt,
427}
428
429#[derive(Debug, Args)]
430pub struct AccountNamedExpireDateTimeOpt {
431 #[clap(flatten)]
432 aopts: AccountCommonOpt,
433 #[clap(flatten)]
434 copt: CommonOpt,
435 #[clap(name = "datetime", verbatim_doc_comment)]
436 datetime: String,
442}
443
444#[derive(Debug, Args)]
445pub struct AccountNamedValidDateTimeOpt {
446 #[clap(flatten)]
447 aopts: AccountCommonOpt,
448 #[clap(flatten)]
449 copt: CommonOpt,
450 #[clap(name = "datetime")]
451 datetime: String,
454}
455
456#[derive(Debug, Args)]
457pub struct AccountNamedTagOpt {
458 #[clap(flatten)]
459 aopts: AccountCommonOpt,
460 #[clap(flatten)]
461 copt: CommonOpt,
462 #[clap(name = "tag")]
463 tag: String,
464}
465
466#[derive(Debug, Args)]
467pub struct AccountNamedTagPkOpt {
468 #[clap(flatten)]
469 aopts: AccountCommonOpt,
470 #[clap(flatten)]
471 copt: CommonOpt,
472 #[clap(name = "tag")]
473 tag: String,
474 #[clap(name = "pubkey")]
475 pubkey: String,
476}
477
478#[derive(Debug, Args)]
479pub struct UseResetTokenOpt {
481 #[clap(flatten)]
482 copt: CommonOpt,
483 #[clap(name = "token")]
484 token: String,
485}
486
487#[derive(Debug, Args)]
488pub struct AccountCreateOpt {
489 #[clap(flatten)]
490 aopts: AccountCommonOpt,
491 #[clap(name = "display-name")]
492 display_name: String,
493 #[clap(flatten)]
494 copt: CommonOpt,
495}
496
497#[derive(Debug, Subcommand)]
498pub enum AccountCredential {
499 #[clap(name = "status")]
501 Status(AccountNamedOpt),
502 #[clap(name = "update")]
504 Update(AccountNamedOpt),
505 #[clap(name = "use-reset-token")]
507 UseResetToken(UseResetTokenOpt),
508 #[clap(name = "create-reset-token")]
511 CreateResetToken {
512 #[clap(flatten)]
513 aopts: AccountCommonOpt,
514 #[clap(flatten)]
515 copt: CommonOpt,
516 ttl: Option<u32>,
519 },
520}
521
522#[derive(Debug, Subcommand)]
524pub enum AccountRadius {
525 #[clap(name = "show-secret")]
527 Show(AccountNamedOpt),
528 #[clap(name = "generate-secret")]
530 Generate(AccountNamedOpt),
531 #[clap(name = "delete-secret")]
532 DeleteSecret(AccountNamedOpt),
534}
535
536#[derive(Debug, Args)]
537pub struct AccountPosixOpt {
538 #[clap(flatten)]
539 aopts: AccountCommonOpt,
540 #[clap(long)]
541 gidnumber: Option<u32>,
542 #[clap(long, value_parser = clap::builder::NonEmptyStringValueParser::new())]
543 shell: Option<String>,
545 #[clap(flatten)]
546 copt: CommonOpt,
547}
548
549#[derive(Debug, Subcommand)]
550pub enum PersonPosix {
551 #[clap(name = "show")]
552 Show(AccountNamedOpt),
553 #[clap(name = "set")]
554 Set(AccountPosixOpt),
555 #[clap(name = "set-password")]
556 SetPassword(AccountNamedOpt),
557 #[clap(name = "reset-gidnumber")]
559 ResetGidnumber {
560 account_id: String,
561 #[clap(flatten)]
562 copt: CommonOpt,
563 },
564}
565
566#[derive(Debug, Subcommand)]
567pub enum ServiceAccountPosix {
568 #[clap(name = "show")]
569 Show(AccountNamedOpt),
570 #[clap(name = "set")]
571 Set(AccountPosixOpt),
572 #[clap(name = "reset-gidnumber")]
574 ResetGidnumber {
575 account_id: String,
576 #[clap(flatten)]
577 copt: CommonOpt,
578 },
579}
580
581#[derive(Debug, Args)]
582pub struct PersonUpdateOpt {
583 #[clap(flatten)]
584 aopts: AccountCommonOpt,
585 #[clap(long, short, help = "Set the legal name for the person.",
586 value_parser = clap::builder::NonEmptyStringValueParser::new())]
587 legalname: Option<String>,
588 #[clap(long, short, help = "Set the account name for the person.",
589 value_parser = clap::builder::NonEmptyStringValueParser::new())]
590 newname: Option<String>,
591 #[clap(long, short = 'i', help = "Set the display name for the person.",
592 value_parser = clap::builder::NonEmptyStringValueParser::new())]
593 displayname: Option<String>,
594 #[clap(
595 long,
596 short,
597 help = "Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'"
598 )]
599 mail: Option<Vec<String>>,
600 #[clap(flatten)]
601 copt: CommonOpt,
602}
603
604#[derive(Debug, Subcommand)]
605pub enum AccountSsh {
606 #[clap(name = "list-publickeys")]
607 List(AccountNamedOpt),
608 #[clap(name = "add-publickey")]
609 Add(AccountNamedTagPkOpt),
610 #[clap(name = "delete-publickey")]
611 Delete(AccountNamedTagOpt),
612}
613
614#[derive(Debug, Subcommand)]
615pub enum AccountValidity {
616 #[clap(name = "show")]
618 Show(AccountNamedOpt),
619 #[clap(name = "expire-at")]
621 ExpireAt(AccountNamedExpireDateTimeOpt),
622 #[clap(name = "begin-from")]
624 BeginFrom(AccountNamedValidDateTimeOpt),
625}
626
627#[derive(Debug, Subcommand)]
628pub enum AccountCertificate {
629 #[clap(name = "status")]
630 Status {
631 account_id: String,
632 #[clap(flatten)]
633 copt: CommonOpt,
634 },
635 #[clap(name = "create")]
636 Create {
637 account_id: String,
638 certificate_path: PathBuf,
639 #[clap(flatten)]
640 copt: CommonOpt,
641 },
642}
643
644#[derive(Debug, Subcommand)]
645pub enum AccountUserAuthToken {
646 #[clap(name = "status")]
648 Status(AccountNamedOpt),
649 #[clap(name = "destroy")]
652 Destroy {
653 #[clap(flatten)]
654 aopts: AccountCommonOpt,
655 #[clap(flatten)]
656 copt: CommonOpt,
657 #[clap(name = "session-id")]
659 session_id: Uuid,
660 },
661}
662
663#[derive(Debug, Subcommand)]
664pub enum PersonOpt {
665 #[clap(name = "credential")]
667 Credential {
668 #[clap(subcommand)]
669 commands: AccountCredential,
670 },
671 #[clap(name = "radius")]
673 Radius {
674 #[clap(subcommand)]
675 commands: AccountRadius,
676 },
677 #[clap(name = "posix")]
679 Posix {
680 #[clap(subcommand)]
681 commands: PersonPosix,
682 },
683 #[clap(name = "session")]
685 Session {
686 #[clap(subcommand)]
687 commands: AccountUserAuthToken,
688 },
689 #[clap(name = "ssh")]
691 Ssh {
692 #[clap(subcommand)]
693 commands: AccountSsh,
694 },
695 #[clap(name = "list")]
697 List(CommonOpt),
698 #[clap(name = "get")]
700 Get(AccountNamedOpt),
701 #[clap(name = "search")]
703 Search {
704 account_id: String,
705 #[clap(flatten)]
706 copt: CommonOpt,
707 },
708 #[clap(name = "update")]
710 Update(PersonUpdateOpt),
711 #[clap(name = "create")]
713 Create(AccountCreateOpt),
714 #[clap(name = "delete")]
716 Delete(AccountNamedOpt),
717 #[clap(name = "validity")]
719 Validity {
720 #[clap(subcommand)]
721 commands: AccountValidity,
722 },
723 #[clap(name = "certificate", hide = true)]
724 Certificate {
725 #[clap(subcommand)]
726 commands: AccountCertificate,
727 },
728}
729
730#[derive(Debug, Subcommand)]
731pub enum ServiceAccountCredential {
732 #[clap(name = "status")]
734 Status(AccountNamedOpt),
735 #[clap(name = "generate")]
738 GeneratePw(AccountNamedOpt),
739}
740
741#[derive(Debug, Subcommand)]
742pub enum ServiceAccountApiToken {
743 #[clap(name = "status")]
745 Status(AccountNamedOpt),
746 #[clap(name = "generate")]
748 Generate {
749 #[clap(flatten)]
750 aopts: AccountCommonOpt,
751 #[clap(flatten)]
752 copt: CommonOpt,
753 #[clap(name = "label")]
756 label: String,
757 #[clap(name = "expiry")]
758 #[clap(value_parser = clap::builder::NonEmptyStringValueParser::new())]
761 expiry: Option<String>,
762 #[clap(long = "rw")]
763 read_write: bool,
764 },
765 #[clap(name = "destroy")]
768 Destroy {
769 #[clap(flatten)]
770 aopts: AccountCommonOpt,
771 #[clap(flatten)]
772 copt: CommonOpt,
773 #[clap(name = "token-id")]
775 token_id: Uuid,
776 },
777}
778
779#[derive(Debug, Args)]
780pub struct ServiceAccountUpdateOpt {
781 #[clap(flatten)]
782 aopts: AccountCommonOpt,
783 #[clap(long, short, help = "Set the account name for the service account.",
784 value_parser = clap::builder::NonEmptyStringValueParser::new())]
785 newname: Option<String>,
786 #[clap(
787 long,
788 short = 'i',
789 help = "Set the display name for the service account.",
790 value_parser = clap::builder::NonEmptyStringValueParser::new()
791 )]
792 displayname: Option<String>,
793 #[clap(
794 long,
795 short = 'e',
796 help = "Set the entry manager for the service account.",
797 value_parser = clap::builder::NonEmptyStringValueParser::new()
798 )]
799 entry_managed_by: Option<String>,
800 #[clap(
801 long,
802 short,
803 help = "Set the mail address, can be set multiple times for multiple addresses. The first listed mail address is the 'primary'"
804 )]
805 mail: Option<Vec<String>>,
806 #[clap(flatten)]
807 copt: CommonOpt,
808}
809
810#[derive(Debug, Subcommand)]
811pub enum ServiceAccountOpt {
812 #[clap(name = "credential")]
814 Credential {
815 #[clap(subcommand)]
816 commands: ServiceAccountCredential,
817 },
818 #[clap(name = "api-token")]
820 ApiToken {
821 #[clap(subcommand)]
822 commands: ServiceAccountApiToken,
823 },
824 #[clap(name = "posix")]
826 Posix {
827 #[clap(subcommand)]
828 commands: ServiceAccountPosix,
829 },
830 #[clap(name = "session")]
832 Session {
833 #[clap(subcommand)]
834 commands: AccountUserAuthToken,
835 },
836 #[clap(name = "ssh")]
838 Ssh {
839 #[clap(subcommand)]
840 commands: AccountSsh,
841 },
842 #[clap(name = "list")]
844 List(CommonOpt),
845 #[clap(name = "get")]
847 Get(AccountNamedOpt),
848 #[clap(name = "create")]
850 Create {
851 #[clap(flatten)]
852 aopts: AccountCommonOpt,
853 #[clap(name = "display-name")]
854 display_name: String,
855 #[clap(name = "entry-managed-by")]
856 entry_managed_by: String,
857 #[clap(flatten)]
858 copt: CommonOpt,
859 },
860 #[clap(name = "update")]
862 Update(ServiceAccountUpdateOpt),
863 #[clap(name = "delete")]
865 Delete(AccountNamedOpt),
866 #[clap(name = "validity")]
868 Validity {
869 #[clap(subcommand)]
870 commands: AccountValidity,
871 },
872 #[clap(name = "into-person")]
876 IntoPerson(AccountNamedOpt),
877}
878
879#[derive(Debug, Subcommand)]
880pub enum RecycleOpt {
881 #[clap(name = "list")]
882 List(CommonOpt),
884 #[clap(name = "get")]
885 Get(Named),
887 #[clap(name = "revive")]
888 Revive(Named),
890}
891
892#[derive(Debug, Args)]
893pub struct LoginOpt {
894 #[clap(flatten)]
895 copt: CommonOpt,
896 #[clap(short, long, env = "KANIDM_PASSWORD", hide = true,
897 value_parser = clap::builder::NonEmptyStringValueParser::new())]
898 password: Option<String>,
900}
901
902#[derive(Debug, Args)]
903pub struct ReauthOpt {
904 #[clap(flatten)]
905 copt: CommonOpt,
906}
907
908#[derive(Debug, Args)]
909pub struct LogoutOpt {
910 #[clap(flatten)]
911 copt: CommonOpt,
912 #[clap(short, long)]
913 local_only: bool,
915}
916
917#[derive(Debug, Subcommand)]
918pub enum SessionOpt {
919 #[clap(name = "list")]
920 List(CommonOpt),
922 #[clap(name = "cleanup")]
923 Cleanup(CommonOpt),
925}
926
927#[derive(Debug, Args)]
928pub struct FilterOpt {
929 #[clap()]
930 filter: String,
931 #[clap(flatten)]
932 commonopts: CommonOpt,
933}
934
935#[derive(Debug, Args)]
936pub struct CreateOpt {
937 #[clap(value_parser)]
938 file: PathBuf,
939 #[clap(flatten)]
940 commonopts: CommonOpt,
941}
942
943#[derive(Debug, Args)]
944pub struct ModifyOpt {
945 #[clap(flatten)]
946 commonopts: CommonOpt,
947 #[clap()]
948 filter: String,
949 #[clap(value_parser)]
950 file: PathBuf,
951}
952
953#[derive(Debug, Subcommand)]
954pub enum RawOpt {
955 #[clap(name = "search")]
956 Search(FilterOpt),
957 #[clap(name = "create")]
958 Create(CreateOpt),
959 #[clap(name = "modify")]
960 Modify(ModifyOpt),
961 #[clap(name = "delete")]
962 Delete(FilterOpt),
963}
964
965#[derive(Debug, Subcommand)]
966pub enum SelfOpt {
967 #[clap(name = "identify-user")]
969 IdentifyUser(CommonOpt),
970 Whoami(CommonOpt),
972}
973
974#[derive(Debug, Args)]
975pub struct Oauth2SetDisplayname {
976 #[clap(flatten)]
977 nopt: Named,
978 #[clap(name = "displayname")]
979 displayname: String,
980}
981
982#[derive(Debug, Args)]
983pub struct Oauth2SetImplicitScopes {
984 #[clap(flatten)]
985 nopt: Named,
986 #[clap(name = "scopes")]
987 scopes: Vec<String>,
988}
989
990#[derive(Debug, Args)]
991pub struct Oauth2CreateScopeMapOpt {
992 #[clap(flatten)]
993 nopt: Named,
994 #[clap(name = "group")]
995 group: String,
996 #[clap(name = "scopes", required = true)]
997 scopes: Vec<String>,
998}
999
1000#[derive(Debug, Args)]
1001pub struct Oauth2DeleteScopeMapOpt {
1002 #[clap(flatten)]
1003 nopt: Named,
1004 #[clap(name = "group")]
1005 group: String,
1006}
1007
1008#[derive(Debug, Clone, Copy, Eq, PartialEq)]
1009pub enum Oauth2ClaimMapJoin {
1010 Csv,
1011 Ssv,
1012 Array,
1013}
1014
1015impl Oauth2ClaimMapJoin {
1016 pub fn as_str(&self) -> &'static str {
1017 match self {
1018 Self::Csv => "csv",
1019 Self::Ssv => "ssv",
1020 Self::Array => "array",
1021 }
1022 }
1023}
1024
1025impl ValueEnum for Oauth2ClaimMapJoin {
1026 fn value_variants<'a>() -> &'a [Self] {
1027 &[Self::Csv, Self::Ssv, Self::Array]
1028 }
1029
1030 fn to_possible_value(&self) -> Option<PossibleValue> {
1031 Some(match self {
1032 Self::Csv => PossibleValue::new("csv"),
1033 Self::Ssv => PossibleValue::new("ssv"),
1034 Self::Array => PossibleValue::new("array"),
1035 })
1036 }
1037}
1038
1039#[derive(Debug, Subcommand)]
1040pub enum Oauth2Opt {
1041 #[clap(name = "list")]
1042 List(CommonOpt),
1044 #[clap(name = "get")]
1045 Get(Named),
1047 #[clap(name = "create")]
1051 CreateBasic {
1053 #[clap(name = "name")]
1054 name: String,
1055 #[clap(name = "displayname")]
1056 displayname: String,
1057 #[clap(name = "origin")]
1058 origin: String,
1059 #[clap(flatten)]
1060 copt: CommonOpt,
1061 },
1062 #[clap(name = "create-public")]
1063 CreatePublic {
1069 #[clap(name = "name")]
1070 name: String,
1071 #[clap(name = "displayname")]
1072 displayname: String,
1073 #[clap(name = "origin")]
1074 origin: String,
1075 #[clap(flatten)]
1076 copt: CommonOpt,
1077 },
1078 #[clap(name = "update-scope-map", visible_aliases=&["create-scope-map"])]
1079 UpdateScopeMap(Oauth2CreateScopeMapOpt),
1081 #[clap(name = "delete-scope-map")]
1082 DeleteScopeMap(Oauth2DeleteScopeMapOpt),
1084
1085 #[clap(name = "update-sup-scope-map", visible_aliases=&["create-sup-scope-map"])]
1086 UpdateSupScopeMap(Oauth2CreateScopeMapOpt),
1088 #[clap(name = "delete-sup-scope-map")]
1089 DeleteSupScopeMap(Oauth2DeleteScopeMapOpt),
1091
1092 #[clap(name = "update-claim-map", visible_aliases=&["create-claim-map"])]
1093 UpdateClaimMap {
1095 #[clap(flatten)]
1096 copt: CommonOpt,
1097 name: String,
1098 claim_name: String,
1099 group: String,
1100 values: Vec<String>,
1101 },
1102 #[clap(name = "update-claim-map-join")]
1103 UpdateClaimMapJoin {
1104 #[clap(flatten)]
1105 copt: CommonOpt,
1106 name: String,
1107 claim_name: String,
1108 join: Oauth2ClaimMapJoin,
1111 },
1112 #[clap(name = "delete-claim-map")]
1113 DeleteClaimMap {
1115 #[clap(flatten)]
1116 copt: CommonOpt,
1117 name: String,
1118 claim_name: String,
1119 group: String,
1120 },
1121
1122 #[clap(name = "reset-secrets")]
1123 ResetSecrets(Named),
1125 #[clap(name = "show-basic-secret")]
1126 ShowBasicSecret(Named),
1128 #[clap(name = "delete")]
1129 Delete(Named),
1131 #[clap(name = "set-displayname")]
1133 SetDisplayname(Oauth2SetDisplayname),
1134 #[clap(name = "set-name")]
1138 SetName {
1139 #[clap(flatten)]
1140 nopt: Named,
1141 #[clap(name = "newname")]
1142 name: String,
1143 },
1144
1145 #[clap(name = "set-landing-url")]
1148 SetLandingUrl {
1149 #[clap(flatten)]
1150 nopt: Named,
1151 #[clap(name = "landing-url")]
1152 url: Url,
1153 },
1154 #[clap(name = "set-image")]
1156 SetImage {
1157 #[clap(flatten)]
1158 nopt: Named,
1159 #[clap(name = "file-path")]
1160 path: PathBuf,
1162 #[clap(name = "image-type")]
1163 image_type: Option<ImageType>,
1165 },
1166 #[clap(name = "remove-image")]
1168 RemoveImage(Named),
1169
1170 #[clap(name = "add-redirect-url")]
1174 AddOrigin {
1175 name: String,
1176 #[clap(name = "url")]
1177 origin: Url,
1178 #[clap(flatten)]
1179 copt: CommonOpt,
1180 },
1181
1182 #[clap(name = "remove-redirect-url")]
1184 RemoveOrigin {
1185 name: String,
1186 #[clap(name = "url")]
1187 origin: Url,
1188 #[clap(flatten)]
1189 copt: CommonOpt,
1190 },
1191 #[clap(name = "enable-pkce")]
1192 EnablePkce(Named),
1194 #[clap(name = "warning-insecure-client-disable-pkce")]
1197 DisablePkce(Named),
1198 #[clap(name = "warning-enable-legacy-crypto")]
1199 EnableLegacyCrypto(Named),
1203 #[clap(name = "disable-legacy-crypto")]
1205 DisableLegacyCrypto(Named),
1206 #[clap(name = "enable-strict-redirect-url")]
1210 EnableStrictRedirectUri {
1211 name: String,
1212 #[clap(flatten)]
1213 copt: CommonOpt,
1214 },
1215 #[clap(name = "disable-strict-redirect-url")]
1216 DisableStrictRedirectUri {
1217 name: String,
1218 #[clap(flatten)]
1219 copt: CommonOpt,
1220 },
1221 #[clap(name = "enable-localhost-redirects")]
1222 EnablePublicLocalhost {
1224 #[clap(flatten)]
1225 copt: CommonOpt,
1226 name: String,
1227 },
1228 #[clap(name = "disable-localhost-redirects")]
1230 DisablePublicLocalhost {
1231 #[clap(flatten)]
1232 copt: CommonOpt,
1233 name: String,
1234 },
1235 #[clap(name = "prefer-short-username")]
1237 PreferShortUsername(Named),
1238 #[clap(name = "prefer-spn-username")]
1240 PreferSPNUsername(Named),
1241 #[cfg(feature = "dev-oauth2-device-flow")]
1242 DeviceFlowEnable(Named),
1244 #[cfg(feature = "dev-oauth2-device-flow")]
1245 DeviceFlowDisable(Named),
1247}
1248
1249#[derive(Args, Debug)]
1250pub struct OptSetDomainDisplayname {
1251 #[clap(flatten)]
1252 copt: CommonOpt,
1253 #[clap(name = "new-display-name")]
1254 new_display_name: String,
1255}
1256
1257#[derive(Debug, Subcommand)]
1258pub enum PwBadlistOpt {
1259 #[clap[name = "show"]]
1260 Show(CommonOpt),
1262 #[clap[name = "upload"]]
1263 Upload {
1267 #[clap(flatten)]
1268 copt: CommonOpt,
1269 #[clap(value_parser, required = true, num_args(1..))]
1270 paths: Vec<PathBuf>,
1271 #[clap(short = 'n', long)]
1273 dryrun: bool,
1274 },
1275 #[clap[name = "remove", hide = true]]
1276 Remove {
1279 #[clap(flatten)]
1280 copt: CommonOpt,
1281 #[clap(value_parser, required = true, num_args(1..))]
1282 paths: Vec<PathBuf>,
1283 },
1284}
1285
1286#[derive(Debug, Subcommand)]
1287pub enum DeniedNamesOpt {
1288 #[clap[name = "show"]]
1289 Show {
1291 #[clap(flatten)]
1292 copt: CommonOpt,
1293 },
1294 #[clap[name = "append"]]
1295 Append {
1296 #[clap(flatten)]
1297 copt: CommonOpt,
1298 #[clap(value_parser, required = true, num_args(1..))]
1299 names: Vec<String>,
1300 },
1301 #[clap[name = "remove"]]
1302 Remove {
1304 #[clap(flatten)]
1305 copt: CommonOpt,
1306 #[clap(value_parser, required = true, num_args(1..))]
1307 names: Vec<String>,
1308 },
1309}
1310
1311#[derive(Debug, Subcommand)]
1312pub enum DomainOpt {
1313 #[clap[name = "set-displayname"]]
1314 SetDisplayname(OptSetDomainDisplayname),
1316 #[clap[name = "set-ldap-basedn"]]
1317 SetLdapBasedn {
1322 #[clap(flatten)]
1323 copt: CommonOpt,
1324 #[clap(name = "new-basedn")]
1325 new_basedn: String,
1326 },
1327 SetLdapAllowUnixPasswordBind {
1330 #[clap(flatten)]
1331 copt: CommonOpt,
1332 #[clap(name = "allow", action = clap::ArgAction::Set)]
1333 enable: bool,
1334 },
1335 SetAllowEasterEggs {
1339 #[clap(flatten)]
1340 copt: CommonOpt,
1341 #[clap(name = "allow", action = clap::ArgAction::Set)]
1342 enable: bool,
1343 },
1344 #[clap(name = "show")]
1345 Show(CommonOpt),
1347 #[clap(name = "revoke-key")]
1348 RevokeKey {
1351 #[clap(flatten)]
1352 copt: CommonOpt,
1353 key_id: String,
1354 },
1355 #[clap(name = "set-image")]
1357 SetImage {
1358 #[clap(flatten)]
1359 copt: CommonOpt,
1360 #[clap(name = "file-path")]
1361 path: PathBuf,
1362 #[clap(name = "image-type")]
1363 image_type: Option<ImageType>,
1364 },
1365 #[clap(name = "remove-image")]
1367 RemoveImage {
1368 #[clap(flatten)]
1369 copt: CommonOpt,
1370 },
1371}
1372
1373#[derive(Debug, Subcommand)]
1374pub enum SynchOpt {
1375 #[clap(name = "list")]
1376 List(CommonOpt),
1378 #[clap(name = "get")]
1379 Get(Named),
1381 #[clap(name = "set-credential-portal")]
1382 SetCredentialPortal {
1385 #[clap()]
1386 account_id: String,
1387 #[clap(flatten)]
1388 copt: CommonOpt,
1389 #[clap(name = "url")]
1390 url: Option<Url>,
1391 },
1392 #[clap(name = "create")]
1394 Create {
1395 #[clap()]
1396 account_id: String,
1397 #[clap(flatten)]
1398 copt: CommonOpt,
1399 #[clap(name = "description",
1400 value_parser = clap::builder::NonEmptyStringValueParser::new())]
1401 description: Option<String>,
1402 },
1403 #[clap(name = "generate-token")]
1405 GenerateToken {
1406 #[clap()]
1407 account_id: String,
1408 #[clap()]
1409 label: String,
1410 #[clap(flatten)]
1411 copt: CommonOpt,
1412 },
1413 #[clap(name = "destroy-token")]
1415 DestroyToken {
1416 #[clap()]
1417 account_id: String,
1418 #[clap(flatten)]
1419 copt: CommonOpt,
1420 },
1421 #[clap(name = "set-yield-attributes")]
1425 SetYieldAttributes {
1426 #[clap()]
1427 account_id: String,
1428 #[clap(flatten)]
1429 copt: CommonOpt,
1430 #[clap(name = "attributes")]
1431 attrs: Vec<String>,
1432 },
1433 #[clap(name = "force-refresh")]
1437 ForceRefresh {
1438 #[clap()]
1439 account_id: String,
1440 #[clap(flatten)]
1441 copt: CommonOpt,
1442 },
1443 #[clap(name = "finalise")]
1449 Finalise {
1450 #[clap()]
1451 account_id: String,
1452 #[clap(flatten)]
1453 copt: CommonOpt,
1454 },
1455 #[clap(name = "terminate")]
1461 Terminate {
1462 #[clap()]
1463 account_id: String,
1464 #[clap(flatten)]
1465 copt: CommonOpt,
1466 },
1467}
1468
1469#[derive(Debug, Subcommand)]
1470pub enum AuthSessionExpiryOpt {
1471 #[clap[name = "get"]]
1472 Get(CommonOpt),
1474 #[clap[name = "set"]]
1475 Set {
1477 #[clap(flatten)]
1478 copt: CommonOpt,
1479 #[clap(name = "expiry")]
1480 expiry: u32,
1481 },
1482}
1483
1484#[derive(Debug, Subcommand)]
1485pub enum PrivilegedSessionExpiryOpt {
1486 #[clap[name = "get"]]
1487 Get(CommonOpt),
1489 #[clap[name = "set"]]
1490 Set {
1492 #[clap(flatten)]
1493 copt: CommonOpt,
1494 #[clap(name = "expiry")]
1495 expiry: u32,
1496 },
1497}
1498
1499#[derive(Args, Debug)]
1500pub struct ApiSchemaDownloadOpt {
1501 #[clap(flatten)]
1502 copt: CommonOpt,
1503 #[clap(name = "filename", env, default_value = "./kanidm-openapi.json")]
1505 filename: PathBuf,
1506 #[clap(short, long, env)]
1508 force: bool,
1509}
1510
1511#[derive(Debug, Subcommand)]
1512pub enum ApiOpt {
1513 #[clap(name = "download-schema")]
1515 DownloadSchema(ApiSchemaDownloadOpt),
1516}
1517
1518#[derive(Debug, Subcommand)]
1519pub enum SystemOpt {
1520 #[clap(name = "pw-badlist")]
1521 PwBadlist {
1523 #[clap(subcommand)]
1524 commands: PwBadlistOpt,
1525 },
1526 #[clap(name = "denied-names")]
1527 DeniedNames {
1529 #[clap(subcommand)]
1530 commands: DeniedNamesOpt,
1531 },
1532 #[clap(name = "oauth2")]
1533 Oauth2 {
1535 #[clap(subcommand)]
1536 commands: Oauth2Opt,
1537 },
1538 #[clap(name = "domain")]
1539 Domain {
1541 #[clap(subcommand)]
1542 commands: DomainOpt,
1543 },
1544 #[clap(name = "sync")]
1545 Synch {
1547 #[clap(subcommand)]
1548 commands: SynchOpt,
1549 },
1550 #[clap(name = "api")]
1551 Api {
1553 #[clap(subcommand)]
1554 commands: ApiOpt,
1555 },
1556}
1557
1558#[derive(Debug, Subcommand)]
1559#[clap(about = "Kanidm Client Utility")]
1560pub enum KanidmClientOpt {
1561 Login(LoginOpt),
1563 Reauth(ReauthOpt),
1565 Logout(LogoutOpt),
1567 Session {
1569 #[clap(subcommand)]
1570 commands: SessionOpt,
1571 },
1572 #[clap(name = "self")]
1573 CSelf {
1575 #[clap(subcommand)]
1576 commands: SelfOpt,
1577 },
1578 Person {
1580 #[clap(subcommand)]
1581 commands: PersonOpt,
1582 },
1583 Group {
1585 #[clap(subcommand)]
1586 commands: GroupOpt,
1587 },
1588 #[clap(name = "service-account")]
1590 ServiceAccount {
1591 #[clap(subcommand)]
1592 commands: ServiceAccountOpt,
1593 },
1594 #[clap(name = "graph")]
1596 Graph(GraphCommonOpt),
1597 System {
1599 #[clap(subcommand)]
1600 commands: SystemOpt,
1601 },
1602 #[clap(name = "recycle-bin")]
1603 Recycle {
1605 #[clap(subcommand)]
1606 commands: RecycleOpt,
1607 },
1608 #[clap(hide = true)]
1610 Raw {
1611 #[clap(subcommand)]
1612 commands: RawOpt,
1613 },
1614 Version {},
1616}
1617
1618#[derive(Debug, clap::Parser)]
1619#[clap(about = "Kanidm Client Utility")]
1620pub struct KanidmClientParser {
1621 #[clap(subcommand)]
1622 pub commands: KanidmClientOpt,
1623}