From d2e40ccfab152f5e6f7680c74ba896ab4086431b Mon Sep 17 00:00:00 2001 From: Sergey Beryozkin Date: Wed, 21 Sep 2022 17:43:48 +0100 Subject: [PATCH] Update DevServices for Keycloak to support multiple realms --- ...v-ui-keycloak-client-credentials-grant.png | Bin 13086 -> 25064 bytes .../images/dev-ui-keycloak-password-grant.png | Bin 18061 -> 28341 bytes .../images/dev-ui-keycloak-sign-in-to-spa.png | Bin 6036 -> 15289 bytes .../dev-ui-keycloak-test-access-token.png | Bin 0 -> 39523 bytes .../security-openid-connect-dev-services.adoc | 47 +++- .../keycloak/DevServicesConfig.java | 5 +- .../keycloak/KeycloakDevConsoleProcessor.java | 3 + .../KeycloakDevServicesProcessor.java | 107 ++++----- .../resources/dev-templates/provider.html | 209 +++++++++++++++--- .../keycloak/client/KeycloakTestClient.java | 43 +++- 10 files changed, 318 insertions(+), 96 deletions(-) create mode 100644 docs/src/main/asciidoc/images/dev-ui-keycloak-test-access-token.png diff --git a/docs/src/main/asciidoc/images/dev-ui-keycloak-client-credentials-grant.png b/docs/src/main/asciidoc/images/dev-ui-keycloak-client-credentials-grant.png index 2995690b656265b48854ed852fc7f73fdf90c1cb..e33fcbc4439d89e763eef756af7157de0cf3b13b 100644 GIT binary patch literal 25064 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 literal 13086 zcmeHuXH-*Nw=U|dh$y@kih!UHM7pSebQK|l-g`ge5^&DhUPL2?EYPS-;BjcFHa`uvG$*mM_2yxp=0SM^dxos;5u!?HNudSle4{p6t|BIIP{HMeJ(KH_C z<0~>w39ve1`RBp0v+aLwSYKYJt}PAC`#aCY{yaLt{p!!)uK)diPUAl7vBOpmE`R*< zUYdWmt8+rH#8TDAE4OK@NTW);-GYZ$$n~e4~+1xt;Z}QeyYso^J%Hz)0%lP(@*{>UuB%K0_y!J;F zw59~Tkos(L?zJ~;zr6Vhr!L%g!410pUunz3i0)zM)y&(PWa3b;!SAO-`8tYKPJMYwDdMoC756;L1DST`2v5d`@h5d5*l-|p^lI$Ms z0;Iga54d>}YGmk@=p%k$@Z9z-mk>C`gBd(YB$uIpk=CK0=L8McdK-w=Elb>hL_E-0pYXk^e)~Om{ERsO89etIN!!sj#UNzLvqr)qpXc_Gh5ZpZjijl&w_s=yEQj~@@#5Fxw9iqKcO zVO=?>D-1pbXRP{pN zs-S~?E~4b)mtY7F{bJD;4I<+sJN3e5HS?`kdkiXVOp-(_b>#fXIJ8-fFaa+F$LJCS zi0?lrA_w2bMJ8U$Ly9{hS_^xUgZ$T*isbib9s8$vk@`K*u&5;c=|W-8*@Zge33-o= z3~A4$Lh6E17h#|=iDA!uRCj-oC@!#b*EUl+NSRCA6+KnZU6Q7C32oN$0hxtEjF^l& z_t$4)%p%}HH|Glo9xswU!&U-YGZf2;sv-@eTteGdMGRF7x{dU+ z_m7b~xI&D(rt7otjqUQOvIbxdmF9VIA3uK7&-L`{*_!IMFX9JdZFd(oLK5>FvV$-z zq87$o);mJ9;9Tqro@TT@di1F0b{A8UkdAD7P)24ZI=DIHfU#=vE3CS@+O+XO7IV*m zsa7@x6*PzOUzrM%u0-S|3#ajGqzy^GbFGng@`wh6X+rh8A zm&Z^SEx(j6R0Pe5L{ofA*@jSgws;}kX-0O(nO|ke;(}8G_$E8-2?owWU0yZ&y);*H z=a$%bvvrDc>?Kj^(bB2OYDy9|GenzjL>mfQ=4ME_7kkuX`EM+kWDs0eMa)&QH8O=@ z6c_R-jr~vGdTS$^O>2TfPn`KxB+NcsV!51U+PrF}5q0I$XtQ-ubH-j(p;mfnqlMpv zvuATeCjE(@I`vjFuWKTV(AxWfez<}Ft?o4Wjg8r-1__11$e6_m;*VyzG>Pr=)Kenk zy%1TQiG385!^l2tG%S=woxf?76NV(|Qmi}(4y}x# zO8#ck7Vji!FZ-fSJp~+QGC*htqME3J8VN4SkSa&4Jgal}b}vUx``H&$4O#u-O~~rumIcQ;Vk%{&1w{2?44nMz1Nw2SQ;?R0(Jj&7i%Oluy%Y>$;V5z|SlCJpS zVGZ_5*G&dqjrjXP6h{5~r;nJ~|DyL=8V12RqU!My2il@cKkO8C$`+-o5GCrV16`>+4G?~hLiN=W9gUq0u6GM-J@K|k z^OD^08u0@!8LSbfT;SGM_f}S;?Z)F#`la?~$)rKG_(Xm^W%BZbnqqjY?ty&Mg$ox- z-@m_%L&McfDjvl_qFE)3<;9WwZd0G?12!#639jWeH7O`m6l5*&2n!2~To4g^hFucz z^+_=G#qo(^)*zN|G$ad|le>ll2^4>j@GU#w}rrHL!?SUNT%AMfJJFB z#9{RHU1{H6?~+B#O5CiKO=7S*Xyhp-q02ACd?p4hMEc2UCjt<$1Y(v={8SiIfr7t@tRflIfyq6CbP*I?i@#3khA zomeNGC-^3G=I6936Svpq(iD8E35C+~BJk#1a5e-in;YZv3oo*F3uUIiV-IK3pl|;5dge8|iff5g}&RTc0AjuPH^&uzhX8E;u<8 zQl%<(v*iYV@X!@Mti@iy-_YIpG^Rv=6%T1pH{EX=mI9zxM@a9O#~iMrfjs!w zqGc=wEz8Y)&#pI156d}BXp3Y@>a-aMi%QY2cDiW0vOe@SrxjNTvrgiNtNOXm>6Yax zL13wJH#@gfh*BL&drx|@v(NH(+>FB@u3AG-+)2Byd~c{^ zP&MOrnLz`HiULz`V-^vMN~EM+FNdK*Lqh{pCX(-}U0$Z^zoXNKKZc!Z_F|o0SSa#j6W@dRA`z7^e8%iO& zXX{>vX2#dFr0$tnBE`_zs8rj+V@`Ca!mdvrI4Y(UkKDD%W`(<}OHC?1 zfB0$eJ4G%4xY_9Rn%pziRR7P+Tu7I#4wjFFEOhzK)r7h)cs$+_Z;ov;`Zn1!;xQ9I zAXXu|NCexuh?M+i+h}~NTSTAu8)+}%?LIeij!PW+6_3t1e`{C&>Es`Y>?vG&>XcQr5jk)=10qr??Wq z(arN-{EnK{NWUg4YaXz%pI?p6%NFt4_$K8?=yWE_l$sSK6Nkk_!*?-%Jo0AdPb+m~ zB0q30C>ft6V`nUIo$k9*4+%e8Ul3&;yekm8eqDP`)Lb6`Omqy`n2OS4=eW)X@*xIi zxo-K-JZ2Ix*N$O`No#o=SM9W?6TiN@?a}1Ba!=D$T{7ZA_A2o4JsILqkeEd2E^YqK z0jIHQJ^i@pyI<_+J(o=C1~?2B>SSlh>DOqYZ+B1g{O+q#Gl!d(RyTmIw6))5WcFaK zzTLMxPW$5Xat_(=^r=$=Q7oeRwZ{CY#h<{!l_D<~PJo5XUH<^lYorLkp5DEyLrjFQ z*x4OFe%!>_!y`&+^duc!T&GQZR1{fWq*p|Y<7^Xv;z+%bCI5?@n4gL#_z}!nV`F0| z=yI^mhFA1ed#Rw=(io0yjfiu6hQK^ran+D$PAPLK51Wy~9)(}&1>J`%H~fk zn6b@9YOs2evxby=e#xXygqr9)Un@O&RYc-L*mu&#e(2f69<$ zm80_Bq-y*@g`H~3RgG7BfkuDa(@yX2>+JxvZLj(}OvFy$8tihIS9TgLJ* z+O@8!sfh{^8QF(ob+fqZ{5tA;(z{&Z@^Cjx#Fvdi$Ks8w#V19#~K&kEv97aY)Qnw+)KB$&x-ImPB z2Dszr9-P75exYD?u%`MYy6p{FpV{{$S!{wm5@Vu!P&AhZ*1j6$be0U-d9DoD3d0-k zC^gcXRV(g%W5}`!Pv+;T>g7xY^pIGzcZ?O#$8^XbX}JYO5eY>g4mgVA z3cZE74A8o;GsF>GhjqKzzI3KShqu}5X4h{GSi`4?^MXP3p3)&dpW!wnv+om#Q*5@09c@u5LU{ z{fn`9@{2Ph#Kgwpc)fE25mzESp-?pUX_L*<%Pr#EZFr-nR4{g1yht;_stX zAz=Kz(fb25nw|gl?fb3JnBg#b7O&}9jh<8)OE042z`Q~zyN{0#0Q4%**h{e+VkOiF zy<{#$-V5)k_u7dOv8XQv>`8H8T{+-FM?exL2;v~xtm^C2&=>231u1DjQ&4FwLBn8# z$<7tb>W1@#eFtVTt>!@-249;)&m!XZ`F9*Zpy+4Mo_Q{R4OaO%XgRXL@seHiZ5|uWg;_E6G9QU{b zYwL^CApAsuj8*w+0*vaNvcA=c`;Mwy+FmSP`qqR3q)drb!XwiFghqX=MP>~WWvIcmI9g|h8VM}wHp1BNe{7QuUd_kJTUhvc zQofjgEj0lz+F|4v>Z4^a?eZXW@zcKeWLp2Q0B}uIiYM)NCxnXfS}a>~I%2sxP@*QX za^i18EQO70KfCL38ckG7NU$lm#Vf~Vz6EPTq#nR>uk_w58EmdnleH5HL=lk1uu$n8 zfB*+a>9VgGsIC>~g5jLZcF~X+h26-o3ltli8xJwU^ya3T#@M+oK(-@KJEa*QwRG;QN6ARynoRP_xy6 zLX9=x8NmV~^;eDw8#mt9;#7#!x<&5+r4+mIG@TA8`Oq3p+KNb^o{U0`>>MY67>9=? zEdIgsgNfYHtkT8>YRO+CU5&bZx^4k@!f!H=4;<{1+1}KG@&Ze=^J@{fsj$U$qioFs z^B%JrKq6$i+w@_^ZrT~&du=K&zP=Y8?T9Zy0jh(=HVzI;yY2FdY9jS#(X8_KtM&t5AnK@>+@LM5EPC*jZh2xdW`7BnViSj}I|61{=} zmcb%^>+tpD)rGP0lEAtf#PPfuK-lp6V9Y5GDMe!PX$@1f1Zwcm*l`M{GUI@b>hhVo zEo@S6zQ!UFpNY-{(S>QQPC&0dF`R+3I4r8UA1RI?B=Oa>M{^d0YozgWbIuPUT_Lh(Up<<)N0-i2$ z@V2}_%|!UbUg0eVUBps`Ng8GTG!R#mV6yRViloT%{QSZHIv>&e$z@w3SWBZcV`l5W zzSBBpgnB)|FBx+M?Yq_l5(G5TWDSb6cA2N;gLW7PDxS~?XGnIu&uVJnRPf7n zl=r&j_RZb^%e?mTEC@X`2XdRs_>`g|yGmO+i5n+qz8e9NtKMxbnYx1Dcp@E>y67f( zsZE#T{xZ1{#}9U zAIa{&uXX*?6;=I{boq8Ym+Q}%4%n!IUvk^U_L;6EQl|GG4ekeii9#lcC5vg$9X9)a zrpf&?&j0F^UkBauq1lq8W1zzYwLn)HPpbaH98O{C$Isc^Tl@*#W1Szqded1y@qyfi z=(Aua^}{Rqlf?DvpD!^`8(wAzj?E@cRi$?&i6`VdJw2HC#Al`%&tt2SuFIdm3;S1h zS8U56U9TkymUiTBRKh>9{>o*!j=7x!$V61t2Dl`BsW(eS?(+({vD+3hwjf|G6=x0i**ASYb-A2{sen1hjCC@9U)GUA7R`bHw zy6KsC_|Jn_yj)y!IH~t1>CUz9x^Ed#H6>WQul=}U>+v5lokE! z6#%#cNkjm;;Y9K5f^=600vBGW4-d-ZSAiPVRl^Z z7&O^AmP=t6aA5|sp{i6}D?B=#n9|x}+La<=ne(uq%W)1PCt!#y4dl}@0IJeZwc^}0 za?SFnQnb9I2tV;w0nk+E^JdXA2Jg+l$OrQI2iK?C=+(AUE9Qm@gZP;EElh!+qF2M& zI4Md;jvPs@r%FsezKSCC8VnP?UGQ~zz#&}&B)4g^ zO`LKp8%7+D9=VU_kIx4n6Xl1hrshGBwoz3N=egxT4kh2gqZIw19{sN_6&y%%ZBEPklYnzqV$QWuag{r#=9r5}-fcESA1ACFhfP7sJ= zO(p0Dy^tOX5#hY!)?f~Y8&tlmK^m6iQ@luBot--I zl?U(dW=eS&3MPwGtCP2ZI=-mzmtE&VOMfqS<5`CJF;@I~+ z8?Zpmuz?tO0~3&(0Nlx4pPMj1%>4Rwnff`v+QLpToEpYLgA*Xa@G@P%rlhTm-2&Mm zEFNf8x$aCTdypz4jcUAKVR1G$Oq7xL@81U;r5O-$VVs;xNWwG^4CJMH?9FCqSwDBP zaaS-3X|Kf`Xe_6o->MBDXA;q9bo^BfM}rW+-4E5<(!+ECRIl{yypeg^Pqhj`X(YHF zKQwsOD|bJ#!l)w5c%@^>F;^G5ae$Y%P%|K!W#s zKKEQjHfAheoMBEwuTeswmrz>9&^{g zgyJE9`G9yLogG1Vy{Fj5&C7sL?9DV<3Jfc)ei0Tn z|1{gO6kDdbXi6Myj)rt9OSt>^7y;fDy)m}iYDiv^xg*!$gL@MT1%!Ro; z8VIOvF>!rY76&W59owo9)oG&}CcVAAh7)Q@ zLODbroq^OY9wI3TIHBA2YvIeeLsoVO7TXCDpzLvP+|IAB?T4Q79x3f|06u?Q59k%|xyb7uu z{F(oL`)s@ET)iN5U7xh1{-ocM2l*>-VM8Np%=h_krmEL_FZvXyJ8+V9!Ipw`6X2G; zH&*_rDi8=>rpztTuyUJDeWVQ?wUEGjVH8L@@~=@SMCHybxhoI2MgCj2hRU6R&_>o- zGmL!sQv1WRl2(o}Dji0=JU8mlNL5vNtR5Cl3^{nbjoiy--Uv&CL3Zul?2? zxGE1mm~QGoLE?yDEaePGX=@8-|DudfrNbIC4ujVQ3EHa)^tgCXrRzcP;zWxjnRq`a zQa68ALty|UXgHtu4=%}gn*+XaIKN~tQO-<)dM=a(V=r9bD1E9JPWrY@Umv^|PEAU1 zfy7@kC4(W`85aO~Ld|GFjHNp5Xf`=R0HEU`nesu(ec1{rKwF?Dw}3u5ScW=IXOp%% z^#t^vbRQi4}-`31R zGCPk8I>bYe@ImOYo%9hWShjqop$NPbrl$ZxTaT@s9Tu?2_TNV;3~IGMv;@lgdoJgu z*SH`-nS;BRn@&Zc#t;fBIe9S6c!qtu42TT+HQvHOHA?~13ZKb(Pu);|uLJjnExVII zCmCB~!R1>uJzt_0w$Z$&ktj5tZ8mQShG%7Eo$#jh4Y{NcU=p@A>r0x}%#ug-pTCOe zDL<~7c*^(OTrcbxX|J9VRJ$3T*P!g&I_4vr2YOO6SwdvOgJv$)YB1=tf@Oc_h`=>c^BTs{5a=R?H+bf;ebW03XxSw=~g zZMopIuak!_YCPW3p+)#P`_Ml9x!8M|_^Y<=lg)F`%ZEN?nGXEZYbPsvAYa|ZzF{N0 z`owM&VB)SB4Xf8LZvteu&FkrN*pJ)q#~wPE($txSnFsa_)ULqY+tSnlUQfxx1_uw+ z^^P9i{nzW^4i^k>Gf(I6J9c32$@8T{e1BQQ;afgGuD~$tm2=AV6TZ;otk>kmEulY@w7 zB_*zL5GFj*IPR_R8(WhgnN(R&H6yi%9U)_ag6_M&Q=?Ao0SDC*pZw)1`F@wF#NkLM zsi1O=*x+2GLh&)fH&jlm-rEGdT9-Wn6_oD--Z~taSCQoZZ9TuQ?clG`$={D!eZ@II zEF9o!&3`R6P$#cD_i(mcEGgerKJf-$ocj6v=7K!eyo{nsY~H$O{)OLVl`RSS-`5Q4 zn$UF^`k)?Xb0VLYpbPv3{;|iNLS=GRY+T{C%6?w{C)Zbj7tMRkmzEx66;@VEqRJ~> z2D+}!2FtQp1;a0XvrH=Tj7z>1@4^uO464@RnIvH2mtH|fbLZnj8|qjU%$sCqA3q$B zFBx;>hq^ns1o4Me3^}6xvX##8LIX-R&ds~M)E92J)ez&k7jcVV$6t~#^j>W>i}!f* z%kglvhYlWs4g~&^?h~Eu%0v_0@p0v@>q`FTxHZsL48HZwi45Npkv0kPSl*_SDa;(= zBWv8>8v6?A2e#yNKdU+1xme;Z;Xo=dS`_c%bFPEP(N`_KXhKVUri*&bhPi&QlN!6O z$X@a_Wj3g~I!=}&zZwtQJet46`(+|Bh&OY4dNMl%WX|G;+Y?foLnz1&P6>CGJP0Jj z-CBn_IPk1hPxR&QI^?Im$mj9-vJ*%~c`jf)_ew5sTn&2;J9~BB>hZd>&Fb}7T@&wn z(#v+=hXX47R(^mtmM`%_@Y(si9hT%g6={zH?pD@>&Trpeb6MhozV~tbr4%lf8n4ne zpq8+yv2WqRzr46NY5v_VN?*KTs3_47)Uxi+ zzbOQ!_?z(&f`>^%)H%c&p48Nm4#i$jN9_9z9(Nd}9Vn8Y)wve2nBQ7cpfFXpwOjxl zXnQfR+CKZZO(ye#%Z(RzK3L5@ft115_daKtyKC$^PUNHy@03bAb52?#toOGSMb}=w z5oXET$g}sK-&P}?72#WgMH{6l7M;8J<>yze5z8d#oBV8S`p!w3_d8GGsCBdl4|*fM z==ro8Cd*@3t7OsX+jtlDg2By#^??V3A|u9tRTW5pZ4y69qrUevgPYr_UYT*f=Pbp6yE534@Ss=!icv+owD?$o_e90 zU2DwdvusadvmbH*2h}ZkH846UwtmIf-Q#*J#ZPWMVus6+!R=IEq$x9J>{mLPCm~0H z@1mjE4OM!RpXbBdmp`k`vq~DbUVB)lbq~S_Em6A5-=D1|MB&j+qf~hQN={TDqw1X= zI`FCKuIcBh%yFu~CDV?@1eO#eYTL-D~rf7~VTccT>yyD9w+cJ5*2kn^BT%SCW(B zC!CVO{{@jJi1$`T>#1beVEm8-~%r*frVN--$v@$wcHLCc?C zyOs{wxx`Y(|X7grh{^mOvbcS{MLe*8j`Mc^0mYv9yf_~Cr>E2Z=H5`a X>VIGoy);D+KMqsUypOr};MxBI`3xTZ diff --git a/docs/src/main/asciidoc/images/dev-ui-keycloak-password-grant.png b/docs/src/main/asciidoc/images/dev-ui-keycloak-password-grant.png index 6a811b158c53f1f3e446c68fbca40fa3201c32a7..363db5c51a52130ff6881de6743138904965b61d 100644 GIT binary patch literal 28341 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 literal 18061 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 diff --git a/docs/src/main/asciidoc/images/dev-ui-keycloak-sign-in-to-spa.png b/docs/src/main/asciidoc/images/dev-ui-keycloak-sign-in-to-spa.png index 1e31b0c1c8e9dd9149716dd0462ccb4eb76635fb..4ceffed5df1c5b61f06a1a4866a3ff71971ab2ec 100644 GIT binary patch literal 15289 zcmdUWXH-+$`zAKH7W7&X5Kw7C1e7Wupdw&EIsxfkDFH%JsssWm3Q8w5=^~vZM0zt| zqc?#RI!Y5llM(`<&5qnP^I?87YyH>Ee3-Kqa5!t9z2Echw>{5$&Ko@)4fZ2kM_5=` z*rE6C8nCb&YzF5of3bq!EKjPeV6*PoIC>?O5Qh zZZ39W9yacFcCH={Zk~$=>XlhoF0w%H-ZpxgIzR0Dw!@CEX{l>&Q`x3b*>;rGhI7+c zK6g_6=Jns-GtIiZS+{6!n}iyzT-kcQa>G7Y-=>r3TVI4IYO3zq z-W(nsP3rZS>?J(lJjNOX1YsUW?OYc2@13%ET)ueV&*?KY{{L`RD(2i&RwkX3oqa`K ze#4c#HZ+>dmX?`>ZR`<`P`gKu-uLwOPX73D@x+O!%aBuh^H-UlI&~^8 zCgzfchDLR5El1yCg;aA-PfuKWy11O2T>s!8hhxm%&`-l-RH~?-pP!(hU`uCb(WfNa z%Hg1^f`V$tj~_3otW1oE(2n6?Y8@Oy?6R`5%!@%mK?Vi}N9KG6pIw!gH|6E!eQC2d zWSvr6TpSY;(j-PF{W_zyckzMre#!q|&dfbHo}mRr3h4c|5pck$U0m>5K<+4Ua= zD|~RUXKyCEZNcI(q}CO~Qr81sb3-tE-A?f3%lwN2>j-j@$)r=c=X!HYtt``xz@b@j zsyN;C$FrS67$$hh%gn4M@`8Nfq{>!4VROxKGStr9(^J~!)!yKByy(e&reWtgh)W~K zeFwPZj+3h>LJkd47-GFOpOn$woX>V^P7&BlQ;fv~p&Sxc(vH^kOD43rVG|iD(M0dD zq0+|cUunvy#%x_p&Cpz(i~@VH!9p_}(rI`>nLt}RBPcA)abx5gG?rB2!p5WW#NY(Y z_pZ#WtRBXj?zC}2MfB1o{Vu}qk{2&h3ZW~;$;uuH$5>UnRiyWX428Wp-mH_VAO;mR zufP_&bPUkAWFKXV8e{WyImEt)JI0%}0ud{A>)6i1M?v4j|msWk=l!JJ;Tu zb%3{9POHB6<(t?e7rHt-t=_zWBK=yWBLZDgWpUP7n$Mqe(FYDHNm1p?U4}KeDLYu< zkYnT*Q7YZJ9reTIaJD~U+*-NIu97HW-JM)MOB-01o0yy_aJA&Uww88% z*7B9K%X|7rQjz^7ZPHAgAFbufMr(UJQ8*(&2-@1xqVK8`sUGF89>m6OG;1tIBgU!{ z$3MH8m3kB0Jv@$L1%WT>o~Zla9fFYPDn+?TIu@J=nEGv zlp*NpwcFi$`uQOaIq4To_`MAA9l&C-#47y{LInBS3k$C3?0Ru4qX&J5*q>(OC8eYy zP{TtOusm;<`N6bbtPQ@pj9=-`&q74``Bk4hSz2CN6916?BbYrraE(Tb5g?s7 zB3aSj*Vo+EYk2*7vCn$;-kMh&HSgY98_I`k-zjJ@gkJ&S#yVi_&D`8v`25L}G3acO zUVEq3vLxRH!y3Dt8!ZUq{YqNjUtD)pcBgTTjnq>Q2n4%*|xh;8izo z&Qrc(+Y<5lUHnm^pGK|6tpaYxi^9-^w6r?wrL1#eJF5#ye`%)T2ECnH+v(EqsWUK~ zLI1zL{OnZz-GjDrh~AoNL?PU{%dU}QPfS;X%d#_FT@Z=-r!o^rw~At%MSn@5UgpPu9Xp)6`wpKsNF>^+ z(x!pV{i4v;*3JZh_~jL;wKri=lqig`)+sIiKaqmvq0yrQB?{$;0z@L)>h?09=W5>* zo6Vy(>a%mz9>}qRpJuhL1lgS$Q`HcqEPSFr1P+Ho4PqN31fae4AG1)KCmeu(P&b>i zsHE}R&>m_=puVk<(UMBsp*N9lNGY-Ke0cqBs?_hp9UG6IN2c81bXFHa9ZfI65ZGZbFp!B^ogX}Vd z^|24kPv2&p`5t4lLH1s=$VaYmXVa%T>$4QT@L!g3Azx5ZuzkxrC#4sZ!CTOf5r_ju zs<`{?kK%5<(Z8Jdz=}S$l2z_KjMPrP3Dc_Ixq~L++76UdmiBHP;zP8D+1RZuyh%_Fya3#;v*Yg4wAE%EE9mZDezKbu})mv<(;B zr1E>M%=F0S?ECcd(zhnt;z=XhY_!iB8TZgFpO3yOMs^@O%&Q&@*AC(Hf^X(ltv^Lo z+a?L!PtNuAux}md)baK(|iOfEbJ8EQDnxt4BVi zMpED2u*(JYLhy0l`{}&A3Vd9-67?H8Gn|}UOT=i!nmt?DwL2N3uc-s=R*K)hg4&(i z(5tSgYOas7u3O}gD`mCiS)708k++;N$qxm>_O@iPt(5stpJpg{eOyeS2h4TvLxLaQ zfk2C$w3b=!ra)SJ;wlv)k@V5JQYXzHF;wC^F4k0Oo7a`vTOb9Oak!=8H9w?}K4Vl_ zQS?&diuBwIumKCx0l?jz25VjgD{WL2cMJ@eEw=CI!MoB-I;f;<1U>w9IFVRsm56g0 z!F$`==Z+*x8Wt55A?GK5*&%EUr@6*XpE~RPQzGJmvXP6Ktempp49o7#OBeoZYl7?7 z+|kvJ$~Kvucn%`g(I%E&u{eYSCRz|U8nWt8AJSozS#U}z=-94KURQd&fDG2UE1Lk# z3TAk0b}H75e%e7Tm&J=&nxW6|@bJTS1O0*+v}N`tftlgzm9wY0F?9R;38kgIJft6U z6IX;aG;qVeF-}I9Le1xA1)$p8Y@^+%KazYns8pl$ZeEc-4Q`ad#brDZ>hE94MEWfF z!;WC{d53wgAtK~1UsR0=)4dlb;Opy~T(-%0x{KQs6cD1;PD08(=vEEi8k6QW;t|*0 zuF~op+h-H5niuiZt`)j1@&;m#gW8M0SUykK-0@eEnzGwSTsC|h!~j8w8-_QVj9mPa zKRyK}VZy?M!u|BS!hKEg;elEi;%^~Pq}`UeOYvNLI_`jOqdaeI+=GqM zfeNS0(6geH zq260@2Gah%8T9$xj9b0_qcz^zqHpPs-ULdV@bQ6~zypS_T<%$&(1Sn_lM|c>bN8SRGSKUf(~EhRVqx%g+hq8AFzA->)(w;(6H zU-C?~pD3FqdX49XZBLy`lXxseTwF&}TN?&Uvv^+f=}TyILRzd?i|0)C=ZD{Q>#?y$ z>!yy%BO~rlyvZJ2$9p%vUqcZ*`*}!DwkAY6p1KuDx;+?iMA&30lskzE3k#1vWB((; zy^dsA@{muS<3erkvU8uc!G~|B)QZ&03z=D1tKR&QqPb$c$UGh-k}3K5V*RhIW;^3f zsOkwt8uA0?(WCLQ$4eZdJU`s#42%7Jt81$r8wyFwG@8DvYmqV50#`^kBJTu+l>2oB zz%cGn9|?pbF!P{yHPnIXtOVSH9H9uVLVKFitHQ5?ZCZogbH?}Yrz-eRFM>_5JbZ!@ z3QECjebxTK;r?*hKLTHcLQ`eD`BUUZ{Z~57y#&`eBY9iKYLuh_gdGBp(%I#*ob8>P- zs{TQtDz`L97(*=@l_*Je|B2TcC~*l<@R_@qfw*KwP$(~(?BW@yu&Gq=cF1$L(;BTf zZo}%L?BkWVtD8~j#z6zHMe6yG$P2xY@zI{_!{gwYr;8#F{ZZ3S+JdqA6HIuR z5)*ZT<6-w-|KaRL!>NW`t28slWJu1G_#STibWrL)jQme`|L1ELq07sU4exqlOG-*R zEcc+;hg+uo{h_ZT;}b*7i=(t}u|m;Nd9?;TJ@Eqd^S-oCf7Om*S|`r`oy(RU_BD zL*M8Uce3(2ERX+r@(+Jo@wzUrEK6(M5V{_8?9VlpbCI03*FrqdImV3BZ2kS{ls_Q)*_aI+0RdO4Z^(-_9t&YR^}mEf#uj%B z{^)2=(lF!8`%Bhe9we+RID1ihEX#wqM6Xm8@J^Er`Pw({9X_1fOI7fiDH2ZS5{HI{ zg&6{fw7Mjmk(}kcH^CO$TcwMN9&4$8ZV|J{{uFvv+Wp&OW^oOiU}m^~5kvX9?YXfW z?~nI->`DA_`v9n#akU2K08SN>v6$b#f7iMP?#=c#!&EM{wY9b9HC#hPLA|?;up>+C+`J<$i6in1Pf9x8MB8G{u2Hux9)?e3O zI()cMd6w*^$3%n6L=nRBz|%u=E}2O76lS^13CEzWE%GZZPhW%@tdQqPIeuO51N`@v zj$^S;yIrwCSFv?*!Hp1(9M53TXFW9N{5AyF4&2Vk3yvbL%Z>I3AN_@~&IpN5PRL~n+{F=yEwO9c z%7X8?2RuYN>^$19$=O=!2wn0Du^2bi3S;ZC`6phD6ft`b*3yrHa_U+rJX28GqaGK{z z#f$H2X~%|zdBhC6ZAPZGc67jMD_j7%^3RrIPgM*EYUR71_Qmd8(oT8%ag9zlvA4HR zkCoap{okW@jXH16I*BX1Hl0C>H&Lqzo51u6)A9WFhyI63LKJV0(# zN5`eKHE#Jl8u`*dr8U2M#O*d)k%oK+S4mU$DC%o$@1khcQw}I?ibz4)uwG{xe|Jkz zJ1X;1YWLhwQvk?|HOmP-&Z~e0R(9F)%lhY3x>1ei$fhq6d8YsTr+O%e*OOCIj~4bQ znJY2vT+v?B-*rau>$mv=%JgDKQls56eEGzP=}LYwi$U@L@qe7$-oJlK&@zpa43JC= z<>;2V(h#P$dXL|E_e~OU%iC?!yU-Gon-EZYzeDv7abqV^XpxC{Jf;HjHx);G1|Q!? zCx^UjZf(`X1TaiH?j&;!W@Xt(uME?r=L&>jBG*2ArEN8nxGr;TOcA%tX;uXI9AH6bVsO z)Odcj6*Kx(>13YIbbQOM@_hbQ>^F6;t6huT`ZNw_wiFEVsfld1L^n9ml=ga0o zU}p7CN-y(gO-xPY+G}$ozGtB(r>LSc)Sey@snK4nqnqQ;F$vEde*k>eo`JkxAaSlE z79UmFQl%OkVIZPnt(_u$`>RI%l|U60!Up5P_@?>JP>~(Pc;-uk*7Dl2(V(#y5w9!J zKYCmHk120)yp_3FT3p;6;sKxSZVH}G((fwpE&W@@ap)dv&}~2ZJcX=MS@0z5p|-Ez zqs#@9-20BSMT&;C#D*~_8J&7_%g4sYWCDLSX=>i@sVbHj)<*@@)uFR>>(>oFvvW-x z{{1_Ul~a0qm`*BGlk!^ZF;%3`ky=TJiHYg_Cf3z>0i0E-)yg?>W4bsUTsY#6w?RT0o9Jd>_se`q7`ymOG^ldho*=^sFk`jZ>3fyuy4>t$?jiG(M zafB0>{Fn&TM74m!8l`I27Do=t%7_7+q^v8$GB&rP=j9WLLdWrk{R39p47>$Fy&OUQ zPONN%$jO%irmlXLTAK8~ zL1TYIdo;q7dy~DmNkGXYjHOnhxOMlhQGZP7ug=-wnOIvpJ3+--3{8Azi~A6%00)4A zUbUoMnRA2Yd|$bSrQ+`HrtgA(K7hESTKJAs(@tNFC8){uL%eac->N65%ae~$E5q&$ z4NZtuDP4{lp+CF0a}+o$)Zo?fB&|(XWqMp!nN-8hUH)TS4Y0B%4;w<0SEmlreAh3H zUrqV))Z@#nsAWwVATWaJtd?;WmKMYsF9_k9ecVl@1?Lkb-Y$drzywemB)NgAC#U!I zi)H7*r*}3L^4qrQP~fc6#!sJSld-!nV7oE#@$rDWB2{=DW%pZtGVVntlacVX5Cy-5 zk50z;+_!HZ;7sfFw>Oou_o4i>&}Pzz!lNAGPV>RmD+g_pl9G^!*89~pHPrIN47pC@ z&9zNFTZ9b;db+V?xI-IlRBy#&`O)8$X%V>*K@s%k4jG5_@1Gk#{rX&##-st#jXGmz9+jD8%2kY=Zf?uFr`?oL@6~PInkBa!H>R zaO~?uB-BL&dz4C+e5E8m0DPSIXjNH4_9?{1sW$jF$C3_R=FV(hQvk{m6qnwn$A zq?`jGkhmk_`BcCj-J|F-V|LC&TmH7zZCe)Bl5F)o=jF+J_z-fH`J z`=Z$P4qI$RO*taDJs8k+Xn}?X!Fy<(Gc8Wa65HX1*>5Ik}H>XWQAud1B_LYtNL|Jn{R>Y=Mo94be;2^+(053({)oqC&Ddrg8@* zs#${sM1;h3&_`qj-C9Z}2Z|AR#@a#*d>03dQcX<_qml7^!-|`mTQ~|qLsq4bT|8XQ z4bVP7fWa&*_y!5_Nl3&}bff$~Pb3LxpU?ZjdK*cbypE)AZy@d4+my*4t&~}|eY6#X0B(=4)@W;aIO@C20R~gMAm!@yy$VZ~MMN%f z%_5|#T~pt{qPN+i@^$8u&5D=dxa$x6v+EuC%h$@Luf0SJH>cuk%72dWb%&B(xp1e}3P_x&_Mq zgj}UL*$;wC4sjq!AmYxTG)y>C>@BhL+@WU;TgR19m z;LM~Aot%;@cB)n3ooObZ?Q&#pc7Cz|pp?~Lk(NSIBTOFQ(pPm6K^fe=f1}pu3r?_w zI+2lpjnD<#2&*o!D+AP3nu3RM6#Fy;TKJ&u*&~wE27>_@coT?mkuk|n6tVmH z>i_{>UkIz#0IArx>G*sZ;6#C93qW`t@cZ%Z_yvVW?qg#S!24m8PM&h-22mMDqMi)K z#4sa-mzdz9xJu=A!?-P`FE6e2)Ex*}{aTnIvmSi<;?XS26l2Cz?O9+C2iT_v&B?N4 zvyEP^_+^?*`d!n%-6SMj28+$FUw=X!DhRqcH0&jK(}F2itU9}$8(bK4JiHd3;+dv? zd~MB%_@VApESi~v1@p40Z<^SKDjEUdXH?|OiQ1tV$jd7fLbF&a=SJ~9y4oo+8iw|D zc@;P_>eytP8Dl%DrV_T$jW@QpO zM+u`Qn5j!s?10CflaV8h>;aNeLU&+$vJ zoq+aiWQQgDKFpN09{6X9$`qmP^DzLq+b41usx*V`%tnBRMXTd`LvTXW5qGin2TXH+ zXv*A)YeCCJIkX2ftBpFiAcR1E{1R*HHMm*TUrT*jPvfFIeyX4NRHKni1%o1(B$cy5 z-AlZP<0QVGl1M%Wzph2E>_x8ar5^^`E)4X-6TCwYJ+G5*Hj5m)pvj}Q;k)&CS3_aM zjnLBdQ@P$jJFx*-(Rr)iG;!|GzRn7r0g7LIB;6d3RF+v_JWXq@>{$w!g*DYCXOC^W zj@$&S@jCrV|E~HWmQR63E6;*UibdD!4G-PeEGY3il%{GbJ-oLe%kVz9d2A0a=Wa77*h zQxYA{Q@t)6>a|tBIeax-klsl~OQ|@*rt#?P57}CbG2)3(ov2#K_&%0rwIR;{XCn2u zNZLnH_|b}zYwInULKDN8{|Gc0X-D%QVAYP&LCAYs((ff1OO^jcX`VQslpyyDE` zc4!*(m|^0Pd1;qXjn?)K(Tb(r1)mk~Ijjq;t+o(4_-5TBxyCIZCJLC`snf4!d zxBAWNGU8KkrH45}J=+(a^GH`A-C%3^@32G8JdyI5@*yge=hNVQrG1@s$$#I}ytG4$ zPmj$6>MIvrHNj0w>vlQ&s-}p$bkRq~gEC-UnmnZ6n+xb{3Rk3FhfAJPD z>SVx%711~~|dCeR8Yx_*Kb( zdJE??>Gz#kRI_5jN1mHN?^)W36|>u4Gem#`d=Bthg@yPCLP2nKLN-5;G40ms*yeWd z4qHM#-7Zx)<)?`@>dLE8r|@7ejwY9smvnzP1#w$94^>`u_ zaVG=se{UPiYv~-&$tX|BEaZKTE?PjX-EMp1WKoztB42e6Kle5h#80HsIwv4;YQMC$ zb|j>vVREHW`WYD(MUfajiXt1wOpNHT^gC)0I$O@Wt9$J=3K)|?m)Fs;T&xBCd zY)dj~bvVg-^_$zcw9W1v8IiNuU4vb5SrMwwZPH(>K!T1TD;93~DpdXQ-8ImB>3*#G z5E%kJfT0$2wfEkKAw-5#|$fmNJd3SmUa+$z{s9jZw~L6RjXj z!i`4C%jy<>r~C5|R$C)Ek@jueN3?6Qt8pWGwI!EcZR)MW#Kc~L0)57K%B-9A*_VLi zMf*}Ag0%Z}%#Pc=>|MuTO%vh8Qq8ZR^zWaXl*-126e0!~2|C|0NJ9yyC!Bs^vE24P zgn`E|)k&!Pm^*=_A00L_zkdI!!CM>!a;cGxD@Xb98aa`Y=d&{;oXJ2Tp_*Z^C{3P~ z)wa$K{SVeWUZSIBUw7ZW^TzO!ikelE`_|>lMTh(PG|=hTZjJuxekx&s)604#4r`lp z$VI5Fsk>A!!}JhEl2Q2es{EkB3{J^|xunyaiAmUiPJB=VLBP?ymxEOAbWcyCfDrpk7MJ-Ox7G`P#!zvsv_@B#@NJ>?I(7X0y9l3+|p(C zDl#V=@*9K`X6`K83EJgek&F^hSD;Pg82(S(m@Q=N~`+UcW-zx{h! zWl9~m{OVG%8_ft8z+9Ih<&XE);O&WQKCsa#+7?wFUoJGieTx;m&S#yN$Z7N&Np0xXAkCiz@T$qsx^1>zTDdzCuvh zMo;7&l27Tw`WkeR_FEsB8X+>qUrvMMn-feGMNhe(R4qgSWWH5#F+T&t zO&-~o2srwEQwH{+@zse=S@u9gpdeKV-O(L35na1KyYZ{{NUl!jzTXP5(H&W<1_)k7 z6|{e!CB4j3FQ7Bv#G3o3NlQh!*i>hius)NCl(&gKVmKDK3JTS0fLjm0%kxGlhm~?C zrZD|EI@{%^UjzzRAt)dMH&;Jf%3alt%Wf`n7&mC%k`{;QqL&Y<4}PJGHbrNFI^pQC zW`P-kY8Y*EGL33Dxld-rEq~1}1&S8WyX(;XX0dEyRksrB<1=x|=C^zK2p&DcX4qPItjkfCNb2(Kcr{u+^<`0r5}c!PR^Ux zJ%d;&)3~CugR?8Kko$}b?Z2b~M$mC-DLDS(Jfr@s7ts27Fmr$gQ27<0iPnYO?IS%` z!4ur&l?}E*mrb_1lB~(3btG_R-=d@1H3Dqhe!lWgCl1q(^kf@Fuc`A~54NGW5K1(@ zB2GkS#8zIvc}%Ouc6sai%#+sZ6K}Uh_OW~#{Zxw9o69=0AX@(%+v4o8`@^64VXZA19>-DM8Z=GG^cz&mTQ^Q6_|JCb$Hn3` z6%%`&hnR5uu8Z2ytTXsQgWVK$(u&IQ9iXf6k-`RZMM2$SoEO1rJe%qIoX2QH@K&dH zXCniLpU3`0xrjV!*A^BV+45WSsbkcx7mW|?N7TiG(h#5{L%;Wt&9ehO5K%E>_-ToJ z5axaNm*lVZ-K4+nx@Q!D80~t&nB+R9*?vEvGOI~!wz_y>Sng1z9OkE2RC@l>2d)iL zY*bbr*igG1jFu*D;bF)r6=65vWx~3fG`)7p((baNNVwalD_MbC2&Y5cv* zN;S#BP&dhOQ9*gwqWNE7YqMULIn2Ml@vck9AHM?S2y<@V+Ii$=XJ?lhVFPy&h6 zv`>1MpEG{YBlt?tvWNbQJRP>SI9=?dMBB;i+Fg?xFdf|KK(I3-;}q}C7hE3?<78)i%00-0Nwen9jaK#Eo06l-GB+XIiNTua&(S{q<`C}5kuo<6<>4Y4 zWN1;467AQv-OJoH3eO1au37kq{CaVx@Jb)?8{6%>NWAAQmjQmbhtp9ZVzoM#!~@3=P< zH@M&kL93%TKh6zDY}!H%4pmC-I&3LEA)E_@TU$aSq$?Er`k19}Ou_X-mW35|$*sMg zl|}{Ma>^$uobk9r^LJ_{b(%s=MFKH(-`Z_q-Vzykgcpc@b1RM*E-~OOJmK;?m5tgh zI#T^1n2SoHUc>}Qt&G>GzfDRC0n_r6m6EvWJM0;KTTQMP{+BL+QTw{>Ue$OFU;cOF zNZI4bAKk3ddmp4Z^Q;E6$q};*G{zm140fb?KJq9<_!Vr|XUw2g{Sb=PebrZFvmUqc zel^URSe$_O*b749pNQlDnY^x!8US#Jv}-yRJJ}fs7cwz23*SofUn#S83)6(GZvrqC z%HdJ5kL8NG1c}e=;SFyoZV0!wgR}uX9zUgq@8Y&N7DW=tmR! zCqJ3uC6B^Mm|&M5Na;?dH8Ecdvv#~e^I|(3lxVPyQgm?#2n9IT_4egbrLkvR>tth2 zj=sB($7#j=ZRVe$m6T+rag2{$dQ0)7L zZ(zE5KU-Sjw>=)C=4MOlv2G_*=fiKl1DHrCuh6VT)1_6K)c@_nokcr9k}N3O0}ey) zzG!VC1(cMF>oq3a$0=@!K35=ewV#--@r%1GRr}*Ro|Bu*vM!l-xn#t3`32cxU0d9{ z6ZyXJt7covcVXeWSb_P-o7kf*i86%?7Xcy{y(y!KTAX=bHn*x+RQ=(7uMKRVI*zyQ z*FMX8HQ4~$myZo0*$YRs4kxuJT=2VNXSsjXg3!c-yRsHrrJwvdlvfM57$h={gCtjW6XHm<4LgZV0os%z2rkWB@yod6ef&<-#qc3*n1*y=Jf7{zPPe4R^ z=KWMMuQ7)@Dev`LU0d@|0aSTkN7OGl2aRt5xFf^) z7gQseSYdeoAVf-7%kTa1Sz5#*6@VuJ5s=!M&@LrHW0v*HEV)H5 z^6Kvr7lz#a)5RKa9?k#&Sm+y;=k;&RV>Vx=ZWgg0+?RrtYe9iP-T#Tm6MJSd`|=t4B*9 z7Jf<)pV!$jZnU+ zXVJW4e*umo6L1{UuUrg?Igb=05H~CUR4!cUQkC`{4JoN8Ap=h$)oc0yjF6ZPy)#|+@PeV46^(#chUM?c0r{6?kh8tsy?ipa^jfxd%hu7U@#zAbQeE$yYKGJ2 zV!;N5HQh87a!%Z1_DviA=ctbtZkFMGNp{@)U3@O%fpItq5V0ONM({s&`__DhMaLhV z0Mu7#3r_ZJecJSD)n%+e;2POGd0;i?rj|@f+!2GwOB$d^I`cSZvZ{&jeyZ#|9t6ln zS%_&tv9(fKxQbh2>q7envu&DvR=1D~1%5I8<4;>ClcW873cRrt+LBG+o6fQsZPxUu zXqSY@LAsy;KC1Sv2{-44R{=8%Oo#$lC7ItCT*%@KmaofAIz7Olr6^myu+B}4v{saR zBGNzeWxD_~m@$jMxk%0_as2ll4@st_LwjBjaf|5=~+Jhp%QMoSkXuc%QNwW{EqOGvI z*;YlnaTfCyXOcbj@r%hhuuSd_ORG$jw|liado|UhJOyb~qYH4;0B^Ci)bXo&YhuTP zzyq)2|0oljvBX_rayNgDGyMPc&+!2Feq45Kii>M+3c)yeNq%rmZ2yZ6nSVdD(!Anf zs}5NB+>r42`cnM=;ONH}=P)yuY{F0$;0}=a`2PR%JBDR1dU$!k?%a6+I=7)& zynFh4*E}&Xaplsb+u)msLu=J8x2DF%-iL=Dv$MB9h2CpS{IKR17S;eQY0#UC4hz$I zzU|5#4ce+L-QD_7C{$BNN4)3q-q2^Y%rC#dMeyE09B8RO-^POPNHVX<-Ph7G)YLq3 z>EBM;&RGjf%gM1Z_qNCPYl4{kH}hDR82i8Sp=R0cz7pN& z#+yU?m-jCIruwVz@c*@IwqEIiyu3LY-Bbo!Xel|eKg}EH3WH&8Wb~?`p+V^9q!eKS ziPQfyFkm90iMF|a|325zqb@62zrL8pAJvkxxaf{|AFcdwBh&hbYHDigkJVMNt^@l6 ziX?&O-@ZN2zIjt=J{aB@5leKF{MWOv(9qDRN)%7}pT7+Gfqipzt8@9*!l=2HJxB?^HB)W*Dl+x4pIE) z7%I%Whb}#BojRGCdUb#3SCe~hqH|UciR|BjhB*IM+r?fy2=q1NgGBst?CIQ95syKE zCO+L-C)$$zFfHaYq*9oQVh2U&Q6NB)U!KPW-JVe$r(HqLggkR%q?Oeiz^-@2CJR+u z1_r%ZwtUP1a`{mo?)`|%tH;MV;x&zbVEXCC=FZ=R_}KyqkF7Pf;Ze6uqpF{0?)nm( z**}B~=_?e6xsp6cvb)UQb?OWAG=4QZQKa*(y-R1x21L>)D2&P4iOsF1$10$S>cBEf zSu?{|S&KiHbgb2bQqd=Z*p@jR8#Ug_&{Zo#sCrPB}z_K##6E zJm&?yX(yEUkNa!V&-R<{cpcx3D=8-Io!K_aLW-j5od#1jym#u0RbdIMrQ2vKx$vaO z$gNKPNwWubm0eQ443A0EY>bH&VGmc&VfS7d%RA?gI8j{gmT$1SE%=E1 z(8`yEYSk@Lw@FD%eQX7{C**%FLH;zMcW0}ntC43Qt}s1fcYH=P#zoO`dh&y+6($!i zW51A}J^88|885-$jU$e0mBoxTJ~w<9+W6r=o%Wt{Jqb zPdNDUx9s}4^tSbgluNV|llsbm`At{0Gj}~mVA^0A!LE6Fs4NwCYxl1G*|Dh*J+WVpfpB(%2n?A!K=83CF=S>xyq z#G@^0+xxSu{#3)Y>_W5!*3dVeQ1CgH^r9vV^~@vOz|xS$_i`N=Sav5fp04Ys=q<=sS7L$6y-I13P93jS(Z_r$~6;@Bu||o_Qda0 zYb+g!L8=VN^ilZ-uAe<-UjW#NB{;Me!EfuBo55VVr%~4RzWK6COl$mA(x}57Oxjks z8w}SjG*XF^T}mWlD(*)4Dv&tgNfO0(UC!&%w{%dP%jXn)4MpUxlcqq>xkC zdC8CY$7=)D-IU2Sjh5#=2@^<*AcLH&u{A?hLcBC}XrQWif40Rrwqu%?#H&L;BpTlp{)c_~M#o!%&GJXS3%WbIC z!YGw)oa`Q3%_(qF$CjpT43vhQvUmncR|;M`$U^;nLTHB)ri(vQYK|yB(`DFSk#kIa zbWUt5aMLxIe7plJze$9kv$iwqBU)YTrd$IQsW%$ERvb{=G5uZ^y{{$AVH_HB0e>Me zNcy9wtjXORA7@FIYf+PFgFDv~&67xQLA^YCJxZcr(Px+})Vj~(Iho^@TkGsI0D#T2 zohs5u8+`e96&Wb96Li3STO+4OY>81w&o=RaW)(2%Ec&0kmaR(E!;IgN!v0Zh1VnpU zBjTlj;M{yqtT_Hb-$52~!ioJJ6!EoS}E24?`{xif0Pd4n1b(W5ZAfFq)Q7@1n=O`nzdl!nzr5%di0x13pz zf(kE3R=Mq%9|HABRLEQgeXU#pK)%{lTr985OD_^hx4jlP*XKb^|7gku~K}h|? z@A7(ndO+Y64t?|v4*D+4Qge+#dT45iBAskQv_m)oIcU@+1=_V`F+^`P>8Gs%_~ZGq z9#(K_y>VbAI!OZ2J%Y`B)+QiKh6*GK#Hw3xb;!wi81C@t#HXA#zvmpXw%N2gIA`2v3fgAt$~2^(0XEPU5UGU zwA=)SuKXPm;fQ9xP6TOTw|wS;WfY-Ze_6`+efqe-_tS4)BRu+2=I?L!zBLp<2rdU` zZy-|gMb3wqL`v$H#y7LMpxm`z2Xk^(BnN(%N&JyLH9UKQkdTsGrlX=@_QLtijOd}X z4P$o~oo?2uKVVYs4US^#I(X^;HnpBGn6ftPryr%kwZTgyC*UNYW0#rpe#QmJC?ON< z63}xpJF`faU@IJpAl5`T3W-3fdk{9%sfI$;h-%V_v8=)2Xmzsxa|CT@RnXW4R8pbQ3m?Qsmp{^ffM|}AEpk0LJML~tAav1pW6B~Ce>}{ zEF}+Iy1c_?v1uLzyx(ox(WB`0&!89AV4$vz}GgXX1HvMbVX3nr{U9*QMgApA8DvG@X`-9%EB-_Em9Z7oLU<){WkGfd{HRuv0`fV&cmlOX*rP(5IrMU<`aYj zRQ;oBX<4PsnBt5GLUze#sp}^+^9Gq@neFYS_#Kf-NHoWQ0VPD2~yo4?4pZS;+W4m0H`vJ5|tD!2yIviK2nq{Vz^n6$X_;_xlQ1*-B z*QXoFc_V!Wx?i?hE~VeblnJz`xfIC93?=h@w$y%cwy%C2{!YnV+TT2$F}TETL!dzzj@4B0Mlc8vkzgn)64MxT^=V z*=Qh;`6xitNu_GnpQV*LF^<1C2L{YC*LKXe6TQ;gFIDFz)$@L8dbG3er+N^DI{Q|= zHssq->%{l+GE9ch0{6-~i3eMrluRgOP8bJ6&FCwZOC72wB&<3!;qS=0C%;nXg31LE zHk|9nj68|LA8cF!ufy@!h~$RIVySi53ZaIfT+Hjnw- zS0?1J>f8*?DuaI2vcxSYsPj)ribV*6!MV`B#;nz(zZ$$--a`av^TE?x6p1v5U;D1n zwq-;=CsImoE~u8ZEP~aNQtRa@+OqgW*TrPh62|?~`yS_@_4w|4=43FcZ9AfLNo@Vj zl&cUCS!DWV#&_A*m5J)IE7lXXc&zv1``k1*{*J-)sH-^n7-qEFR*(z_1K1G>{AzPfD@6_BU$^s{_I7QVMaYpK7{{uyA%a!e z;8xvAd1b;WnU=?QbmZDj0t!cY*W!u>T|{*39PSTa%KGIL^3ZHYncZ=hZhf5eXYJsA zbG_(F-Ny^&V|<;LP{*S@1M+|N4U>jOG%hJvIVMs7Mc~sVsC(f`NyETFO2RAe2x8ng>36R%5zDp~?mIBe}l0 z^UB1CTd4K+Ef=#PBUaN4B0zlg(CDIaaQbepu6uskU|=L$q^tb}W6Q|+7KlPiaoo=m zNt>|pc^m*xaPxF9PQ()XqvLU-;&%@r(lm?_Gyk?UtfAy%ltGHP2B zh7;;ZO7Xp&UvruDcF+Z~#z}<8Z@VC~i^<*(3IUBI+ofiy!yUIUHy#%7X2GxJnXkF` zy*xpC^+8u^UsAL!IXlouuRJXu*zchZ+sa}JPBdX4%5BLl))=A&|jZPB~h zG~ZZBtHOysnp=#ES0f;a`odExBDv`$kcdosify`bxjUc(02Q4!Mdz~}%!%7pS^!92 zKfZR&~t_zJJ>i~faFuOQWUGCPXq<@xi5Ola?(iw$ii+I zAHWi2>N1n;)bBo{XalKIJ@@cY5NJP5&3W2*P+|NFheegKLDafOu|SxhnVP2amVSJCb0#KhHt|HCQe>s$^dkpg)|Jo&=VmzY|=xF4$r@ zUFr7O#PdJKRIhIObT2YO0Vy`0?ZJSY;&OYQH@sld zaMuQmMw47k$LdEOxtH3#2+{XN31K-eIjlQ4HDr-jRj{Xbbz^!T^e=~eF|o^Q`zBSK z>RSXv7^AyFK0ssFo>4OGel>q9tqM_Gu+dQP`z)3lxN1>B*mK6qHN%lEl> zC5JUFc5aHBdUq4RcR=*luxV?f&$PppCt_xOu>&WTBCJ7s+ zdcnj+0gD6|hwZovnwqeLw`}1m0J+(_WGe{`xU>ravKuq*?Or3Ob}`!oxM`D5eYrBi zrlPaFU3iZ6QsX%789X}yJ5aEcx*Fi#`6mzoh$}VbrMwM=Ix|vkNn;NYclL~{YA^Hy z4v{uO;RWyxe~;8jZ2dZF!aazZdTy1*r(%3|vf4(OpbyB5!HKEAN-_f6`Ptb1OAU4d|UV$YOMV)a&AR-?;#E4F(bxVEqf;`fm5@ zn{J~T7xTq712^4RUsTo?%@qYsoWaIkHx4M6QW{-MwDw((h#IEn&v(37-bSwz()f1* z@jNd1cGI?yQqsc~=kqipw3|b+MJ^?5b|F)&w-i_;TY{Z<&`K+r^|bzUSqubP(QL(l zLD%BhVtqP$d~n3^ii}*X8=#<-a_4R~LcaT(!^qy}6s!Psi<-2sR?!Bu4_hGCSz&0=E}roXZ`e*+#EK_5u)V8EZ)$iX{{Wy6kLi{F zDm(Rj1U|gql&&27rxX2THDYF$FH})7@gM6J*+xCDTZmh^v{e% z4{#l_$KDtp$^`r+^Xf$-E_PuGD4e{iy3AQv_Kn{O+0~$T45>ogTX+o>5u>c>4boS^d==B zE%aVO2`!<_MSt%*v)0Ui-#2UKTkE@PWqG)sd+I)W@8{Y3eAdxYp(Lj#Cm|uB1gSpL zBO$r`i-hEY>Qz$UO`|{SDe%u_4+W6HRp1G{YV!&Bo6b|o*i+xl&eP|GyDf>mtDB20 zzlXKEt*xuaOE*v4rA9dtlKUi}XHN}$Q`aYbe0xSNwQXzf!)!^F*3nita6lDUtq`1D zF;s9m<_OlUL!e%6(2F?^Ggq1#I6LaIKYh>E-q0u?$yV|!l5OH(%}?fa<60`QWmi^i zN@ShyZnzRK2;g}WQL2qQANl#?@cGI0egwtv(<_h*+G}oVx^wH+0~Hk&KR-X&?`jwS)huM^#;&~Yt8im z{~NKMQt}lm+s?Rwtru>bL2}T=FC3cb@C5#3?r-L`zc$#_?`T&FOM7p^sW!$7ZNu#f zy*14S;kF)r0Rg!_V*hDF6KLaTXA#^`??)|pe1=G1xm5Dix6hhk)4N9!Q;6jKQ)RN&_c3Y$gQ@IO~%4?%v9pi}6 zf3mRZpXUj|4}>_^|!69Et`eFBa8$OxFqXcNJ#94Q~#o* z*XG#6?cMWra7Iz_7?r_!z=+&US>nr)P1(=HkdP2?mc|>q?o=1AG|iOif@eu2F5?Y~ zunKpK<9VYNsDtGXw3d2DYG4{#mW)~G8#C-oSJ2zKpGwP1mXwyy|+MeSa$}-Uh4IE#g*aPIo;QO=J zP$Gtw;M>jB^6OW@co*7pez~7W2-529h2?0=pXq^lj0Tot9@@CsC(f3gKo|;|RU%h= zBuLlVa1Dk_T1;Y2y-31xY#((L-EKc8fiRB4d{+`Vk(nXe3$8>OB2Drk$ojlPhNos~ zw&E@mI z7P9$vyt@#~21b}F`Ry*oL`6kSOiaX0O*!|iB(P)+xT|7Dg!)>ndL%tix)_H*@ z8XWiNC8ea`ud_qH8}ktsi7aDV0q~zT%2rx zI3?rOm`fDOa|IU3C<{NBVo12B1uirP`R&N$c4a2AgY5g#2fIfbSL3m=nChsNesGz> zo9}iV@CGF1Zvtg-K@hsGnqR~cTW?zKjh3o#ORRBOSQT@B^-3o@R6E}oiEKQ9#PfoO zzV@@QxrTqLfsZ!!4o1JdwO|Lnu6}p zgOP?{IXP^{s^_M8v{t%Q?pURxu?q{{Klr55FQgug#-X(SsU8P@#l4%-!Pxg^8G-vB z565&~kx2JwSz%v)t7u zH$0A`8WC|B=k+NuhntkwrMnEO<*LWS*sf&A3xXU+$~?kGY9#qI3cK?n7#xp(WmLQ# zv=eh0c>KEHC6aj(=Zo%65}B&P9+>^-s8=LpUM#yT8{nz_+BhvFL~#}ufS$1EtA-k` z4ZHjfjbIRS=rqtw7uK8$J~X7^y*%Mzk_3f<%ay(OiO^co8|z45gW4x2Eht^N<*~59 zP2O;JhpY1^?w<9;Vx&oSo#9D?fmxL+hCs9}XwlP+SUNJ^=5Py$kvX*|R~JUU{( zaS@G1ZyMY6XDQ8R2xbfyS>)Sk(mP=Qv3vd6FofWxUlfH#AC)Bdc3G?iA-(?DVpS(P zo||1U&G;sFcXz!};ar@5Ju)gP9hz5p{u6*)*F{C9;hPUXCm+uF9DrQ`u@XCsiWoz= zH6{S+kFdAeiNSzjaVN@srPI^99lg@Qr}f{b3d+;abWnO07JDy^_FVM?aH3gl&0_>) zQVMQV9f^f51^avbxDVakxUo7=t3P`JNM>z5F&@?$kv{w-sr(KD0|JZ~Dex{%-cfyV z;UZ|K>&3;AZ)S#hU%rItsj7bZZrhX0^Pf5R#t9EGTGe_i=%veOI~;|@hlQ(?Cjc&u za@2`&N|kdw+ey{SGP$!IUW7-vT~C(66$&0%K6QT)9@1dGtG6bwG8GtI3Z?zNVz4@LY}?0j%`U)(T;#YbKwD*J$N; zNUu-=KLW53i0R!W%;wQj+~|l=zV;cSLqD(3HErx%9D7rP91o5?l4b2n%*`zfPyS?KM|3e&TAlHpFNzkB)`6Ui*0mH|(C_wsYZ^MbLdMbZLa((1|6HTK zUvr`86Zr*vSLT&Q{^4~=kA<0;Oj9v9;>-!Uu#py++a4$CimwQ|C$Gz&ED?(c?_!E_ z8Ow>u%E}gX*b$|KI(_|a-<8*!CIxrPz!sYRM@^};^jeh}_e2Nn%y-=3R16;20GvH7 zi#n%X!9fGKK?lBs>YrX_R?yLjK0Z0opGeGHys54&fBg6<;7f8||L5xaHrduZh;>+5 z#UKa)_TLgt8_a=YhKbAI%<+l;*TUAPQP2B#83Q3u%K(cc5#s7xSvI)P>I1&yKdwEq zPzu#A@;mKFD9StMzg*Gi(65UBcfj#~LXZFNOD#gV5&2qaYHR-g=1Ef6+S0O6Mbx|g zE9@>mp`GWyz>p)Sc6$AWT&TuBJ^Lf?=BIxcg4ibrL*dqp@({O#XYBqYw{|6Ni`CbJqTu^iEkVtL z*vSlTe&f7fl4($E9`)UpmX<>G>cmQ)sUX?22@(G?#emwny5;4vxnv=aD#K!v?AmgB zxX#au4tg1mVBW6DNq)^vHJxmKvC5ZN(QS`cTYmf&`zTT>I=Fgf=IU_nF4O`S+t*;w zo_jNbNmjTL@ecuSJyRQevJQA^dk4KwBJRm)q*<=NtVG&|FFFo?kKj1Qm&*}e86*$o z11b#Af4a$W@!tSz<9HTmhH!!Uql*@c(=j#3#(woQsm`B2XVQ_hHBN~;i#@Spn1AlN zuT}0!bVoR?pc+i=j$neb<&46WO4mJi=wtWynEiOf$oX=Biwq>=i*=L)4>l1GRU$by zZ%|T#-?FlcE{*un<6BdBOvIneah?`kR8q@%eEs#Z8Lq%!l)NrTR=DLsEb#`TLE@$? zxGs<#T&Qby>Em^<&Z}3mrvOGf*_ykIaT_vFQj61#r?1@G+`3g4xX^iNiq_uVUd&}c z71$T4pyOw=`*e-ndf9pW2072@z$FlMD4`)wKVOS;vV1moZ^?4}d?4pLWmp11lP$84U6Z=2ejeZMC~`Sl81jc@JB4G=B2XPmavZAUMYF{^-Ukm#IvF$p9W69yJ*L zXMxZ;Msgg4=jLf2nS?-aNE(D8!Ym3B78Mmd9Wb}*xJu1H%Lz&rpQA++Ps!lA=wy!5 z!!&H5b?H9S<8LK`2WmxKSywz378VLyDKmy)A9lgTY74*CpaAwJkNWicW47|ktsfW0 z=xWs6CU+dc!~ z7~e^l9gMQEx90@GbsFkdMPC*GwsE+$`Yf^Lq&wJN%zBkgQc@BGqn8LY4Nnx%_w@9% zdbvMRwLy*!G~qWB)h-K?|B}H4O5WMMT#G`f!;ak#3$+_ZD)x{rJm#g}^3H_yk$VA3 zCzcz$pmVec_<-=lfCCKRqG13BCCHx9Fr|L*Z zo`(;J-i*zWAZ;um>^V9u7FkyMbr}{z%C%r|(mn!vLA4*H(0`u7@VF!qDX-NE$og+c ze}Dhyr2v0By+Rm!rO2y9jF;1JLBhRIkY0IS#5u4Y+gY-No1qfeRt{)*&-X*B(kail zy2q>v?w%X=`NdbZbF4#lK&l2?>^1uah&~2k##xq_V51-eV6H2hV_qXq)(Ly67B#Pg zws${-)9#HowTx}Gad@p9TUlwBJw+a9dzYL=l&(+I-Y-063fGNQ9`?vy=-7>$ot?dN z_pX4O8&W#spQYWptiJn11IBata)H8=H*72O9r^_8L5>q)r${V=klxRwJ|{pd$f@K6 zL4;T9oaeuek{FTv49wE{=ywxniD6|}AQW2ZzekTLwonI%M1*0n?wm4Z@w@UA08k-$ z;&~^lu-803SNfGqy7V=sn0N$XiX*vp>5e#z07^h)}`A;)rboUB& zX$1;wckQZ+!$U$&WP2{{_tXf&uDHYI=jNaz9t^URPnaMtGY&^F7^M#sGzN>^pbH5t zR=P_ivYxB>MtYf7Z#olsd3_`#nB@EoPApjhM}(iJcyEj%mc}a7_SP0V7xIVslR1b) zw9^43o*O({cD=dx*vF7oAhaMbX<)^I=3G3VNU07!aRv;}`4Q@q9po651H?a`U*8nv zjnf54)8lh6otl`SJTrEm}Kx#p;UA^t`<_9uJT@lDKZ{v?FRk) zGfeL9E*{G&1GpvXO|abFW`B!gN{dy0i7as_bFv)Z5KXU6pp77qbe?E=OMjy)=VOni z0*)5ZWyY%59IdPren%HLE=BuF&z>zuMWn<7@+BiHyRfoSSns#{a^?GifAJLWXS5E0 z>f``&ZWU9UJyyBN$OkUgGf5J$9}bllckHS2avaX-Ugw@$j40nJ@KT;f}TEpb<2ECRo16w0CkU*CbZP_SSa#5>?Ovp1Pl{l-P4+Y<3Pm>(|}Bn+Gsmsxbe0 z;U`yih-+z?m#Dj9?zS%$Rc#U>-TAL9qx&XuM7nwrNaq7L8H5(RPr?d-Tg zpybidi`yX*dCjVd05zUrx=$ph;W3`xq-~?-elQIxoj-^txE}X8V(LHpdj*34{OvT> zZMlbSFC(~4aJqZD!{#Dh`EI^bf?Jf=H4yNMEx%eF*X=D=&@t9x+o;z&wLKTFzeOEz zsV8)I#!8RKj%+uz+@xgLi|LH#&i#3b(Am)e8uwlws=>8(O*UIp!i~Vr=BZdZInxJ; z3VV8O-ktGX+5!7azlZ3`y^hqrLN>=hFgjKyI-1;!yl$OwdsFt%z=v|j&j3X&i)v(J zadS(1?58#ul$70Gz_qu5v4Gv7rOgL~uE5@CkT|g2dhAbemmgeA58m6exAr_-7K$J& zdz}AjA4@wOj=OOI&dkHMpgh6G)2EhDab?(@JAn{IEOW_3t-E9Un;-!1_peqmh`O)a z`{Rlq!1W57PL75C!lD7yWKt`D$?bpVS1x9|>RD`34FMF>z~0(OyqNl3aDfiQ5_*)> z8P6Z<8`!njGrvBcg9}dm_Er%aheoG$CU9pv#0CSQiVFt@cDr_(q8|H<3*9UEenPfRHm>gkV1bwm@0I-@yl{{cPfbth+X8}_E4E>@rNhE)<*YX>kh&^xY$B&L9 zCBPaJyV{7G9-k&D0QC$d?j_Po`hTfASkDFkI-*NGZKzn?{sV*@;}(9mtEUHStr9i# z#)#v`HoI$5Zq`dBAMd@84a3)ej}qPl&xv0k}H3 zlN~cA=^%xc@VlUi&Dq&3*EDH1fEgc0q>utUow)Nv(J;RrRr)0#92$32O?Bd7tgEZ* zU+cuV&>OE0GiY#jSm<2g6x7xR4X~tCEiZ3V(@XEj#&g^H$0P`tD2yOg9A{utn9b4Q zot>Syw6wIQrY20SqO_RXfDX(PkPWT0QzImLK;O&JFp({u-$GCF#GQ+ePo|9dj8PKq zG*W^vH(4W~P_-*9`+1yZm3&F@Q}P*9jK?bat--N1s!Atym7-p)&PvM49e|-LUlNGU z4#`$-I53>`;WEmL>rItKIEVzZ-#iD!Z?5z7aANvmWKriPBvX-ea&Q|UMhyT@!3{M9 zaGz~ASZX#-S21v`_t~eJW>KrdM+ldN&V>H%6@AwLSs=K#w=t*=CF1MUdy0Xe9=0sK z8g82VJwd=U+L;J2=`VpG!)+Hw)#^0a%rY?V880mP=V5W*eO5 zy~+1zo9E43>~&Bm2&Yxd$pVdcCGw}8duaVlALgg0zXkUlCtCUS3ki({Pe+s1j}aSI zlO)TLY!3SqQ$x9f6rJvK9$j`3)KS*}vj&7Hc?>H`v#eo;hLl`J%7D@7kFjn8X9f-& zL*sebK1^)7mH^-uvjcWAC^{##B$`#+D046RY=BErgF0g-{cXnph+z!f-`h6yeP)NC zF@w6j$0j1pV=|n)H-IkK!)Rj=2m~0)8^?<<@u20B;!y6bHo@FISEFA@*2L`wQ$b%N0dhi01&&-FHOLH<6m!;5QKFz#lW|?zl;ufO zz=`*1FdJqtt#2%>yg>Jywmuqsk9n!6Ah6Q(A-uX6m#dz+(-kAz0zIG88@%FuQkg|y zi7M$&?aPeuy<7c&F)d1jI3ul;$h!b(%h$^2|I^pX-uOck-F*93OG{U;+>y6FmU*Eo zMWsPbj(f8)*1NA#H#U?KzqHRZ*6>hgH^{8Wk0SBqP=H&ZLB}ji!>#jRiY|HfsCs|Z zz1}wF3;9Bq*j@Y3!sQKJ+K6tT!()Ti?26JS2~T%Z^ZAsCrJC?z)vLCm<<8u^)ou}ws~zJd&@4mUItU} zR94JUM;ovvYkLyGDJMYW_Fpalw!hnQ$;q?BCk{}T8{@$`AIRsmQ`b*}B&8(_9T&*q zrnT<~`()^ZqpQsZh;LQjSLR8UJ>8^U>oxHjo6Z6ZwM0i>xV?2cCa+Fwd%AQb9v zMDinKywW~nePe@~^IKxhpBiJ(u;K&$yMW_l_5jrJ4#6btW8yN7_Gtt>GJp$!n^|0= z82lWY52KXCZ@n7H)meM)GJ-uZ%rHWZe*+B$m5nW~&1Kj7rR#ZC&<&UXPDV>>i^E)k zd~qZNAmP-U+C~Nj2IM|JA0PI;fF8Gu7<%|gNbEN15SkXcTN4l!c87<{$EW(2%hAq!Ok#fi zqM&J3kx4n1oE!u=qPjEhuH2~!Kvvn2m}DvoINfWc2*6g1C5HfDSSOhG3uLpxvV3}Lz0tzX9af!ZiQ z6J%#;>2lBH6TV`u6MgT7tR6!vxG9Yi2bMy zI45x9{-%!oN|!-BTEWm|)OPG08m3%WOSps1S;MOQJU>8qfnbi9g1oO^jZdn4lTQCs zfMN4Xi55`ECj72uk6K}5WF+C$uSc3mLh8Vw%qrb_bwuz*m}KV{hknRoQ`vV0ESZI7 z#u1`{;jA2pdB(GsBhyPP&6v`IwEzgT+*rO;WH=XST@&VN_#wha7?dWw6_it4Z1N<#AI&c*+S5(kFNIW93VKY{;iJQnl!%lke3 z|6?3>J4ql~mL_l;W@TkPh~oL%XwK)ae~hnK*0Wi<^@$3mJh|RZ^8L_vWfkB6qQ0=+ z`8!RSZQuhhSz$FJqzX@Xlu>e`_I*+tlJumBg_W7i@Ju7m6?fzRW@A?e79Lq#N3&|* zxN%P1?(Q%R);}ZR?o1dpE9uoDuVu{paiTJSlKR`djBo=sy>oFbR^Y|gXF#J|=Zz+H zSe$Af{Z}fAua%I^f2jTcORmuW2w~qMgytpraWxzUN#-qVRxBxE>M#Em^6

+6PDCfUDK{!z|I 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 To(w=h0OpXH&3T&1rQiPs$lTS; literal 0 HcmV?d00001 diff --git a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc index 65051f176f6f10..aa49ca75bbbcc9 100644 --- a/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc +++ b/docs/src/main/asciidoc/security-openid-connect-dev-services.adoc @@ -72,7 +72,16 @@ First you will see an option to `Log into Single Page Application`: image::dev-ui-keycloak-sign-in-to-spa.png[alt=Dev UI OpenID Connect Keycloak Page - Log into Single Page Application,role="center"] -Next, after you select this option, you will be redirected to Keycloak to authenticate, example, as `alice:alice` and then returned to the page representing the SPA: +Choose Keycloak realm and client id which will be used during the authentication process. + +[NOTE] +==== +This SPA represents a public OpenId Connect client therefore the client IDs you enter should identify public Keycloak clients which have no secrets. This is because SPA is not a web application and can not securely handle secrets which it will need to complete the authorization code flow if the client secret is also expected to complete the authorization code flow. + +The clients requiring secrets can only be supported with this SPA if a default realm has been created or if `quarkus.oidc.credentials.secret` is configued and a single custom realm is used since in these cases the SPA can figure out the client secret it may need to complete the authorization code flow after Keycloak redorected the user back to it. +==== + +Next, after selecting `Log into Single Page Application`, you will be redirected to Keycloak to authenticate, example, as `alice:alice` and then returned to the page representing the SPA: image::dev-ui-keycloak-test-service-from-spa.png[alt=Dev UI OpenID Connect Keycloak Single Page Application,role="center"] @@ -82,7 +91,15 @@ image::dev-ui-keycloak-decoded-tokens.png[alt=Dev UI OpenID Connect Keycloak Dec This view shows the encoded JWT token on the left-hand side and highlights the headers (red colour), payload/claims (green colour) and signature (blue colour). It also shows the decoded JWT token on the right-hand side where you can see the header and claim names and their values. -Next test the service with either the current access or ID token. SPA usually sends the access tokens to the application endpoints but there could be cases where the ID tokens are forwarded to the application frontends for them to be aware about the user who is currently logged into SPA. +Next test the service by entering a relative service path and sending a token. SPA usually sends access tokens to the application endpoint, so choose `Test with Access Token` option, for example: + +image::dev-ui-keycloak-test-access-token.png[alt=Dev UI Keycloak Test with access token,role="center"] + +You can use an `eraser` symbol in the right bottom corner to clear the test results area. + +Sometimes ID tokens are forwarded to the application frontends as bearer tokens as well for the endpoints be aware about the user who is currently logged into SPA or to perform an out-of-band token verification. Choose `Test with ID Token` option in such cases. + +Manually entering the service paths is not ideal, so please see the <> section about enabling Swagger or GraphQL UI for testing the service with the access token already acquired by OIDC Dev UI. Finally, you can select a `Log Out` image::dev-ui-keycloak-logout.png option if you'd like to log out and authenticate to Keycloak as a different user. @@ -92,6 +109,7 @@ image::dev-ui-keycloak-login-error.png[alt=Dev UI Keycloak Login Error,role="cen If the error occurs then log into Keycloak using the `Keycloak Admin` option and update the realm configuration as necessary and also check the `application.properties`. +[[test-with-swagger-graphql]] ===== Test with Swagger UI or GraphQL UI You can avoid manually entering the service paths and test your service with `Swagger UI` or `GraphQL UI` if `quarkus-smallrye-openapi` and/or `quarkus-smallrye-graphql` are used in your project. For example, if you start Quarkus in dev mode with both `quarkus-smallrye-openapi` and `quarkus-smallrye-graphql` dependencies then you will see the following options after logging in into Keycloak: @@ -99,7 +117,7 @@ You can avoid manually entering the service paths and test your service with `Sw image::dev-ui-keycloak-test-service-swaggerui-graphql.png[alt=Test your service with Swagger UI or GraphQL UI,role="center"] For example, clicking on `Swagger UI` will open `Swagger UI` in a new browser tab where you can test the service using the token acquired by Dev UI for Keycloak. -and `Swagger UI` will not try to re-authenticate again. +and `Swagger UI` will not try to re-authenticate again. Do not choose a `Swagger UI` `Authorize` option once you are in Swagger UI since OIDC Dev UI has done the authorization and provided the access token for Swagger UI to use for testing. Integration with `GraphQL UI` works in a similar way, the access token acquired by Dev UI for Keycloak will be used. @@ -128,7 +146,7 @@ If you set `quarkus.oidc.devui.grant.type=password` in `application.properties` image::dev-ui-keycloak-password-grant.png[alt=Dev UI OpenID Connect Keycloak Page - Password Grant,role="center"] -Enter a registered username, user password, a relative service endpoint path, click on `Test Service` and you will see a status code such as `200`, `403`, `401` or `404` printed. +Select a realm, enter client id and secret, username amd user password, a relative service endpoint path, click on `Test Service` and you will see a status code such as `200`, `403`, `401` or `404` printed. If the username is also set in `quarkus.keycloak.devservices.users` map property containing usernames and passwords then you do not have to set a password when testing the service. But note, you do not have to initialize `quarkus.keycloak.devservices.users` to test the service using the password grant. @@ -150,7 +168,7 @@ If you set `quarkus.oidc.devui.grant.type=client` then a `client_credentials` gr image::dev-ui-keycloak-client-credentials-grant.png[alt=Dev UI OpenID Connect Keycloak Page - Client Credentials Grant,role="center"] -You can test the service the same way as with the `Password` grant. +Select a realm, enter the client id and secret, a relative service endpoint path, click on `Test Service` and you will see a status code such as `200`, `403`, `401` or `404` printed. [[develop-web-app-applications]] === Developing OpenID Connect Web App Applications @@ -198,8 +216,8 @@ Please see xref:security-openid-connect.adoc#integration-testing-keycloak-devser [[keycloak-initialization]] === Keycloak Initialization -The `quay.io/keycloak/keycloak:17.0.0` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default. -`quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image name. For example, set it to `quay.io/keycloak/keycloak:17.0.0-legacy` to use a Keycloak distribution powered by WildFly. +The `quay.io/keycloak/keycloak:19.0.2` image which contains a Keycloak distribution powered by Quarkus is used to start a container by default. +`quarkus.keycloak.devservices.image-name` can be used to change the Keycloak image name. For example, set it to `quay.io/keycloak/keycloak:19.0.0-legacy` to use a Keycloak distribution powered by WildFly. `Dev Services for Keycloak` will initialize a launched Keycloak server next. @@ -225,7 +243,18 @@ This configuration creates two users: However, it is likely your Keycloak configuration may be more complex and require setting more properties. -This is why `quarkus.keycloak.devservices.realm-path` is always checked first before trying to initialize Keycloak with the default or configured realm, client, user and roles properties. If the realm file exists on the file system or classpath then only this realm will be used to initialize Keycloak. +This is why `quarkus.keycloak.devservices.realm-path` is always checked first before trying to initialize Keycloak with the default or configured realm, client, user and roles properties. If the realm file exists on the file system or classpath then only this realm will be used to initialize Keycloak, for example: + +[source,properties] +---- +quarkus.keycloak.devservices.realm-path=quarkus-realm.json +---- + +You can use `quarkus.keycloak.devservices.realm-path` to initialize Keycloak with multiple realm files by providing a comma-separated list of files: + +---- +quarkus.keycloak.devservices.realm-path=quarkus-realm1.json,quarkus-realm2.json +---- Also, the Keycloak page offers an option to `Sign In To Keycloak To Configure Realms` using a `Keycloak Admin` option in the right top corner: @@ -233,8 +262,6 @@ image::dev-ui-keycloak-admin.png[alt=Dev UI OpenID Connect Keycloak Page - Keycl Sign in to Keycloak as `admin:admin` in order to further customize the realm properties, create or import a new realm, export the realm. -Note that even if you initialize Keycloak from a realm file, it is still needed to set `quarkus.keycloak.devservices.users` property if a `password` grant is used to acquire the tokens to test the OIDC `service` applications. - == Disable Dev Services for Keycloak `Dev Services For Keycloak` will not be activated if either `quarkus.oidc.auth-server-url` is already initialized or the default OIDC tenant is disabled with `quarkus.oidc.tenant.enabled=false`, irrespectively of whether you work with Keycloak or not. diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java index 08f34baaf2e6fb..cd580975597c59 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java @@ -78,10 +78,11 @@ public class DevServicesConfig { public String serviceName; /** - * The class or file system path to a Keycloak realm file which will be used to initialize Keycloak. + * The comma-separated list of class or file system paths to Keycloak realm files which will be used to initialize Keycloak. + * The first value in this list will be used to initialize default tenant connection properties. */ @ConfigItem - public Optional realmPath; + public Optional> realmPath; /** * The JAVA_OPTS passed to the keycloak JVM diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java index 5047e5f2b8160a..38b17975a97f16 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevConsoleProcessor.java @@ -36,6 +36,9 @@ public void setConfigProperties(BuildProducer d devConsoleInfo.produce( new DevConsoleTemplateInfoBuildItem("keycloakUsers", configProps.get().getProperties().get("oidc.users"))); + devConsoleInfo.produce( + new DevConsoleTemplateInfoBuildItem("keycloakRealms", + configProps.get().getProperties().get("keycloak.realms"))); String realmUrl = configProps.get().getConfig().get("quarkus.oidc.auth-server-url"); produceDevConsoleTemplateItems(capabilities, diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index dbdc5dbd8ec3c2..1f7ed7a2f8fca8 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -18,6 +18,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -36,7 +37,6 @@ import org.keycloak.representations.idm.RolesRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.util.JsonSerialization; -import org.testcontainers.containers.BindMode; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.utility.DockerImageName; @@ -87,6 +87,7 @@ public class KeycloakDevServicesProcessor { private static final String CLIENT_ID_CONFIG_KEY = CONFIG_PREFIX + "client-id"; private static final String CLIENT_SECRET_CONFIG_KEY = CONFIG_PREFIX + "credentials.secret"; private static final String KEYCLOAK_URL_KEY = "keycloak.url"; + private static final String CLIENT_KEYCLOAK_URL_KEY = "client." + KEYCLOAK_URL_KEY; private static final String KEYCLOAK_CONTAINER_NAME = "keycloak"; private static final int KEYCLOAK_PORT = 8080; @@ -100,7 +101,6 @@ public class KeycloakDevServicesProcessor { private static final String KEYCLOAK_WILDFLY_FRONTEND_URL = "KEYCLOAK_FRONTEND_URL"; private static final String KEYCLOAK_WILDFLY_USER_PROP = "KEYCLOAK_USER"; private static final String KEYCLOAK_WILDFLY_PASSWORD_PROP = "KEYCLOAK_PASSWORD"; - private static final String KEYCLOAK_WILDFLY_IMPORT_PROP = "KEYCLOAK_IMPORT"; private static final String KEYCLOAK_WILDFLY_DB_VENDOR = "H2"; private static final String KEYCLOAK_WILDFLY_VENDOR_PROP = "DB_VENDOR"; @@ -111,8 +111,8 @@ public class KeycloakDevServicesProcessor { private static final String KEYCLOAK_QUARKUS_START_CMD = "start --storage=chm --http-enabled=true --hostname-strict=false --hostname-strict-https=false"; private static final String JAVA_OPTS = "JAVA_OPTS"; - private static final String KEYCLOAK_DOCKER_REALM_PATH = "/tmp/realm.json"; private static final String OIDC_USERS = "oidc.users"; + private static final String KEYCLOAK_REALMS = "keycloak.realms"; /** * Label to add to shared Dev Service for Keycloak running in containers. @@ -153,13 +153,13 @@ public DevServicesResultBuildItem startKeycloakContainer( if (devService != null) { boolean restartRequired = !currentDevServicesConfiguration.equals(capturedDevServicesConfiguration); if (!restartRequired) { - FileTime currentRealmFileLastModifiedDate = getRealmFileLastModifiedDate( - currentDevServicesConfiguration.realmPath); - if (currentRealmFileLastModifiedDate != null - && !currentRealmFileLastModifiedDate.equals(capturedRealmFileLastModifiedDate)) { - restartRequired = true; - capturedRealmFileLastModifiedDate = currentRealmFileLastModifiedDate; - } + //FileTime currentRealmFileLastModifiedDate = getRealmFileLastModifiedDate( + // currentDevServicesConfiguration.realmPath); + //if (currentRealmFileLastModifiedDate != null + // && !currentRealmFileLastModifiedDate.equals(capturedRealmFileLastModifiedDate)) { + // restartRequired = true; + // capturedRealmFileLastModifiedDate = currentRealmFileLastModifiedDate; + //} } if (!restartRequired) { DevServicesResultBuildItem result = devService.toBuildItem(); @@ -167,8 +167,12 @@ public DevServicesResultBuildItem startKeycloakContainer( Map users = (usersString == null || usersString.isBlank()) ? Map.of() : Arrays.stream(usersString.split(",")) .map(s -> s.split("=")).collect(Collectors.toMap(s -> s[0], s -> s[1])); + String realmsString = result.getConfig().get(KEYCLOAK_REALMS); + List realms = (realmsString == null || realmsString.isBlank()) ? List.of() + : Arrays.stream(realmsString.split(",")).collect(Collectors.toList()); keycloakBuildItemBuildProducer - .produce(new KeycloakDevServicesConfigBuildItem(result.getConfig(), Map.of(OIDC_USERS, users))); + .produce(new KeycloakDevServicesConfigBuildItem(result.getConfig(), + Map.of(OIDC_USERS, users, KEYCLOAK_REALMS, realms))); return result; } try { @@ -226,7 +230,7 @@ public void run() { closeBuildItem.addCloseTask(closeTask, true); } - capturedRealmFileLastModifiedDate = getRealmFileLastModifiedDate(capturedDevServicesConfiguration.realmPath); + //capturedRealmFileLastModifiedDate = getRealmFileLastModifiedDate(capturedDevServicesConfiguration.realmPath); if (devService == null) { compressor.closeAndDumpCaptured(); } else { @@ -247,28 +251,35 @@ private String startURL(String host, Integer port, boolean isKeyCloakX) { private Map prepareConfiguration( BuildProducer keycloakBuildItemBuildProducer, String internalURL, - String hostURL, RealmRepresentation realmRep, + String hostURL, List realmReps, boolean keycloakX) { - final String realmName = realmRep != null ? realmRep.getRealm() : getDefaultRealmName(); + final String realmName = !realmReps.isEmpty() ? realmReps.iterator().next().getRealm() : getDefaultRealmName(); final String authServerInternalUrl = realmsURL(internalURL, realmName); String clientAuthServerBaseUrl = hostURL != null ? hostURL : internalURL; String clientAuthServerUrl = realmsURL(clientAuthServerBaseUrl, realmName); - String oidcClientId = getOidcClientId(); - String oidcClientSecret = getOidcClientSecret(); + boolean createDefaultRealm = realmReps.isEmpty() && capturedDevServicesConfiguration.createRealm; + + String oidcClientId = getOidcClientId(createDefaultRealm); + String oidcClientSecret = getOidcClientSecret(createDefaultRealm); String oidcApplicationType = getOidcApplicationType(); - boolean createDefaultRealm = realmRep == null && capturedDevServicesConfiguration.createRealm; Map users = getUsers(capturedDevServicesConfiguration.users, createDefaultRealm); + List realmNames = new LinkedList<>(); + WebClient client = OidcDevServicesUtils.createWebClient(vertxInstance); try { String adminToken = getAdminToken(client, clientAuthServerBaseUrl); if (createDefaultRealm) { createDefaultRealm(client, adminToken, clientAuthServerBaseUrl, users, oidcClientId, oidcClientSecret); - } else if (realmRep != null && keycloakX) { - createRealm(client, adminToken, clientAuthServerBaseUrl, realmRep); + realmNames.add(realmName); + } else { + for (RealmRepresentation realmRep : realmReps) { + createRealm(client, adminToken, clientAuthServerBaseUrl, realmRep); + realmNames.add(realmRep.getRealm()); + } } } finally { client.close(); @@ -276,6 +287,7 @@ private Map prepareConfiguration( Map configProperties = new HashMap<>(); configProperties.put(KEYCLOAK_URL_KEY, internalURL); + configProperties.put(CLIENT_KEYCLOAK_URL_KEY, clientAuthServerBaseUrl); configProperties.put(AUTH_SERVER_URL_CONFIG_KEY, authServerInternalUrl); configProperties.put(CLIENT_AUTH_SERVER_URL_CONFIG_KEY, clientAuthServerUrl); configProperties.put(APPLICATION_TYPE_CONFIG_KEY, oidcApplicationType); @@ -283,9 +295,11 @@ private Map prepareConfiguration( configProperties.put(CLIENT_SECRET_CONFIG_KEY, oidcClientSecret); configProperties.put(OIDC_USERS, users.entrySet().stream() .map(e -> e.toString()).collect(Collectors.joining(","))); + configProperties.put(KEYCLOAK_REALMS, realmNames.stream().collect(Collectors.joining(","))); keycloakBuildItemBuildProducer - .produce(new KeycloakDevServicesConfigBuildItem(configProperties, Map.of(OIDC_USERS, users))); + .produce(new KeycloakDevServicesConfigBuildItem(configProperties, + Map.of(OIDC_USERS, users, KEYCLOAK_REALMS, realmNames))); return configProperties; } @@ -337,7 +351,7 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild QuarkusOidcContainer oidcContainer = new QuarkusOidcContainer(dockerImageName, capturedDevServicesConfiguration.port, useSharedNetwork, - capturedDevServicesConfiguration.realmPath, + capturedDevServicesConfiguration.realmPath.orElse(List.of()), capturedDevServicesConfiguration.serviceName, capturedDevServicesConfiguration.shared, capturedDevServicesConfiguration.javaOpts, @@ -353,7 +367,7 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild : null; Map configs = prepareConfiguration(keycloakBuildItemBuildProducer, internalUrl, hostUrl, - oidcContainer.realmRep, + oidcContainer.realmReps, oidcContainer.keycloakX); return new RunningDevService(KEYCLOAK_CONTAINER_NAME, oidcContainer.getContainerId(), oidcContainer::close, configs); @@ -384,23 +398,23 @@ private String getSharedContainerUrl(ContainerAddress containerAddress) { private static class QuarkusOidcContainer extends GenericContainer { private final OptionalInt fixedExposedPort; private final boolean useSharedNetwork; - private final Optional realmPath; + private final List realmPaths; private final String containerLabelValue; private final Optional javaOpts; private final boolean sharedContainer; private String hostName; private final boolean keycloakX; - private RealmRepresentation realmRep; + private List realmReps = new LinkedList<>(); private final Optional startCommand; private final boolean showLogs; public QuarkusOidcContainer(DockerImageName dockerImageName, OptionalInt fixedExposedPort, boolean useSharedNetwork, - Optional realmPath, String containerLabelValue, + List realmPaths, String containerLabelValue, boolean sharedContainer, Optional javaOpts, Optional startCommand, boolean showLogs) { super(dockerImageName); this.useSharedNetwork = useSharedNetwork; - this.realmPath = realmPath; + this.realmPaths = realmPaths; this.containerLabelValue = containerLabelValue; this.sharedContainer = sharedContainer; this.javaOpts = javaOpts; @@ -458,31 +472,21 @@ protected void configure() { addEnv(KEYCLOAK_WILDFLY_VENDOR_PROP, KEYCLOAK_WILDFLY_DB_VENDOR); } - if (realmPath.isPresent()) { + for (String realmPath : realmPaths) { URL realmPathUrl = null; - if ((realmPathUrl = Thread.currentThread().getContextClassLoader().getResource(realmPath.get())) != null) { - realmRep = readRealmFile(realmPathUrl, realmPath.get()); - if (!keycloakX) { - withClasspathResourceMapping(realmPath.get(), KEYCLOAK_DOCKER_REALM_PATH, BindMode.READ_ONLY); - } + if ((realmPathUrl = Thread.currentThread().getContextClassLoader().getResource(realmPath)) != null) { + readRealmFile(realmPathUrl, realmPath).ifPresent(realmRep -> realmReps.add(realmRep)); } else { - Path filePath = Paths.get(realmPath.get()); + Path filePath = Paths.get(realmPath); if (Files.exists(filePath)) { - if (!keycloakX) { - withFileSystemBind(realmPath.get(), KEYCLOAK_DOCKER_REALM_PATH, BindMode.READ_ONLY); - } - realmRep = readRealmFile(filePath.toUri(), realmPath.get()); + readRealmFile(filePath.toUri(), realmPath).ifPresent(realmRep -> realmReps.add(realmRep)); } else { - LOG.debugf("Realm %s resource is not available", realmPath.get()); + LOG.debugf("Realm %s resource is not available", realmPath); } } } - if (realmRep != null && !keycloakX) { - addEnv(KEYCLOAK_WILDFLY_IMPORT_PROP, KEYCLOAK_DOCKER_REALM_PATH); - } - if (showLogs) { super.withLogConsumer(t -> { LOG.info("Keycloak: " + t.getUtf8String()); @@ -500,7 +504,7 @@ private Integer findRandomPort() { } } - private RealmRepresentation readRealmFile(URI uri, String realmPath) { + private Optional readRealmFile(URI uri, String realmPath) { try { return readRealmFile(uri.toURL(), realmPath); } catch (MalformedURLException ex) { @@ -509,15 +513,15 @@ private RealmRepresentation readRealmFile(URI uri, String realmPath) { } } - private RealmRepresentation readRealmFile(URL url, String realmPath) { + private Optional readRealmFile(URL url, String realmPath) { try { try (InputStream is = url.openStream()) { - return JsonSerialization.readValue(is, RealmRepresentation.class); + return Optional.of(JsonSerialization.readValue(is, RealmRepresentation.class)); } } catch (IOException ex) { LOG.errorf("Realm %s resource can not be opened: %s", realmPath, ex.getMessage()); } - return null; + return Optional.empty(); } @Override @@ -596,6 +600,7 @@ private void createRealm(WebClient client, String token, String keycloakUrl, Rea .transform(resp -> { LOG.debugf("Realm status: %d", resp.statusCode()); if (resp.statusCode() == 200) { + LOG.debugf("Realm %s has been created", realm.getRealm()); return 200; } else { throw new RealmEndpointAccessException(resp.statusCode()); @@ -726,11 +731,13 @@ private static String getOidcApplicationType() { return ConfigProvider.getConfig().getOptionalValue(APPLICATION_TYPE_CONFIG_KEY, String.class).orElse("service"); } - private static String getOidcClientId() { - return ConfigProvider.getConfig().getOptionalValue(CLIENT_ID_CONFIG_KEY, String.class).orElse("quarkus-app"); + private static String getOidcClientId(boolean createRealm) { + return ConfigProvider.getConfig().getOptionalValue(CLIENT_ID_CONFIG_KEY, String.class) + .orElse(createRealm ? "quarkus-app" : ""); } - private static String getOidcClientSecret() { - return ConfigProvider.getConfig().getOptionalValue(CLIENT_SECRET_CONFIG_KEY, String.class).orElse("secret"); + private static String getOidcClientSecret(boolean createRealm) { + return ConfigProvider.getConfig().getOptionalValue(CLIENT_SECRET_CONFIG_KEY, String.class) + .orElse(createRealm ? "secret" : ""); } } diff --git a/extensions/oidc/deployment/src/main/resources/dev-templates/provider.html b/extensions/oidc/deployment/src/main/resources/dev-templates/provider.html index a18c17d2d36563..efd73823816177 100644 --- a/extensions/oidc/deployment/src/main/resources/dev-templates/provider.html +++ b/extensions/oidc/deployment/src/main/resources/dev-templates/provider.html @@ -41,7 +41,8 @@ $('.implicitLoggedIn').show(); var search = window.location.search; var code = search.match(/code=([^&]+)/)[1]; - exchangeCodeForTokens(code); + var state = search.match(/state=([^&]+)/)[1]; + exchangeCodeForTokens(code, state); }else if(errorInUrl()){ loggedIn === false; $('.implicitLoggedOut').hide(); @@ -99,20 +100,30 @@ } function signInToOidcProviderAndGetTokens() { + var address; + var state; + var clientId = getClientId(); + {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + address = '{info:keycloakAdminUrl??}' + "/realms/" + $('#keycloakRealm').val() + "/protocol/openid-connect/auth"; + state = makeid() + "_" + $('#keycloakRealm').val() + "_" + clientId; + {#else} + address = '{info:authorizationUrl??}'; + state = makeid(); + {/if} {#if info:oidcGrantType is 'implicit'} - window.location.href = '{info:authorizationUrl??}' - + "?client_id=" + '{info:clientId}' + window.location.href = address + + "?client_id=" + clientId + "&redirect_uri=" + "http%3A%2F%2Flocalhost%3A" + port + encodedDevRoot + "%2Fio.quarkus.quarkus-oidc%2Fprovider" + "&scope=openid&response_type=token id_token&response_mode=query&prompt=login" + "&nonce=" + makeid() - + "&state=" + makeid(); + + "&state=" + state; {#else} - window.location.href = '{info:authorizationUrl??}' - + "?client_id=" + '{info:clientId}' + window.location.href = address + + "?client_id=" + clientId + "&redirect_uri=" + "http%3A%2F%2Flocalhost%3A" + port + encodedDevRoot + "%2Fio.quarkus.quarkus-oidc%2Fprovider" + "&scope=openid&response_type=code&response_mode=query&prompt=login" + "&nonce=" + makeid() - + "&state=" + makeid(); + + "&state=" + state; {/if} } @@ -188,16 +199,30 @@ function logout() { localStorage.removeItem('authorized'); - window.location.assign('{info:logoutUrl??}' + var address; + {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + address = '{info:keycloakAdminUrl??}' + "/realms/" + $('#keycloakRealm').val() + "/protocol/openid-connect/logout"; + {#else} + address = '{info:logoutUrl??}'; + {/if} + window.location.assign(address + "?" + '{info:postLogoutUriParam??}' + "=" + "http%3A%2F%2Flocalhost%3A" + port + encodedDevRoot + "%2Fio.quarkus.quarkus-oidc%2Fprovider" + "&" + "id_token_hint" + "=" + idToken); } - function exchangeCodeForTokens(code){ + function exchangeCodeForTokens(code, state){ + var address = '{info:tokenUrl??}'; + var clientId = '{info:clientId??}'; + if (state && state.includes("_")) { + var parts = state.substring(index + 1).split("_"); + var index = address.indexOf("/realms/"); + address = address.substring(0, index + 8) + parts[1] + "/protocol/openid-connect/token"; + clientId = parts[2]; + } $.post("exchangeCodeForTokens", { - tokenUrl: '{info:tokenUrl??}', - client: '{info:clientId}', + tokenUrl: address, + client: clientId, clientSecret: '{info:clientSecret}', authorizationCode: code, redirectUri: "http://localhost:" + port + devRoot + "/io.quarkus.quarkus-oidc/provider" @@ -262,6 +287,7 @@ } {/if} + {/if} {#if info:oidcApplicationType is 'web-app'} @@ -275,10 +301,10 @@ function testServiceWithPassword(userName, password, servicePath){ $.post("testService", { - tokenUrl: '{info:tokenUrl??}', + tokenUrl: getTokenUrl(), serviceUrl: "http://localhost:" + port + servicePath, - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + client: getClientId(), + clientSecret: getClientSecret(), user: userName, password: password, grant: '{info:oidcGrantType}' @@ -291,9 +317,9 @@ function testServiceWithPasswordInSwaggerUi(userName, password){ $.post("testService", { - tokenUrl: '{info:tokenUrl??}', - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + tokenUrl: getTokenUrl(), + client: getClientId(), + clientSecret: getClientSecret(), user: userName, password: password, grant: '{info:oidcGrantType}' @@ -306,9 +332,9 @@ function testServiceWithPasswordInGraphQLUi(userName){ $.post("testService", { - tokenUrl: '{info:tokenUrl??}', - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + tokenUrl: getTokenUrl(), + client: getClientId(), + clientSecret: getClientSecret(), user: userName, grant: '{info:oidcGrantType}' }, @@ -322,10 +348,10 @@ function testServiceWithClientCredentials(servicePath) { $.post("testService", { - tokenUrl: '{info:tokenUrl??}', + tokenUrl: getTokenUrl(), serviceUrl: "http://localhost:" + port + servicePath, - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + client: getClientId(), + clientSecret: getClientSecret(), grant: '{info:oidcGrantType}' }, function(data, status){ @@ -335,9 +361,9 @@ function testServiceWithClientCredentialsInSwaggerUi(){ $.post("testService", { - tokenUrl: '{info:tokenUrl??}', - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + tokenUrl: getTokenUrl(), + client: getClientId(), + clientSecret: getClientSecret(), grant: '{info:oidcGrantType}' }, function(data, status){ @@ -348,9 +374,9 @@ function testServiceWithClientCredentialsInGraphQLUi(){ $.post("testService", { - tokenUrl: '{info:tokenUrl??}', - client: '{info:clientId}', - clientSecret: '{info:clientSecret}', + tokenUrl: getTokenUrl(), + client: getClientId(), + clientSecret: getClientSecret(), grant: '{info:oidcGrantType}' }, function(data, status){ @@ -413,10 +439,34 @@ return servicePath.startsWith("/") ? servicePath : ("/" + servicePath); } +function getTokenUrl() { + {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + return '{info:keycloakAdminUrl??}' + "/realms/" + $('#keycloakRealm').val() + "/protocol/openid-connect/token"; + {#else} + return '{info:tokenUrl??}'; + {/if} +} + function clearResults() { $('#results').text(''); } +function getClientId() { + {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + return $('#clientId').val(); + {#else} + return '{info:clientId??}'; + {/if} +} + +function getClientSecret() { + {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + return $('#clientSecret').val(); + {#else} + return '{info:clientSecret??}'; + {/if} +} + {/script} {#body} @@ -436,6 +486,33 @@

+ {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + {#let realms=info:keycloakRealms??} +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ {/let} + {/if} Log into Single Page Application @@ -589,6 +666,42 @@
Decoded
Get access token and test your service
+ {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + {#let realms=info:keycloakRealms??} +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ {/let} + {/if}
@@ -643,9 +756,45 @@
Decoded
{#else if info:oidcGrantType is 'client_credentials'}
- Get access token for the client {info:clientId} and test your service + Get access token for the client and test your service
+ {#if info:keycloakAdminUrl?? && info:keycloakRealms??} + {#let realms=info:keycloakRealms??} +
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ {/let} + {/if}
diff --git a/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java index 13335c8a8dd2bc..b052998ecb909c 100644 --- a/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java +++ b/test-framework/keycloak-server/src/main/java/io/quarkus/test/keycloak/client/KeycloakTestClient.java @@ -32,7 +32,7 @@ public KeycloakTestClient() { } /** - * Get an access token using a password grant with a provided user name. + * Get an access token from the default tenant realm using a password grant with a provided user name. * User secret will be the same as the user name, client id will be set to 'quarkus-app' and client secret to 'secret'. */ public String getAccessToken(String userName) { @@ -40,7 +40,7 @@ public String getAccessToken(String userName) { } /** - * Get an access token using a password grant with the provided user name and client id. + * Get an access token from the default tenant realm using a password grant with the provided user name and client id. * User secret will be the same as the user name, client secret will be set to 'secret'. */ public String getAccessToken(String userName, String clientId) { @@ -48,7 +48,8 @@ public String getAccessToken(String userName, String clientId) { } /** - * Get an access token using a password grant with the provided user name, user secret and client id. + * Get an access token from the default tenant realm using a password grant with the provided user name, user secret and + * client id. * Client secret will be set to 'secret'. */ public String getAccessToken(String userName, String userSecret, String clientId) { @@ -56,13 +57,47 @@ public String getAccessToken(String userName, String userSecret, String clientId } /** - * Get an access token using a password grant with the provided user name, user secret, client id and secret. + * Get an access token from the default tenant realm using a password grant with the provided user name, user secret, client + * id and secret. * Set the client secret to an empty string or null if it is not required. */ public String getAccessToken(String userName, String userSecret, String clientId, String clientSecret) { return getAccessTokenInternal(userName, userSecret, clientId, clientSecret, getAuthServerUrl()); } + /** + * Get a realm access token using a password grant with a provided user name. + * User secret will be the same as the user name, client id will be set to 'quarkus-app' and client secret to 'secret'. + */ + public String getRealmAccessToken(String realm, String userName) { + return getRealmAccessToken(realm, userName, getClientId()); + } + + /** + * Get a realm access token using a password grant with the provided user name and client id. + * User secret will be the same as the user name, client secret will be set to 'secret'. + */ + public String getRealmAccessToken(String realm, String userName, String clientId) { + return getRealmAccessToken(realm, userName, userName, clientId); + } + + /** + * Get a realm access token using a password grant with the provided user name, user secret and client id. + * Client secret will be set to 'secret'. + */ + public String getRealmAccessToken(String realm, String userName, String userSecret, String clientId) { + return getRealmAccessToken(realm, userName, userSecret, clientId, getClientSecret()); + } + + /** + * Get a realm access token using a password grant with the provided user name, user secret, client id and secret. + * Set the client secret to an empty string or null if it is not required. + */ + public String getRealmAccessToken(String realm, String userName, String userSecret, String clientId, String clientSecret) { + return getAccessTokenInternal(userName, userSecret, clientId, clientSecret, + getAuthServerBaseUrl() + "/realms/" + realm); + } + private String getAccessTokenInternal(String userName, String userSecret, String clientId, String clientSecret, String authServerUrl) { RequestSpecification requestSpec = RestAssured.given().param("grant_type", "password")