From 61e32bce4f8702caa13bd6e8f0f18a6ff1e76e20 Mon Sep 17 00:00:00 2001 From: James Hodgkinson Date: Tue, 5 Jul 2022 11:38:25 +1000 Subject: [PATCH] docs updates and UI cleanup (#874) * showing the queried user when running account validity show * updating account delete * tweaking account and radius delete to show new message formats * renaming credential reset token ui * updating documentation for functionality * added notes to dev readme on how to install/build mdbook and updated docs --- DEVELOPER_README.md | 22 +++++ kanidm_book/book.toml | 9 +- kanidm_book/src/accounts_and_groups.md | 118 ++++++++++++++++++------ kanidm_book/src/images/kani-alert.png | Bin 0 -> 11047 bytes kanidm_book/src/images/kani-warning.png | Bin 0 -> 10655 bytes kanidm_book/src/intro.md | 4 +- kanidm_book/theme/favicon.png | Bin 0 -> 1660 bytes kanidm_tools/src/cli/account.rs | 99 +++++++++++++++----- kanidm_tools/src/opt/kanidm.rs | 26 +++--- kanidmd/idm/src/actors/v1_write.rs | 2 +- 10 files changed, 216 insertions(+), 64 deletions(-) create mode 100644 kanidm_book/src/images/kani-alert.png create mode 100644 kanidm_book/src/images/kani-warning.png create mode 100644 kanidm_book/theme/favicon.png diff --git a/DEVELOPER_README.md b/DEVELOPER_README.md index c2caaa053..3fa7258f3 100644 --- a/DEVELOPER_README.md +++ b/DEVELOPER_README.md @@ -247,3 +247,25 @@ docker run --rm -it \ ``` This assumes you have a `config.ini` file in the current working directory. + +## Building the Book + +You'll need `mdbook` to build the book: + +```shell +cargo install mdbook +``` + +To build it: + +```shell +cd kanidm_book +mdbook build +``` + +Or to run a local webserver: + +```shell +cd kanidm_book +mdbook serve +```` diff --git a/kanidm_book/book.toml b/kanidm_book/book.toml index fff6f68fb..98ab26961 100644 --- a/kanidm_book/book.toml +++ b/kanidm_book/book.toml @@ -1,6 +1,13 @@ [book] -authors = ["William Brown"] +authors = [ + "James Hodgkinson", + "William Brown", +] language = "en" multilingual = false src = "src" title = "Kanidm Administration" + +[output.html] +edit-url-template = "https://github.com/kanidm/kanidm/edit/master/kanidm_book/{path}" +git-repository-url = "https://github.com/kanidm/kanidm" diff --git a/kanidm_book/src/accounts_and_groups.md b/kanidm_book/src/accounts_and_groups.md index f97ff9d64..070d2d1c6 100644 --- a/kanidm_book/src/accounts_and_groups.md +++ b/kanidm_book/src/accounts_and_groups.md @@ -27,25 +27,57 @@ and sensitive data), group management, and more. ## Recovering the Initial idm_admin Account By default the idm_admin user has no password, and can not be accessed. You should recover it with the -admin (system admin) account. We recommend the use of "reset_credential" as it provides a high -strength, random, machine only password. +admin (system admin) account. We recommend the use of the "recover_account" functionality as it provides a high strength, random password. - kanidm account credential reset_credential --name admin idm_admin - Generated password for idm_admin: tqoReZfz.... + + + + + +
+ +Warning: The server must not be running at this point, as it requires exclusive access to the database.
+ + +```shell +kanidmd recover_account -c /etc/kanidm/server.toml -n idm_admin +Successfully recovered account 'idm_admin' - password reset to -> j9YUv... +``` + +To do this in Docker, you'll neeD to stop the existing container and run it with "bash" as the "command" argument, to get a shell, then run the `kanidmd` command above. + +For example, if I'm using the developer image in my test environment: + +```shell +docker run --rm -it \ + -v/tmp/kanidm:/data\ + --name kanidmd \ + --hostname kanidmd \ + ghcr.io/kanidm/kanidmd:devel \ + bash +kanidmd:/# kanidmd recover_account -c /data/server.toml -n idm_admin +Successfully recovered account 'idm_admin' - password reset to -> j9YUv... +``` + +Once that's done, exit the shell and start your server container again. ## Creating Accounts You can now use the idm_admin user to create initial groups and accounts. - kanidm group create demo_group --name idm_admin - kanidm account create demo_user "Demonstration User" --name idm_admin - kanidm group add_members demo_group demo_user --name idm_admin - kanidm group list_members demo_group --name idm_admin - kanidm account get demo_user --name idm_admin +```shell +kanidm login --name idm_admin +kanidm group create demo_group --name idm_admin +kanidm account create demo_user "Demonstration User" --name idm_admin +kanidm group add_members demo_group demo_user --name idm_admin +kanidm group list_members demo_group --name idm_admin +kanidm account get demo_user --name idm_admin +``` You can also use anonymous to view users and groups - note that you won't see as many fields due -to the different anonymous access profile limits. +to the limits of the anonymous access profile. + kanidm login --name anonymous kanidm account get demo_user --name anonymous ## Viewing Default Groups @@ -62,10 +94,31 @@ Members of the `idm_account_manage_priv` group have the rights to manage other u accounts security and login aspects. This includes resetting account credentials. You can perform a password reset on the demo_user, for example as the idm_admin user, who is -a default member of this group. +a default member of this group. The lines below prefixed with `#` are the interactive credential +update interface. - kanidm account credential set_password demo_user --name idm_admin - kanidm self whoami --name demo_user +```shell +kanidm account credential update demo_user --name idm_admin +# spn: demo_user@idm.example.com +# Name: Demonstration User +# Primary Credential: +# uuid: 0e19cd08-f943-489e-8ff2-69f9eacb1f31 +# generated password: set +# Can Commit: true +# +# cred update (? for help) # : pass +# New password: +# New password: [hidden] +# Confirm password: +# Confirm password: [hidden] +# success +# +# cred update (? for help) # : commit +# Do you want to commit your changes? yes +# success +kanidm login --name demo_user +kanidm self whoami --name demo_user +``` ## Nested Groups @@ -76,18 +129,20 @@ Kanidm makes all group membership determinations by inspecting an entry's "membe An example can be easily shown with: - kanidm group create group_1 --name idm_admin - kanidm group create group_2 --name idm_admin - kanidm account create nest_example "Nesting Account Example" --name idm_admin - kanidm group add_members group_1 group_2 --name idm_admin - kanidm group add_members group_2 nest_example --name idm_admin - kanidm account get nest_example --name anonymous +```shell +kanidm group create group_1 --name idm_admin +kanidm group create group_2 --name idm_admin +kanidm account create nest_example "Nesting Account Example" --name idm_admin +kanidm group add_members group_1 group_2 --name idm_admin +kanidm group add_members group_2 nest_example --name idm_admin +kanidm account get nest_example --name anonymous +``` ## Account Validity Kanidm supports accounts that are only able to be authenticated between specific date and time -windows. This takes the form of a "valid from" attribute that defines the earliest start date where authentication can succeed, and an expiry date where the account will no longer +windows. This takes the form of a "valid from" attribute that defines the earliest start allow authentication. This can be displayed with: @@ -102,15 +157,24 @@ to aid correct understanding of when the events will occur. To set the values, an account with account management permission is required (for example, idm_admin). Again, these values will correctly translated from the entered local timezone to UTC. - # Set the earliest time the account can start authenticating - kanidm account validity begin_from demo_user '2020-09-25T11:22:04+00:00' --name idm_admin - # Set the expiry or end date of the account - kanidm account validity expire_at demo_user '2020-09-25T11:22:04+00:00' --name idm_admin +Set the earliest time the account can start authenticating: -To unset or remove these values the following can be used: +```shell +kanidm account validity begin_from demo_user '2020-09-25T11:22:04+00:00' --name idm_admin +``` + +Set the expiry or end date of the account: - kanidm account validity begin_from demo_user any|clear --name idm_admin - kanidm account validity expire_at demo_user never|clear --name idm_admin +```shell +kanidm account validity expire_at demo_user '2020-09-25T11:22:04+00:00' --name idm_admin +``` + +To unset or remove these values the following can be used, where `any|clear` means you may use either `any` or `clear`. + +```shell +kanidm account validity begin_from demo_user any|clear --name idm_admin +kanidm account validity expire_at demo_user never|clear --name idm_admin +``` To "lock" an account, you can set the expire_at value to the past, or unix epoch. Even in the situation where the "valid from" is *after* the expire_at, the expire_at will be respected. diff --git a/kanidm_book/src/images/kani-alert.png b/kanidm_book/src/images/kani-alert.png new file mode 100644 index 0000000000000000000000000000000000000000..0882453e037db12b00825649002497500b845709 GIT binary patch literal 11047 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 literal 0 HcmV?d00001 diff --git a/kanidm_book/src/images/kani-warning.png b/kanidm_book/src/images/kani-warning.png new file mode 100644 index 0000000000000000000000000000000000000000..99924c7436afdd2dc9777fc0c005ed58f2c25fef GIT binary patch literal 10655 zcmV;QDPY!#P)@Ew^Sr$YoN{dJnEHtr$*kZ$iXfzf~G$v7_*nS!`QDZc* z1jUXeSP+e(s0e}$sV*QLq}Oe1x#gVq_s49#d+zpS7v1mk%yaKOXJ*bj=X~#+ciwsD z9Z^*pad1LJjs+eA`U9(hJ5_Z?{YqsZjl?=QAtGIYr9hJshaKQ_RsFPnq$-A0-vTtE z+IW!Cqyn&kmqeshJ;+lEjl?<#AtD2T^W&UO1)e#8;&`HwSO+H_0tDbPU?GqO{JHQT zoG&8d>qj($Mjh)QgNU34%mg?GcsJ(!UBCn8>wciWs;)VJ;uWEhSO*bAM1b#s{(fLN za70X=2ygj8#vbb+ zfr$8ll|a`dU=2n~kB6s#3Fd1Q7^14**0G4C(AZ-gJoqip72qbyCl$c;z-aT;hcQ9K znkMQLjXl;u01-*XbW$nJfptL3N|f6L998fMJfo`D*O7>2(AZ-g9QY%U0!Cq~45~)9;gk9N!Qi6?Dc)~8dJH%np!{vo#sU1Q zpnILlUf(ybF~ucSAB-D}4g__*$Px&su3M*NFn)a5yrB7@M;DW8ArPoD`Rn@zHm115 z`lztCnia3N`u*?K6WQ6S-MV>}Sq_?5Os@OuO#b@5fsM(NRKp5MH6k9Vl9N?;?9jNF zH&4~JJzc z>ib4ErZU7jzp%HuAReh&w^q%})Cv&}s}3CKS;rR87RBUxq1M|`-#4-`l_Hf5tf0U& zup%C@9($~aJM-qv({ba*X_qctv~S#9|&iq7lu<*JE^p7p$1Oe_U1s@1mC z_swifrHFNH;e-BdJW?HYm}-8$s;WNn$Rq0W`AU*Q0SyL&`tr*!YZ3nO5AV7_FD@>Z z4jfu*ZK>~@*_et*l?ZGGGy(Ldc*J_~MO9V(>Z`BRvaB+sDolxqiJF#{W{BlDsv}2w z)|U?2skq!M3LFy}iS;u{z#WC8xHTTBdh}3@L{wFE)TmK$NmZC`zWHV?!j>(nEn9ll zJF8%zP*CpXMq>R;63_zJ2WWH9z43@OeR>g34m<3y3W?RbcW*6)sZ+h{1^s<-xqP5c zjoVb;H?=V-z$1lZm=upxg9fR(ZV^Y4lanhXR`ce~wG1x4*t7mT(4&gWrU3~xYEymR z)L(kSc*EoZ+8%U&JYs$Rc`1IRq@+|xtgc}n*kU#3Qjz+)StM8lpOHROyLK3_Y?-h9IrQXC))v;s8#wAs1YHHkas%mUuM;+yP&Gn#7i|cx; zT5YTEoBK;mz>q=`99_^;lzGU0zv|kxahRd{$tR!0CDvt^T^6@o5f&{nt~Vaney((V zmsPoa^?ieXsR@`@_~2&7>#ZhCh(`%kRdpOkJ9X;hNvtVTrj%Q@2$LpxUmNuN;`%ax z!>ZK2`o6)x!~~pONPuDSNY$i?>h|q%`A~?76DN8SYn_(^pcfoRb@*^k8FquF6xaDB zU{|`0^?j3nX$dpYoK{GHui_DF;>2>;P>l8K*QB2}kOohntfL?x=tnt94GlTuds z+bZ48`o7WinSfRSi&vBUZ17n;1|%JTYhGDMfb-&!sznRcefuipLm`F^9a@T5u!#CqhBO0vP=`RAW6MXZ-zdZ|j~i*Ww=p7QL+tP(1ye+7_OVO#6!CLYKH z922zJ3b+YA<^$a-D&x0!rd0x=t(T$tTXf}xXcIqS3m&TEH4`x*5+(shRkF;V3LpMe z@krI7gKBPWmH3dIon2~*XVa!lRVrVE-Mdv&Qat5a0O~I$*Ao@CwK6xPAt%5WwAp+~ zH==XTLQn2U*k_RkTvAS%K?3gQXBtu!rVma>1zccI1=s8sv{~CSNa(nBglr)n=vP6R z=D;2>ZZVtU5v#JJxftAb+ieQynP;9^t@1^fIa5`{Q?|Q`iRA*L%WZFYCl7`MT$X4P z*>{B@hx=Rf;bTz|9N-#{{1UWS`0Fl2N|LHDUDSnW&>}6~2naaK79tmQA(}DXlo`{B zNYLiv3gmpSut)i0JW_S29cj z+;VL%>=r@uTYx|HfyqO$Ea5*Qa$QW3u?j~&dMrM#`u=%5w$GwFaAWK_5joEi-oASP z_8TW-9}+Of?;e0J1nph&zEP9=#WIfXK^=xh@5B(Z{9Zm z>yCcjWzRjFV4{!nVvmc+kr)#LZ7@O8Jn_&&o*oC4!3!_Ez^qxbuq=zbygY8W;RZsX zP_^nR!hiwr7w;&OHvprGe?DH&#!_fd#1fI7iGEonBAV!z6(Vx0h_sKFKOl@bvlEtG z&hxmjH%#n@WeaclE&l$8qwuv!C|?f01&{8GK zm|76ZvIq@|SP3>$hNsYV)@b;1A9{95=KpMAqb>5V=WYuY!$)?&uBhJo1|rw?#Ft>x z@=r%sPL}gJ!@xGUz<)37Oz@w_mw&JNw}$2cBETty$3)~9FumB}z%^b4MPSmT$_W(* zW5GqM&*TygLUiHF>Ts3Qd3j8UgD+{u- zAt%SAj11Vnzx40I@7dXqnF+bM=67bMIkta4Y}@8}iA>;V%ya@~xqe?&&8|gS*BC7U zT6^d}e#CU_D4PfGEYpc_%(PSF*F7896E}~T>|$O{$(c-N9VZes?ww? ze8Btnn+IO_fU~kp%E>XuV#$%7UVN^Q9633VpI_%~J_IvLEEo=V0UiZ@+mL#!VZfZ| zHBg>14zOqsJhK8O^oFDBeV?mhI0}cnNHpRiVaJeuC@?o(fs_=mZ9|Ck^aCbmZDT7C zGh!Ljkcc%L_`28^`?*Hx^bEtw9y?YK+> zK3COnK~_Vo2(&#&i8XCK?8+@1YK{=_r#dB;i1Y!*E<6v8YKgTW8@}AmA^+XL<)3e5yg;@s@}g^OZJWXLSO+UM zWS9P(2b>N(iP?HYF%P`(0hjCzaw$!Y91I!u7o003M^1^d^@RKak-Ws)3OuK(X?3c+ zi^v&4n;H4PDeFm)88*hxXI2tgvWH;6Vr|5w>kk(oy<60oNOg+o8{ynf>RXCZh+rOi zCdGU%?4U~Ww~*Uecz1k7Z$(wDlonjq#5&Dy@xSoZ<=dOm_Q9)b;p7e`9jtH_F8CDQ z*-*XmhXkNm0Fr!=?1Sb(^F7H2J91(E4)#Zt$0$~X3dzz6cs8cGTU7P28Z@UysB0Z7 zGwNbzh0P6%hhMdXhX&QLBnJSNz_gQL#wJ+22cini{LnN2O$rFoB3S%=Wd=lDIQuY@ zr#$>;C49Gw^hi_-JuV)$gbA+F3$y=aEb7(xUDp?1p`a@>ka(^wKQ~wc=NxWQMW~8# zcWox9nKD5{7Ft4ozXf53xoTEb$D#_eqP34YwPUGjR)WpG6$h_TxxrxRJ|g)Ji$x^O zXVHK1P<9<)en7NB|CM4X%m)=xPET*XTA z$+ocaspIk~u*h+dg}dQ|1G2a0&kz4fGjpiV4)gZ>`1@c_VioCF#$8(G25mZna$|3J zdjo9DW(*CDSipJ7ep+m~j6k5^g_;+IW&2>kZc;zp!X=+?V{CQ=zXG|@+7S1bi7$7U zl|b=E)~QLxXDw3NbQvtzrgwhOri-h}b-m#Bqs>aBtvRqUn>uqkstK_Yn+0$JCA73e zpK1Kyws2!_e6GThy`~YT#4a&tM5U1D7{lugy~@v*YJ%QR-~kr6!}ol@S+vWk#*Z(g+WHwAriyh+PK|i(t&aXlQ$QW~eu*0Ji6X zqqXJGP!`oDma1+{u=(kuc-~cws1g^qDnZI?tK=1ErMg}cBkMciFYu_{E3>{$5@ z(`RhrAa-n75OiqX9Vtj{td!}1VItaxh&@}g$_W5|_kRjq|} z_}-`yu~aqcxV-Von#R{*UE#VOkQ0T)70kC*w#Rxr&Gdk(dPVI>=#3iB6}s@om)r4g z%dHJ@8WD>#IvE?)ORLMz7puH`5$lJ2aQF8RQQ4=e@7A7_Wf7NHB64PuU*-pWk|83l z-t@gVUh-OK`<(_++$qfRgfbtgSh4+K0w=6>-6Wi!l?>b%uDB_Ypmt6MAY06)nW_ zl~YF}Y6$@wrVKMHtnc|ACV9AV2jjd7Kivu!ero1wA2|*zkelZ7u!uaZs&zJl8;=y5 zH|@t4aVrVcRZE8l^$KZf@=LAxZ_FxD*An7;#}N&w?0UuVRM zN1KmxqgY?=sH@91qN=#)GxK?6_p;{}?1s%T`j@Nl**3WCXxM(4Ar-*99gt|VNmcX8 z)>M1&?6FieBhe>wC$C`G$OaZF=$DB7VVJWGuI&lUV?5c@Lonn$6X_-v+b@HrB{W|J zp8b(fp2MqkDlp}Y3iBN%P1}IACNo}+MjR*%ec!wWC-yIU?#*@P^Jb4g;Q28l!}mAA zhHQM46GpqX5SLi0`l;V$>BCDoDC57Z$%MarXO!34!fR{czJ;)}PG2IW@yrUdp!bnu z!7C{5lgrIo#n_$yxc;^Ve|tp>Vy2qu<9{U_}Nzemo?2C^aRC_4zjV zb|?ObTQW?0-Jx7!sp@+^i$!-VsJqcaUEt0I@MD3WSVkEBwxo0vn5trD9{h8e@#X~M z75m4pYc6Mbn79DWnhAYc!kZ`K83+8ng+_T*jzwOHSK)2n5%ycWp{gtDOz0A* z(3p_#aLb!(u@~<-5aQGvyYgWEPV-$vxap>wXx^$8qL& zqDP)W9c%hVShO2E>~dH2B(6FtB$ldv8L;{6_62q4ZCIOlBCW{Rhz=b(@Zf_Fa?(jB zF?W0Q>-?fbz~B>3IDv^1Cz9H=C(l;n6+7@9_;d^W{#P&})dUb3@jmz_n{$&_nuQae zjD}Z6dJ`r+1izmThc0gIMjZpW$% zgXx>=jBVxL1xjf5Lrm8`p?CGJwXDRPWiS{dF)@*ploVE^!kUt6ra@rAd&Ll|^P|CL%&s#3-;;#oHT7uYSqMD89g^Dn6b^mYLVuH6^Bi z6KpuDB@AzG^r`Yl1#t6MCV=kKLm;Ju6+WJhWeLn0g@49rSnU(}P0(V6hzzKj$Djkkt{?Rxd<)eIXp zjOELhlkY%w6QB&j?~JvtFN!f!GA!Y(AfbRu>|f&2mXM~n~k$sM6vv&vo6Q8P<_T`!2; zH_%ZtBKl4DvaTQ%!S9hjEiJ9+d$=0JioFNXXq5T$=bQShvexbLaB>GY`*65_A$;@` z+|tL`sG7!cI9i=A z|M3Iwh)AEhQ0j{W5s`$T#k(i8C-KD*6_d(Qcy=Y+v4C(^7(XD__d@R;fK;??+v{u1 zD<(F;1(+BF8?)ioO77BC677>9*>A}1g=W?87>oDN!Cb3V1#OMR+o!;btKbjcz$Kp> zm7rTQ6V)&!(L@25dZszVl6KveS9)o?wk)_QB8?vG6>+tQla7>%h^}nzR z{`d{7AL~8$RT*3}7oPL5FLi7JD=##?OjVE@g#qsrTk=cd(r)l-_4lu=G@>rNz7FnR zNaUv+?Bm*E9iLJ>Xjr@l{S4Bih4_y|J<*$REEUx5KMM z9#~}TLWL3ON@7Q@ncBFxYt0(eDH)zT!RRaiKFdV9d8}Y0)%R@}H{0khUdRX=W9_li zP52-%&T_x&Z48(It%7iCUt@c!3uK1P1bT<5g#Yk0*;{jY2xb2ET%ulv(1M8SWjwMR z<^4_j*>dUZ@@Gx{bpk%iq6ctU?X&=VBHZ%OAOhtX=AK**A8sZRbveaj1QGReG6R^m z11CSqK1Ugp5$2o+7I8<|rR`H5F@8VVZ1jpDwGf=`)Q+&=T=?HlMqxj>W3fpi!8W?g z8|&cscIJ9b{YKGUyaztnVxCa!Dwju(gWnwmUu=cpsnEF`U9P%VvKJ<=#C>TsuH%v( zGM)&NRdv6J{A*7>>zC~%5F5Q`e*|n{udDbd9n{tiIh_5`Pb`_fF@7ZH)FkNIjA+_E zYAv?4PXsM*?;1zpFW(W3y4B_RCN<(xAPwaJ{#bn5U)r# zmgm~qQZB)UUw1Bh{7-%0(%I&7N3J1Ko@091Zim3%2E%u|VcA}@v1Lgdo?O;2SySXh z;f=NMf6l`GsAZ_7gYyk}Z(v!^w#fFJRG%u!}!ERQ##{vp7;rG?N)6 z@^);UKq%2yHa_NxjQ9%$Y7^&of#+7ihd;rT;bm=QTXNvmZ{daEbti+XX5R3%wYaaW z!Hu}&J1)-ylk*~;f8Ij8vn!ulLr!VA*JY9)RX)dT*;7)(Ocar1fzE?GblO6shhSG8 zK_D%DuByRuT)tnht9&of!R@dth_`pdkG8OPeT)mq_FU8z=BjGRmr9G43EtPriJ-5p zfv&F;x^saUUDg$*3^T^XTfQzGUNPjr?cc(nHgK_r9#|7NYUV1hpNF=2ned4BabH@) z*SS%yinz3KRBwv&Mkt9@0DDVVoc4xbPlyCe{rLN#Xozi=k5ons@fuNFWtlV0j-O>;q(w;*JW)?b}Qbiu8kqw zf7fS|_KzR9WYS`KcSs_1aW{fz9cJbft7?glhYn4QZD{xm<0)`SH#7Qsah1_mK0L$Q zv97AvlWztjGdJT-TTe7Aj4x<2Ki}as;N854?yO>!5hzmD0rLm+2|q?$T_Pf}#7YE) z9od{vvY)s{hZoln0p2UI#b1r#1K!Jt@btSI;esySnTDo7zC$k&Nm11@i^5!Z?x!4n zyECuY=xGZ=**#v;_vL$!K6|#nPTEYboQPfmOcIgKTXQ+@sTGX<$1?i+E!;tEaZc`F z<}U}gtyy^QZp~oH`DSYA=@q8u8r{hlC9At%Vn)~)H$UGBA8#dpRXRc2B4i8mLJt20 z-pz|@P5ROa>bNYrG148VF_H* zgW%tnaxLIVtf=ybwOK4(pKYd9+9hKBXmLzTwk2K0@WcQB2_Q*CK~$Cy`Ftz>F^82t zacn#2+lok9I)4W)DtS&-GcbdI8DNMOaT)skZU!yeM_(KI=Q*?oBqfpj9xaeg$pj8< zf}|uFPs{d6CQ@*s&-8SKpCz$BVy2ZcLJ)FcUp{QkF|iLe?}ttMaW?KJygn0ORs_E- zM1nS}^P_y{8vSGuupk<(-FdeX7|<$#kk2AvcfN6DR^{dr#QlyE#1ddwDv?gf-uvoI zT?@0fA+B;`Z3|koU!jQnImyRgmtTPYa1R^J`Ybr&P1IG+P}PsUDzj~QrDcE%uj@(R zryO`?HI70{RW0&_O7O{tzwXSbQ%9Cv2>Z=082TP=RQZFdJ|QB%0tNydfMm=z#M^;+ zu}hdlq$$uFv&VNg%OW*s(M6OFA(wWJdT#*|uy91skmK!h7O=>&Ew;PL#*o8$U<+mk zjvs(kbs7I47Jf^<9MFa#r*weHD+%ulF+1Yw>4oP-BpLHc8wva0&@sJcw{B(5LC_sDiVc(RoPho``u-81@0-ANH^&rPc_$|J> zx(7|38d7!ych5rf!Np`oT)M03F3(Cu?(+$E3}}OI!ESO~rDe&XtcV=xw^(#bACev# zRQ-{C*fpLEfBuGut1QiT7~?f+{W-vA$;>8xPR$OZ3KLZI8LxaI(kfuF`lh33@%O={ z?`>Wb&ijPu>}~7`xeQR%YODgN96a}g7LlR0@YxN$u>W~{Y1>oSg??`lUYpIwp{Sna zS*eIv@UkV0jVd;9ma4uVljk%`_;6xB1CgBz7>(=oRx=kkNmcKRm)CE}TV0wlX4&}!O4|K0!Z7MXB8&DE-J?}?DYK_dNmajelvAHx zN&aP@TlTc|LZPb0#ezH1<=RXbmDnbZi3i z&L%J-l{P_}*&DdciYU6Tqb z*u}nJVa2B-Q)&A4srX7N^pB^(AHOE-7zeSXamxGr7B5C!#<;2;UQ!?;<1JyzuFJ8i z>gF4Z+$aqHfNDKj7w?*Vr(is&gwKRjZ)Idlz>_N|Ng3)o|Q&oZb0M54j9I zP^5y&EwNu6ayfc!HedF6i|D%>i_g6@9ABqoQUW%wi+HO^s_Lj}+z=W*VZ`a3YH!_Q zr(}3&Fh0MR(*t*AFZvcgPIFoAyKR z7BFQvK1+B=L{6yU^^+B(X)Vw11#P&p2Z2N%m)CC14GSW2Ji@&%j=*>1Atsi_WCc8scX$@l`D=wgBJgdr*Fl~U^0KTbCI~y|m7EiQKqV=%$*xlbG zk{e;2W2Vn)%?q?9DA(LjsR~2}1a01I;^WZkdJ%YN39hT0tEw|9E)4-&-aM}}zkcJS zilZ}UhN0anL_-eafcG$Se{F#_K&yh^t%0@yoAv^SgdDC_)s@w6VZ%d#%JF4~Ca^sh z*Hs<_9;ofr%r!xci3MhPK5(}s+$Lc8EVhLlj!@MKw{8-V3xYPU?H-4(yyfhLxMnWy zt7}=17tv#DEcihP5%C2rmW5n;CiqyHALUY2U0mOC#iCXsUa4xns@~x$gM2nWh8$8Y zxTBKA-*=U)rz#o5Y(j6W{3wG(#3KOpF9IXNE?q6SJ3q?N4Utq(OT;RKsxAyg=>yy= z7VRooCO_hG-vf(@Y_G)DbbVXFz}AFqiwQLp_h7|m3LPBP`&G5UhVQJES7D8X5b*~s zz8{)O&zWc7uPD;ZD{J7YIpjrM+NtV67A*Xifd;V!ld48SE*H+(MrgvkiZ?8{unRQt z;e(&Io$6plgCG`ws;-K-oc7$0M6Ub-C*GdMU<{zw_Qapy`}xcV{@l=Dhy|dkUpdO~ z*VdA8{B*+Q?b>>6PY6ZnRxtD5hz5oRMJxbS{Wk1!^bhHL-uG?XYv$sv@>ty8r5T)Z zC{e#v`zuTuQFAm1xOoGix0zI69AY- **NOTICE:** +> ![Kanidm Alert](/images/kani-alert.png) **NOTICE:** +> +> > This is a pre-release project. While all effort has been made to ensure no data loss > or security flaws, you should still be careful when using this in your environment. diff --git a/kanidm_book/theme/favicon.png b/kanidm_book/theme/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..0bcdc0054223c09aa7104c322c1a57bb5b160cde GIT binary patch literal 1660 zcmV-?27~#DP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H11_?<- zK~z|U-IsrC)Mp*XU(fgZyilPCa>v5u?5g>(8m2pKTp6u=Q?D?Molvb?H z*c{8n)#HjH$Ydn3h@Z)*A5BqYPPTbG77sNI_ItauMTrh1Q)!_H!LpJ&1qfukjA0nOB z$)q!vpfnXlQBXA_GMRj9!2k_Kq7gs{VcuOUp1HGBRP~)7TAyt#z-qM+3`PL3m`%iD zaT19XsiaOkkwjG$@^W(kFdDQBEbtaIFB4yQ{xckT*ewn`bQ_QDYhcIcmhzKCQda;% z6EQL$ky9p<0RU^Z1*6dbQerm9QvmbkKz+V&x4Ze>dt)4_$tA1Wj`0Wew0{s{TvMQF zMZrB!4qw{G#6)byFP=zZ(Ng5(J0YFHps8e8OvDpOf`NX9&%e9%V*!K^ij*>AGEw&B z3S8C|xcVc+0c=K;wN45Ex|4;5w4PwhcNV*&3{5iupzCQi$dknURy>wFNa<xsQcAKcYJA%NngDqwqFX9(Z>hk2EzOl?HNc_T5BQ}A+H2tCu#el9 zfTn;J>1R^0l4Z>&8IK^-@u#i{u%}KOSdmY4GL3pYfv+}`3ZqkSNAacpJ7ciHK6-S( z;H~N&%fEFpI-!pH`yan1fYpfFww%Tr2@cR!4L>^rs~xbu2u_Z`!HwMA(Ld0)`PhI( zN~vF|p8;qr6%9EGs{#q8zFm81CpT)l-7pk`m(M}L<*Yd!psUi(s=7Rp=?couY3idcHU z!`a_@>4~S|lppFG5Khi65RAon^VrKX{YVNrIy#uT>I5_e{(K%D`UD*G5ZHT)=Q_vm zKe3KYZL4{1S|_BGJiSqz-dV$%@BEWLyyatbV=>?Ggn52zB@dbu3@x`X^UfdcgKPs_ zjKOj{SX4MN0J~g}Ynlb{$4S3>fzH1SV6qyi{FR5wmQreed^?AoW-P78Y5n_<{F4Tt zs^|de4Bl{pk#kYPFZJ>GBW}Lk@-;j@#Qw&m9IVNu z@rg4u*-Y#xHdE0Prl+Zd%3t?zvM>OX33UgsSvY3podJh2nGt(x5n z34A?m-lF@AM?QO3sd&GkkS~!TIiG%^wrKx?8?~GMIsGrDgFipFQV8P!0000 match commands { AccountRadius::Show(aro) => aro.copt.debug, AccountRadius::Generate(aro) => aro.copt.debug, - AccountRadius::Delete(aro) => aro.copt.debug, + AccountRadius::DeleteSecret(aro) => aro.copt.debug, }, AccountOpt::Posix { commands } => match commands { AccountPosix::Show(apo) => apo.copt.debug, @@ -87,14 +87,34 @@ impl AccountOpt { error!("Error -> {:?}", e); } } - AccountRadius::Delete(aopt) => { + AccountRadius::DeleteSecret(aopt) => { let client = aopt.copt.to_client().await; - if let Err(e) = client + let mut modmessage = AccountChangeMessage { + output_mode: ConsoleOutputMode::Text, + action: "radius account_delete".to_string(), + result: "deleted".to_string(), + src_user: aopt + .copt + .username + .to_owned() + .unwrap_or(format!("{:?}", client.whoami().await)), + dest_user: aopt.aopts.account_id.to_string(), + status: MessageStatus::Success, + }; + match client .idm_account_radius_credential_delete(aopt.aopts.account_id.as_str()) .await { - error!("Error -> {:?}", e); - } + Err(e) => { + modmessage.status = MessageStatus::Failure; + modmessage.result = format!("Error -> {:?}", e); + error!("{}", modmessage); + } + Ok(result) => { + debug!("{:?}", result); + println!("{}", modmessage); + } + }; } }, // end AccountOpt::Radius AccountOpt::Posix { commands } => match commands { @@ -149,7 +169,7 @@ impl AccountOpt { AccountPerson::Extend(aopt) => { let client = aopt.copt.to_client().await; let mut result_output = kanidm_proto::messages::AccountChangeMessage { - output_mode: aopt.copt.output_mode.to_owned().into(), + output_mode: ConsoleOutputMode::Text, action: String::from("account_person_extend"), result: String::from("This is a filler message"), src_user: aopt @@ -221,7 +241,7 @@ impl AccountOpt { AccountPerson::Set(aopt) => { let client = aopt.copt.to_client().await; let mut result_output = AccountChangeMessage { - output_mode: aopt.copt.output_mode.to_owned().into(), + output_mode: ConsoleOutputMode::Text, action: String::from("account_person set"), result: String::from(""), src_user: aopt @@ -310,12 +330,32 @@ impl AccountOpt { } AccountOpt::Delete(aopt) => { let client = aopt.copt.to_client().await; - if let Err(e) = client + let mut modmessage = AccountChangeMessage { + output_mode: ConsoleOutputMode::Text, + action: "account delete".to_string(), + result: "deleted".to_string(), + src_user: aopt + .copt + .username + .to_owned() + .unwrap_or(format!("{:?}", client.whoami().await)), + dest_user: aopt.aopts.account_id.to_string(), + status: MessageStatus::Success, + }; + match client .idm_account_delete(aopt.aopts.account_id.as_str()) .await { - error!("Error -> {:?}", e) - } + Err(e) => { + modmessage.result = format!("Error -> {:?}", e); + modmessage.status = MessageStatus::Failure; + eprintln!("{}", modmessage); + } + Ok(result) => { + debug!("{:?}", result); + println!("{}", modmessage); + } + }; } AccountOpt::Create(acopt) => { let client = acopt.copt.to_client().await; @@ -333,6 +373,7 @@ impl AccountOpt { AccountValidity::Show(ano) => { let client = ano.copt.to_client().await; + println!("user: {}", ano.aopts.account_id.as_str()); let ex = match client .idm_account_get_attr(ano.aopts.account_id.as_str(), "account_expire") .await @@ -463,9 +504,9 @@ impl AccountOpt { impl AccountCredential { pub fn debug(&self) -> bool { match self { + AccountCredential::CreateResetToken(aopt) => aopt.copt.debug, + AccountCredential::UseResetToken(aopt) => aopt.copt.debug, AccountCredential::Update(aopt) => aopt.copt.debug, - AccountCredential::Reset(aopt) => aopt.copt.debug, - AccountCredential::CreateResetLink(aopt) => aopt.copt.debug, } } @@ -485,7 +526,8 @@ impl AccountCredential { } } } - AccountCredential::Reset(aopt) => { + // The account credential use_reset_token CLI + AccountCredential::UseResetToken(aopt) => { let client = aopt.copt.to_unauth_client(); let cuintent_token = CUIntentToken { token: aopt.token.clone(), @@ -499,11 +541,20 @@ impl AccountCredential { credential_update_exec(cusession_token, custatus, client).await } Err(e) => { - error!("Error starting credential reset -> {:?}", e); + match e { + ClientErrorHttp(status_code, error, _kopid) => { + eprintln!( + "Error completing command: HTTP{} - {:?}", + status_code, + error.unwrap() + ); + } + _ => error!("Error starting use_reset_token -> {:?}", e), + }; } } } - AccountCredential::CreateResetLink(aopt) => { + AccountCredential::CreateResetToken(aopt) => { let client = aopt.copt.to_client().await; // What's the client url? @@ -517,11 +568,14 @@ impl AccountCredential { url.query_pairs_mut() .append_pair("token", cuintent_token.token.as_str()); - println!("success!"); - println!( - "Send the person one of the following to allow the credential reset" + debug!( + "Successfully created credential reset token for {}: {}", + aopt.aopts.account_id, cuintent_token.token ); - println!("scan:"); + println!( + "The person can use one of the following to allow the credential reset" + ); + println!("\nScan this QR Code:\n"); let code = match QrCode::new(url.as_str()) { Ok(c) => c, Err(e) => { @@ -537,9 +591,9 @@ impl AccountCredential { println!("{}", image); println!(); - println!("link: {}", url.as_str()); + println!("This link: {}", url.as_str()); println!( - "command: kanidm account credential reset {}", + "Or run this command: kanidm account credential use_reset_token {}", cuintent_token.token ); println!(); @@ -844,6 +898,7 @@ fn display_status(status: CUStatus) { println!("Can Commit: {}", can_commit); } +/// This is the REPL for updating a credential for a given account async fn credential_update_exec( session_token: CUSessionToken, status: CUStatus, diff --git a/kanidm_tools/src/opt/kanidm.rs b/kanidm_tools/src/opt/kanidm.rs index 47a88efd7..db88c4806 100644 --- a/kanidm_tools/src/opt/kanidm.rs +++ b/kanidm_tools/src/opt/kanidm.rs @@ -26,9 +26,6 @@ pub struct CommonOpt { /// Path to a CA certificate file #[clap(parse(from_os_str), short = 'C', long = "ca", env = "KANIDM_CA_PATH")] pub ca_path: Option, - /// Log format (still in very early development) - #[clap(short, long = "output", env = "KANIDM_OUTPUT", default_value="text")] - pub output_mode: String, } #[derive(Debug, Args)] @@ -144,7 +141,8 @@ pub struct AccountNamedTagPkOpt { } #[derive(Debug, Args)] -pub struct AnonTokenOpt { +/// Command-line options for account credental use_reset_token +pub struct UseResetTokenOpt { #[clap(flatten)] copt: CommonOpt, #[clap(name = "token")] @@ -163,26 +161,30 @@ pub struct AccountCreateOpt { #[derive(Debug, Subcommand)] pub enum AccountCredential { - /// Interactively update and change the content of the credentials of an account + /// Interactively update/change the credentials for an account #[clap(name = "update")] Update(AccountNamedOpt), - /// Given a reset token, interactively perform a credential reset - #[clap(name = "reset")] - Reset(AnonTokenOpt), - /// Create a reset link (token) that can be given to another person so they can + /// Using a reset token, interactively reset credentials for a user + #[clap(name = "use_reset_token")] + UseResetToken(UseResetTokenOpt), + /// Create a reset token that can be given to another person so they can /// recover or reset their account credentials. - #[clap(name = "create_reset_link")] - CreateResetLink(AccountNamedOpt), + #[clap(name = "create_reset_token")] + CreateResetToken(AccountNamedOpt), } +/// RADIUS secret management #[derive(Debug, Subcommand)] pub enum AccountRadius { + /// Show the RADIUS secret for a user. #[clap(name = "show_secret")] Show(AccountNamedOpt), + /// Generate a randomized RADIUS secret for a user. #[clap(name = "generate_secret")] Generate(AccountNamedOpt), #[clap(name = "delete_secret")] - Delete(AccountNamedOpt), + /// Remove the configured RADIUS secret for the user. + DeleteSecret(AccountNamedOpt), } #[derive(Debug, Args)] diff --git a/kanidmd/idm/src/actors/v1_write.rs b/kanidmd/idm/src/actors/v1_write.rs index c3dd94366..e009f21fd 100644 --- a/kanidmd/idm/src/actors/v1_write.rs +++ b/kanidmd/idm/src/actors/v1_write.rs @@ -778,7 +778,7 @@ impl QueryServerWriteV1 { let intent_token = CredentialUpdateIntentToken { intent_id: intent_token.token, }; - + // TODO: this is throwing a 500 error when a session is already in use, that seems bad? idms_prox_write .exchange_intent_credential_update(intent_token, ct) .and_then(|tok| idms_prox_write.commit().map(|_| tok))