From 77e9fe91f147cd841a3c7842ce1d7dc83b7beab0 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 18 Apr 2016 11:33:25 -0400 Subject: [PATCH 001/149] first commit --- .gitattributes | 20 ++++++++++++++++++++ .gitignore | 47 +++++++++++++++++++++++++++++++++++++++++++++++ README.adoc | 10 ++++++++++ 3 files changed, 77 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100755 README.adoc diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..2b70adf8d8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +* text=auto + +*.html text eol=lf +*.java text eol=lf +*.js text eol=lf +*.json text eol=lf +*.jsp text eol=lf +*.md text eol=lf +*.properties text eol=lf +*.svg text auto +*.xml text eol=lf +*.xsl text eol=lf + +*.png binary +*.jpg binary +*.gif binary +*.ttf binary +*.eot binary +*.otf binary +*.woff binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..44612eb8b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,47 @@ +# Intellij +################### +.idea +*.iml + +# Eclipse # +########### +.project +.settings +.classpath + +# NetBeans # +############ +nbactions.xml +nb-configuration.xml +catalog.xml + +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log + +# Maven # +######### +target + diff --git a/README.adoc b/README.adoc new file mode 100755 index 0000000000..ef17956cad --- /dev/null +++ b/README.adoc @@ -0,0 +1,10 @@ + +Keycloak Server Installation and Configuration Guide +====================== + +image:images/keycloak_logo.png[alt="Keycloak"] + +*Keycloak* _Documentation_ for {{book.versions.swarm}} + +http://www.keycloak.org + From 2f36577356b054b22ffb446189bf276e5372fef1 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 18 Apr 2016 15:28:19 -0400 Subject: [PATCH 002/149] initial move --- SUMMARY.adoc | 14 + images/add-provider-dialog.png | Bin 0 -> 90246 bytes images/add-provider-select.png | Bin 0 -> 60459 bytes images/domain-mode.png | Bin 0 -> 105612 bytes images/email-simple-example.png | Bin 0 -> 14926 bytes images/identity_broker_flow.png | Bin 0 -> 21625 bytes images/keycloak_logo.png | Bin 0 -> 18350 bytes images/update-server-config-dialog.png | Bin 0 -> 67031 bytes images/update-server-config-select.png | Bin 0 -> 82234 bytes topics/cache.adoc | 58 +++ topics/openshift.adoc | 44 ++ topics/preface.adoc | 20 + topics/proxy.adoc | 238 ++++++++++ topics/server-installation.adoc | 610 +++++++++++++++++++++++++ 14 files changed, 984 insertions(+) create mode 100755 SUMMARY.adoc create mode 100755 images/add-provider-dialog.png create mode 100755 images/add-provider-select.png create mode 100755 images/domain-mode.png create mode 100755 images/email-simple-example.png create mode 100755 images/identity_broker_flow.png create mode 100755 images/keycloak_logo.png create mode 100755 images/update-server-config-dialog.png create mode 100755 images/update-server-config-select.png create mode 100755 topics/cache.adoc create mode 100755 topics/openshift.adoc create mode 100755 topics/preface.adoc create mode 100755 topics/proxy.adoc create mode 100755 topics/server-installation.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc new file mode 100755 index 0000000000..b8b0dc4a3a --- /dev/null +++ b/SUMMARY.adoc @@ -0,0 +1,14 @@ +== Keycloak Reference Guide + +//. link:topics/templates/document-attributes.adoc[] +:imagesdir: images + + . link:topics/preface.adoc[Preface] + . link:topics/Overview.adoc[Overview] + . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] + . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] + . link:topics/cache.adoc[Server Cache] + . link:topics/clustering.adoc[Clustering] + . link:topics/proxy.adoc[Keycloak Security Proxy] + + diff --git a/images/add-provider-dialog.png b/images/add-provider-dialog.png new file mode 100755 index 0000000000000000000000000000000000000000..976e5e148d74c860e2c000e8c51d3f65bf7e73ed GIT binary patch literal 90246 zcmY(qbx>Pf)He#nTC_-UD-`$QMGF+SV!_?rB|%GZ4epd;#ogT<3KR(r!Ce!a%k#e9 z{qEd7b0#@wCjab{wbsvegsQR(7CI?90s;b-oUD`@0s_(%0>Yd0w{KpbfI^RbUq2At z)MO+ODksSgUT=`CzAAl1K&Xkscr-zIy?^H{tK)`%fam_-g}7!(<&A*wQYa_&Rm0ox z_-UbuZpd#h;`dA711EfQEzD=X!E!a-<1FKVSFLWq21a^QpZL#KkndZ3(!Mw#LHd`} z^bb}r!duD3A8?fS;v^b*=sO)%(2nJ`+>;LYvwr|CxW#Rc&nj14lhJLftEi_zUtz=M+*d^gjH6f?A;p@EL+b(Mg=kByDpg89=GwaPwNA;%3t zukKFAc3ely@f71M%C!v)4D|K0GBY#N)6=zhczNk0)c#vu(a*;!FIy@v*HbUoD$kE9 z!vUygD|cg40nZq@cjH|?yXjVy25p`*qBT>vXnwQ9&Wp*=RQOgmZj*Rpt8-C;GDRa?s_s34a;O zeO`V!iW9v$dxmyBuLRs4pS`38z^Ptt;V&Cg&$GFYJ5&LiWdRp}^}87)q33&0(hixB zr*L;|K!$Y8%DOpLU{@uvQbNk>>cs83+s*WSZ)Iz1Yhu!4S+`2`78&7|D&Ubz%q{Rq zPtB_?gTH)`qUuYc_M)utg%X(2B~S{^g!dqMxR$Wk7TMoP#q4rzuh!sS`p}XnHF^?aaW$S`V=~cc?^y-$o4*McN|GimP}HZKP=A!xS z9n9|acpfZC4Y>Zbw>d7h?>Tk*!dLzIe?s_OqS*N}&jPN$*FgH=_k?XeHom|A*?%BY zs!-77-<*%Rz3ew{VYrOt&A8tTLYmVm`)i-w<@t29o?nx>U=;AQH4uf5k6%_+25(t) zG=56$dbHs5(>sh!GLD@76mC|H?1-5h7zL(lHoGcyl>0zmQw{dsQYu+t!(BGWUqql^ zd-wZ{pr7bL61GUPH`A zxH_<9`o|lRCg47Cxpq;K3eN&v#>9DvUQJHr0*|Is;jiDosqoyFlaT{jC|`jNCgC{b zN51MgA$pI*$MP?^0E(^29U#TZaO*W=*eELjjdKk#bMl+Qgf4xUCiBr;X`Ox@k!_=X zc9zrPr4p#qf}@^1B&BYVKDDvN2Zvx8`}55^;Gm&65%2W(M*Y5wGQC>oiL8>0nGa^A z_KGQ3BMBeB8qyL0pw3?fw6r0^@}@a8ao=}$C&*^k{~6oDb`{Aod+D9b-4&?v+Z+?P z_aDJABFPm;B|8`+kN8MKF|!cbZxhCS3J$h!q{$aHiPYd#AA zPDC2U5fe6s1;}an>r9lfZ91Fp-GSVs0UC1#xrZ^I>4PO#D{L}lMR#sO05FRP){}^VCzLwRy^2KOmzw2=5u(OLciNPD& z#!o$>O=@q7_&9<9NESHVO9@7_*t!?O_#jy8ID-a0OCJdm!DYi z)WB~oYH~8Lun)B_O8k(nTDjV=CPkPtfKZDdS%>jw~(+7yOS`AB6f)1$7) z>>MEq+p6zmPz1I0sfm6f1y>Z|?ve;efB!wM)K*V?>NKxg?~@ptR8u(aTlPRg@wuDj zyZZtbnIC0Y<>24De3CXMLqJEPg;^Y&TZ~w`#)URBfo!?lrTXvU&8fdiW8R=PU#*}H zEyHlirgB2X$d}_09_%bKIJA~ev#F4@(Y=p-rQRw7+tNzQ1H*G?gHN!lX7$eV*P^Je z53^d)d9lru76o&I(bI-;`$|Ma(vlU2(aUSA!KM-w=Hv5RkHBZ>yq~LzOicSn!HP&g z8)fo{if24StIV7q#XT|qsoP574ROR@=`Df=op9ZbBStUD#nSsDBY=h^h|!&o0`h)X?=-AR5Gl!_FxP91Bv&`Lf!k3J(hkUlx>Ll zeSLF8Ow>si(0GXId6UZj>By+dX(*NgP-XamfvZGF`wgQsp(NbI z*8bBZOTL2m1U+5%o;ow##i zE%OZM|4Dpnct1tJy_F8Tss~SXO3K`b8H@g5RV?7}#3)V~w(2}JwA8k*UlY55rjv?N zh@xFMX*!+3k*>BgXYIqKoqnTbDNN_fetV>lHz;3#Sc}#|nrOeBgL<~SlAS=73OPf=SdU3kb6WuXEd1Cd z1<#7}b>p)b_*lMDiEIhHIUw}dYXAHj`JcVq55LAw%Ce>=f4oO07)COqL zJ>=&nh&08XwUK1&DVztFt7J_*T={tA8FLU$9Bk=k?HZ5YF{_`>B(-tw74|&LG0Ofn zk>_PiFJfCTpB){j2gwAf@UIWD*MAG!*5mu^0Zv}2wwyNeaBH=c2gEQnOC(O?TZn@F zc(LnrE^D^XTdMKcSaBLWcSXj2H+?zrPuz_;u;MzQbXaR2*aq3(AmmHlr{By?aJFWD z2{5;6KI(JmbaC?M>+(Qe29mS$8u|uwRW1IVnw*N=$`GjogF_*D*1o}oA zPM)Z%I)JLr&8K#CKzlU_%?o;l>R>(zmZIX zE7V&p^3$IXBmwqhxb$Q8*i$&Jer+xCrt3H%Aea4XS#mw3PtAssupB%rpC3!fLe?Y@ zvATyn74F*giuk9WPmxS5#7oE!jOMdV(1-Ofy-b1lu{&|tT|2K4XAyeY^pp>ExmkMvxTM+&X3~q~M zw*}h8cr@$6HI7c@Cp0TtM?YAVY_XK_SATemj`1Qe|Om8OYNaREqYv+yqRXY@4;P9H%pbh8P|JjC?N&}^~JYi>O# zb%yb58bR6CjVeltg?jh56S@nZSUayL4f~;WUdepoN z$R=K!6nHUP%`3QH^a#AzK->{O+RRC8wH2#t9sZu9rvO{i zpL|z4wTl(e>-y7iDC;WOQg}y@Vw$>#U0<9JjEz%}h-_eZ``i*@5WiXm~GCIaWl|HUy z0qSfPWuEKU1j@E+;!srj0Nmm~0(ind-gbhkPS-MRnwpM%+n$z#(G)~3lC_Rr!F-mW zn{>j{Dl;}AnY{Cm^_Ke#%U72Ci2sJ``QE%j{6A|v`$E}%W;{A(bDW6S{UA_{LR!CJ zQft{KPs6y|=biuU`v14<^rBibLRhYj8_WYF;-B6Oi%Oc~m>#LX&Q)sxauhHwB!~%e zefU)3Mbcy9uxKi`)s{$#VbvYJ_-bx@@ZKf(h|!=p;_A= zowV%1W|u>X0b5{Jb<6kgd0{mr)Fb&@g7S)vg(v(bUBPC^c<-^#Hc7LgO0d6egLy+n zxdz^jD>-|zsdLRRMF<8;T8`wB*@?+}HPMi$Zvy24y-{kBt3Q1}z-UkOD@!k-B7sqI z6KuP2s97>P`GPVeONMss`Qlr5fns}pOpp-Ma@c$r|3SA$Y5!pwRiRZf*DFU<%;lIh zBF%$GOUo~|xA_l4N=v2Ncg`}ZBVtz*r-ogmWv;Y)!ZN*W8o{6^kP=9t-H=hG;hHSp zs2|E*s8*!Ct?WjGUV^CnnIR1tBBAI}Lu{p7O~lmA)KEW>mJtNQbSAWPIQ1yfSLQAr z-7#+&uhK*QTgOSGo-E(0He%eDK8-|1N|7w%v zZaXOFn8H~nG|yPQ*UP_RKvb}T22n+4qspm|eYs%ZXbp&Yu9& z4Oy})P8$6qj@o0`oixn7<1l)R9c~2Ql3dJ!|6IOu>c;8*5wmdQ1k4Y6$gZhf@G!_C7}k=yHEI5_eg93<`SCYK=;R2lklOzsIT5_J#`S8EQ~?3tr`V6*$k)UE zL>>1@!NMNEPjx?z53rXMLT`P48OswL-~DJ)J?CmZYoM~^Z+Ar_pdAm&nHA<-1&=}8 z1j)F2!>4IP_dv0?w^9Z2Fa_|VXVRx2w-NTgB z7{3Q>Fb8ey-LDdPE=!%O=s=U#+EF~2Yh3W155Q)QnTQpz{2OTjLCfD0O!2QL z9nNu_GlGV3z59m?jtzGd>G8bY1;>{PAQ=s7-XS{KLVrhot} z8DlSDk}mHI{orVS;sIG72Ybv9Hg(jP^6ZQ>=1x4#M-xT1@s;d4b*raG5hYAn3Alg# zSL@&L?KBauMCpF`h5Uq7LKP{C--i<t;D*PFMPNv5;Jd^8WVQZR-hQIa}C{iw21hz|)2NU(OE1y%3n4W9$eFsPu zT{d^I>!6e)FShm+iMk+$r0*wZuKPXTDVYlsRvOx2$^%H6pFfvWm85P20b6=Pn?AM{ zGtY96ite9<#2D#}9=|*YG9)#qx*`RpzYKSedi^Vq2Alsf-w+xCispq(^?gn26JY=u z{?h$XnWbmqA*oSYeBoUvLVoH~wy{Q!sAY`J&OGs6mTT*yFiN8uJ-u#Tqs8Cl*tE{xa8RrMuXz;;Y1piyNW;BRfIe>c$8Nm>(4QcC6wd0EzT9j{h zj#&qK5i>GWn5*CRb6T^OB#hc)6+yT+&>Nw{@eteeeO$wEh=g}xrkazPu`=v-+wOsM z#GR|U@jZDx8Rz{EmpDJbZTr2~STjL%`Rb@#1D5_a!He5s_Cf0U?*|o$)6LvIzBmmUPrn za#CCo68t!DeN!*_RV=)Ra+$>zUn9x?sQFiN5)r&G<+%RMxqM+L85<;EMghig;seX3 z4fi>_-OjTsx*E%4@^TUE-4HdX{$SlJf;qY;jVU;#7$n@34GEeeN9^EA*Ngfw>88-L z@>|ZTVb9kTc9kx6T^>3^_j-=@15s;2N2>ho?5lmNQ<}=k4I4F3&f(P zr?)hN=~R4(1ym>xZ|2`1+{a($W>I5=K~{k0B4HrI*e`fhY`Gk^-wl;$wLEagdr z8V2dl-w86$qa{69yKFmm$_V3aFLJg=9v^nM+Xh{(+6YY8r5jRIqm2%^Xls=T2;{S3 z_RAEY!w&}#rZ9ZbhM;dWK{$-BGi_^%yZH=rnR|FQOJqfuqrl-2NkY^Z4-1s3uP zG$30B_hr89lmwmE%Q2*cQ8mhf;3G%Sm2w3)|*;_h(&*MoD1a*1BTW# zxnrDfrbhCsB6y%mJ=3$=Gu-u?_hNYcJ=3%<*X|1BdLnO*-a}Hys2>WkAu3(%03W_d zbt%|X`_;%8XtERJ{NnuF}G&9`foZjrr83l60Fh)i_j)`U5u* zv1cVKK~pPKvq*(IBW~+@))6fYH@sn4F7&|%rKq9U!SHRBM1_Kt;aKQygiof2^p!D> zc*nW8y30rqv8csc$TVIo?(H#ijFKiZUnXZ|0DANLA9vntsGrbY6g5Q~YS;WYq=5F?Tg-Z=@w8h$AN+ZMYn9W4b$T#0lcGG57DNgFF6cDSf_&kHQ56OXlUtrgZcjJ~+MO zXQvnYH(m$G9F0M~J=Pz$mfx^5;gQxp$m*27S1>ahj^$h}>&B>>>mEh?_Lc}D!eC)p zA87>F%1|=+{Fv~^NM-K!w?Sq`Z}I)j&pUn%E7AP8OopQeyK~e&;P*0`{`MA7Rm!x> z)|p+o#OLP$nX>xbuJ77odyq0B;uYVVCs}hRH&AemIcJKzrR$x<#lJh2S(aT6|060D zgWQ*k{I*GD)|~b)7%REFEe!Kn#SAG@jg(xK3xAuXF^6R6A9f77?-6P55{_jOe#KF` zAgroxp&9?jpfivk?A2Zw^pb4W??(C{-F&dfr+ej1Pz^&`f2@XQp>}*LbN~*hx&_D` zd(*$lNzhk03E>bd(95GXLg`yaz;47xA91Xr*d<{e5T5vy&vELrd(y{oBKS1PumCgC z7Zp5dHH}vJay5IpH4elL7dzt^zeBHE>m3K0EUBk?5*6u($n7%yT)ksb@dt{CK_{l} zFWsIW%lXB2#^dz30WlF{Wz$hC(->o5Hw7>TOAX85KMy^}(ZtM~9YTqgLTg9fbZ*Np z>h9!%=w#|V^&xtTcIdwzEV)CL;bpT7aX8*Az%-ptp5&MFP4$LW|WEmQT_E~_-1 zGpGa-@6b~I#kn3rLC6i5dIdjt`)3t%!VOEnickcDlF##T%u|D#Q&WgXvux02RI~bt zu(g&su=kuS0xey!&+*p#U=QjCU`(`l{E64(^%`(hy|OLJ1CVz*JX@BZg(4ry(~K$p zG3yKwVr=2@sAolqLyOf-df-EL`wd0J9nX8!y1iJKOvYeL%%^rJ$NvMXP%9Pa@Wa}- z(rExEx)?WKXwD{BL-a_|{DOHVW!4THPM1IA(4gDu#NKH{)Rqez>B~TJP2opSl3GU*n44Ps`1wWV4ai4zb z%)Qvz4W{U9+8r)ZoQxl4ld-W5_!yrF-*GPCJSz?}&cOSo*SJ5NN`6->qJq=oo)R8u zodnLaO%iMCn2W5}HF<2W`wFKf^FqT4j_B!;n>f%CxuKzaCsEPZwFXN%u&7K?Tu!ql zOLS0ZbYN*TNQMD}BPBj3{Tho(_>NKv?VjL3GLGlhIw%Ky5#>kkVR$h@w0&2EM*C_M2vVr{WENxAg~8>nQDy8q~><%f5*soJxM-xzM&5=MP7* zrW4=)Krl2xd8QmG6g<5Kt~GE%p{Q?YbsehJZ`Q9ymrE9y5+J+dBeTYG_6`Vbv=AzqEx|2od}LsC1q+Xb(^|RV_}5;Ma!Dn!;x9&HRm zwEl3bjLyLBq_UM>!_ zZr7?X*ZSTX8~V+}{~oxdP;mqT?6808@!+&`_gCxc+oIbLn}Z|Gm!@N2QYpcG5GQ45LU zPTAxbjpT>4`>tt7{Wx0}^L{@faN!1hlfPu^=O$Gfu$P}N!=e9jd%ff2_p*nkZ0HN$ zh^T{NRBEr0OteBnYAnX!0T zU9?}d;stx@|5wMSz39(O5NG>F(^xG1pW?Co^8uu6n(GmDrr%lhvGeE-+)am#9n(KO z%jRNlQ@{XHr>YIu4#CL*Lc1&1DFdM018@~Z%Jz1k>ynG-w3p*_fIpMBiJ-f`pt~cN zv*nr>(DP}VhjZ1#x7Wpe1)D0pGD^;b_e{=(zj zV-fjN(H#?mAv@)e*;8FSVc2bTCI)zY;>3G&ky2!GcE&2LzmNGg4MZ;J^Ehvg) zLUeX5IVu4R-A!*+G3OD}ILPMBoNl?b{A|VIE+&bIS*iMleDtVHf#BGhR;GIN zH%s$v%c^2F2)g+*y{<3KUk zV3QKH3dHgO5V9sSrgT=s1`uY=se1+%Zm|Q%n=eN+?OP&waR4sIf(inUZ~q3}V29q= zZ63;3w~n_HlvhfZrC@dhr{JtXNdp~mO%OLkFPAPg?J6zNRshH=Wl;FrX6ELtQk`0J zWM_(_%35U1kh@2c3PDNy+J(c)&oMp0(-U$(ZjzlThOX59IEKFxgVubhcgMnrX`;GD zSaYe5H+MHnKT`3?5CDiKww8Oc+ze4PzEN|zCU#KKs%G77>Lqz^Jk&fkK@-u)vk z;W1om6VtFOUpPEPH*lg35|NQ6wM!WmZ6Nvh1Z>&;noBUuey!5EJ3QAOazB(hD8VQO zptVYOlY+%6q3ihWq*N`TZ?J@Nh)TNoO56PxpP;!l-5p^+C5NP2Ox9BzG}6vBa?=J9 z_tRbg^G?_r{dO9=X8bqVdV$|b@ColQtOq{h6B?~{q(TL#cK1-Lu5f{zU(T~bi5Kl$ z`kMdziI?Qn?RR=Je=6$z9@2BKo2pw;6(b9y@^!uM?O$oRfYdEmO~y`;i-K;_7uMmQ z6wZ6p0c((e;{$k{uhSm47!Yq$1sRc}BVpUPAlQ70Ws7k)4+t4vD`I#sID6T>iOUIq@7q00c7V3;JKe5w^|`at zYICzZbFy4=kte2_<5a$gAIemw;}~&Kw%QALyWDh#B*(FrlQ%a5&l5H`ETBWFN@1`4 z!H74&bI@_wy5PwkC9erkc-tketfpNvd_t`xqK;_>xI4N8q9F=u|Z;3V8f zFUS8gU7vL$-}^&|ODW{}AmJfCC7(n?{`cJtl18 zJrCLMlO0vFH9-0+ls6dAak3Cy)JMl(&-^Y6rauf^x`_B4xD>0uoIvwW+F(qUu<%fk zkr^YwakdbJGaJRYT0n6D!Ps$|tucFL!$~Xl6F`EE2gEjSX!gR-S-3=~uUqi# zn_V8PwyTren$*;t;?4b#2Zk!;0xF_D=f6Live6AJoAa)J8p!S0Q1vjbA^LAQACBCP zl5GGsqu|`?*_ij&Hd87Bk%^}>*Fc|nK*m+-x!}=jP;N=RARSQI`?HMmfPLH>!~F`0 zQB0%z15u#=yk=UX6+=b3i^6>?6R+h6^+kD8GchxJ$bs8O)hsyCUOUf#-Kas9bHew_ ztgdEac6R6}VmTFCWiKv}Um_STX=`;95prT7$L)oth3d zfN=AD2LU9W+S#j`M1cH=$Zt;2%V*vo$0fN~e+S~B&#E~Q_<%kwcAJB91)U9!3Zkj_ z;qXgMoH;WcsT1ul($>jchM=Zi%sgRmLkNNauwuY&kl=gg2l1?8u(wssSa=Ol_%OIT ztC9@=roq}zP{XRNP4uL6+*?)GFQ!K%A*e+uqLoS42x%U42s*ib8lPj zIQfra;J(%Jjfzq5?j~bfw_(*h#UBy5zL#bRalt=+T&i#jvZ>Rxvk`vPq6j1VjndB= zMuRuf@pyqo1ISm?Kd;?2<4bfBc@=6cV;2-_GCr!+F&u(aVk*q8XzQ)RXZCb|4zD%J z;hI?KR_c#wTKhy++^8)_o$1z4FgD^CrlD_OklCf1DY@0#(C|ltTeNKdYg$m!YZ{DcF+C z0#zF)Y()=roR=hI=)JY$mAmS7I1o1_7O-(FCj5-v+vR;H305lBlY&WP2R%9{z}~Mf zDarkni4%y$BnnHOru${7fOqUR_DR-O0dKsa@EzQgpK<0?hBBp+LJy$X$K9T5rEQ$2b$aTYBE}47eQ4nLQ)#tlj%}J(LQF)90t6s3Xs= zra+oi5r~b}!7<|X^R?lMp`=OAhVcE!K-5E^i9+#|RAKABUs8!^g+ClSrFlzklyAKX|% z;K6BwB%`7mVgIvQ36TSN_NI{3Sybwcn3b|IwPKjE0d44fO_;p>ncTmo8+weq?=qD) zsI#nEzFMe&*v*gg+TE85dVCY`naiTA+v|bXb@pa;aYC6C1zqv?S9p*oGVj8I@Zi@ncugc>N}_+U>&)^eyUIv}jUeM#|=oo9hG)@}kgMtAc$9O}uc0 zV#l|v+6Q!uTqXe-I7x&*#)D?syQH|DXH2W>$q|q6`;ks5P+E-$Z({@LB(=Lz7|CWW z)MGc+w0?s@f5lY#ijT^rS;q24@wop`sK-h+wGDv{roA0y zii%Eh3(+-8YQOlP>~SVW+Mk>EGhiBfNDTw3Sc>h0w9aTWb}__A-1DxEhSv*w9gGE^ zcNk-q(eYt3SxuefC7EiNMe{>)2b@Eh8(*xc9ka%I~+29_%kr1^m~HvcFn=aZS_?u>&n; z+#U3B1RKe~#l$X3c{TYrZNm_sZ2vTpce68QN+iQ$4JAF^asV%QnI=J(Zk5N-wzb*h z>bzW_Pn_UdJ-uF|`&c^4R@17z##*MsnV3jTPI(pbD9iIqWLNVs3+v{BjY!wV2wQU< zM&)=GH}9V8yX)CR;~g!=$x)6LfGv;`n~HYHzvHeVNiJ-9@C2olOxODx#eFK2PFd4hNf_*&*ON zR6+<~=XVf9@iO#s4N*#bn#M3w>4Ggoi3VZhBJeVPQQ*bjJ3y>H@Gdcm^G#g4hq(D{ zgc#8t{dk=feClx8Frnl9`o{D(f-W#}+I4v1=>C>s9q+qyNW%YB#ecM4CyNK+G!yqC#AWTaJxhe*emMWF>F*QiIO=PmA~9SsCjXwhU%2CQ~ILA`FPvbqM$H zIHecZ{xwLZ*dJuSEBQ%C(){J(0}I0gH$`n6dM*4qUWBYV_hPq5zr{sp^65ZM#&a+` z_iBdvLOzLd)MhfpexSBYBX3$&^?Qq@!W^LQ#>dNlCMBbq{t_cGGS9{ZcxUr8X}s|0)BA%@vi7% ztESlKqiU-GqNiB~iD!_^59Fy|flq^$#0l>|g}!qoeFRqTva8NR(_df9-jn17FqPLL zkM-PV74z6k>2nWOlK!@arLhTZGAmaBy0yo8=1JQ)wZGMf#{0c9@4~abFacexBX}nN zVAH(>Oc&Tm2ZGMGH?MTv zO<^;tjEnmDn>U-M3tOZJijg**(VHH<8E9YKgY_Tr+I z;$o4FhcP=BY9@A^%8Z2O$mZr~dB0*S5eCbZA^Pm0BK>031@zdU>kkUBRxF_}XpZ#m zjTSC zF}so4px1$5)VMp=_{OD+4Zs)lkiRn^Zt;pC`wEkqB#1N&b@i_SDQ~U?_n4rh2dzvl zD5>ma;3yXG)xU27e6Dqr`gm{4hrrw>at8eUmA_K8XoymJQ|IxZlQX{6wz9aL%TcCp zaH=Uy>|()wMYb$j2AZurC=ek9UWFpd=y~U-P>cw>U1ZM{$N<9XFH_~XWtT#Ybc5m` zXL3%KyjYt@A*m||!cAj8M6^sC?YQ95FDDWYQBW=YL;|o^gi_;X@I9&pQH$Y%J5QOa@IvN0Xo3auMWVT}y*~0x*>cH1=j}|xkSp=BM0FeBK8ly=!PyBX1o&Eb&jEfcJX%yYf7IX(&9wB*PqaT&4toB!VR7a8!?(6` zFb{R&Bl0Qj21k_=jO))iB3$qKKVCE< zo{V%;f8MJM%Wulrl339Pu49m{ER&8ulw=gV4X5|)eY#f-ZF=jIv!TF9H-Q( zJOQ-f!&W{FU9|X>KxoqI!rCaMV3=mvsoF%=AGX)PZsR`>v!Bf-yvTn#nh9GRm0lyH7(w((lP1u0ROzdY zgE?cn0UWK$DG+mAQ?!Ll8nrh1yQ!75AjtPQ?yW+pgYx_N zD%7L8O5yIEt%R5H@`vm4%%C=m4S(A~q-s$~@h*Q-u=*rEzUS?2^V99mCt~3P;UJ!? z=eod(onfC1CUHX4)I>9)z{bIT-jL&B5tQR!Ty6X zFF^2#^T(i+tTfjx-HXJd-C#g8l@Tvhx_eF*ZF85kq9N*#-i$HOc-_M-!vM2?cyRke zx#^1}vDYQT=V@_KPe$?Fy63DotYsMmDcE%`Icb8|g&eHpQobH@zxV+SZ>NC(`hbbs zg_2uxsaxJo(0j^gRy^K)ioSs-ZJgq>q?u7&P_>0_#pUejPeI}BI_O58Ex3o|09{PG z(sKDU-aIDY`u6Amox$7xqqpT`97dqs{7Q6HD_&JbEsv|y7yvRcO3?i~{o9wohtZd8 za+EL8fH%BL5xWAh$nHxua%i0b&0DSJvW9i$496(l_m4oo=`g!*pWjkOxovnm`K6?X zMI0{-q&@wt5IA6@#WQz8z%O3h?@T$qOY7hgF&R-=QkbnQmCgF2=gQ++kQ-6yYi`ABpKp2#wQX?Ue^%-8F`g&QskN#kHBC)H+S^;08gJg5Z7z^9 zp7gR|i!5tCxMA)Ty7JdYg5H<%oUx5p?zw1+?euCQf;+ej>n!YeJ}^u;JyukNh{JY# zRQ#8~Iv1Afceg)yHIV101U~<~DcVo_=<5Ipuo(fFtoeCPdN{86*?j93sU#tM+WA00 z=8*Q6tmpDKzZjYt+&uMZr{S%0?%?qW377rZr&^~oAzo$kv$^;VZjmEdkLopIa-*xb zigF_(!>-P)j?P0e+I}3RbVPUwikH7lM|ZTiKSWQv$VX^LQ(xgHX^Qr8&gng~yK2voi3Jc;SEoeF#F)u8wQ-f(BbnfWKQdncj9 zYnw3WiF?USNY!g=no=33YUaE+oL1o3*==cxOg@auS$%p8;?^yvQihExl=3)t4eUYO z8W$>O<3)@fI5Zj=Dgg^}wF?o6L)7mmzawa{UWZ?e{ukDwdyOt62z-nP$=hO*Ni}At z$1Mai)`uN`Tm$WE*KiX=_>~+h)lhp3MV)a}+!BTTcS!8$KLQy|86hb{`#&wsMHxnf z3=#Wgu2SbB4g)E7JYDSIs3=o3*FTQ%;!{zY~1T;z+6t>nKF}z}z}lk}{u@1Lg=AdQn%FKPOHKD_<#qe=vQU0=Oj0 zQ`%F2Oe5N~dFgC1)@GX1|Ge3EHh~1ZD()t9m|t>T35gyz>@%=%*o{zrq3MnJQ@bje z-1ibx&m>Uxg&>z*%;*w32TWkrPALm2aOaGYI}3}unW;|FOc=0F30x&=>7z<W#E#hgBxKTawZj_M7bNLIxF;M#4@C%p1c_L>7Ooo*WAZ2C^G#HS=$&;&tS^-s$O zRqE-r?9&xbf=cL3~~<14du}SNFk@f(UPD zu;LYM2lx)0PY=9`iX_-^khm$}6srt7DPHPC$q_Y(&u_m~@LQs1O5f`=NkxFuYbcqE z?GCG`&Y9M~T328Zs=Bz8dFxohRn;TbnRsEW#i6mNyi1Ad_V?@@(xVDBm-0W}=UT2Y zj15Zp(5V?>CRueD-(T_^Gph)0&Lri_HWJaZ>clfvQ>Mx>OsC`XwF*79-t7OpI+i#u zT&+_G9+^5Wqc1tK)MVsfm2rdcqD^=3g?YYBi>e-$I z3>7V}cy2~3&6V0E8TD2&X*{W7nRo)fhXo0?jm}Lqh6X7vIVS;}wtjSV8S!%LiF%5~ z7@Ms-ii+)biZc}Qb#$FhZm|s4*S^k9cgfDE%?)Ir7%C=bC>B{<6&Nhi-yz{BtsJjR z-6fu%0t!HgEIX2uohOohA5j5HcDrw+iyY0o5UP+%F^*7vJx21wC-b5jok@s@-A*6t z*?3K2V@Mc|;L7kAYnJsoskEYOwT*249N z7;_Nt$C0sV4QR&&LiVKP(g9u}_87x372_uC(yA0EdR;1TvubcR}mvhSP3Jz`F~ zjA9Nj;37Ia3mC1*%-h`ML@sd76-i%^OsaUC|CYe(nVqU=n*a6Q*&^^0w27H>TS`u%ysfb@JNt1%I)gD#K!n{rtrZR-UCtIog$UmqwSwZ{msxt z-eoY0CH36YZDJuT7JYS_gG(h9LJ2ZDloVr>MdeL)996fJW6SaVbNHu6ud z!d9}giN^;fuu;3x@Z+Gj^E~II@mQTQ-o5FWJxrVl{8s47Fpd5jwGlmbd`K#Dk-+3> zp^L)frS16)`mm_8Ba^cW-5c|5Gg$vM^Ze{E|LU0llu>!v)gI`6*eZxv-entYV3KUe z=Ni4Z|LZ^(1t^1QpOe(lJ7c&l37+*cn9I82+lV`iy`Wsnvho3zddr45?#k=t=fsm*#`6h<^m z*)mx(RA73-tLHziljZy!$+Ck-Hf}22V-UU}7IF+Yn70KwCWxqTJ4DNoR^(m<6S(AQ z=3u1keZAXwV4RrZ3Os}E>^S@MyynM)Zhq~_>G_k#=)`2@!m~3xDXE5vbgW&MG_Sy1 z4+lOkI}QB>`Tq}DUjY@>*1ivdAR-|t-7O%};Lx4Y9l}VblrW@7i*$E4L-!EU(#_DF zLkSEZ^&juOzwf)>`oC*Yv(7o}v*X=wJnyqn%`$s}&|`cqCO_@{FgsoHUb`sA0Y>$y zwy$8~du3G8NE4PzmnC zIMzwnzrHIGa1Ao;?^SXp)jcU!X|=8WnG6xsX(Y5hj%?MxaviJM#Xknjw6rS4!PKak z?^?LR*&yeg9^`nnnN#O0T;{H`cz2hIR4`Fzd+**_(1 zPnw{VE#oXhC{g3 z2svxYm)zcC6>2U69tB6rOi7Cd%I+iz<5gaYCWh?14x^=-raI2Yw z;#NFf*>W?iq~V-422EFbn@puC9V@h3IF(QC4K_m#7#zrVt91El)L>vCAp2HRupHUuO8iHkcc(*WoW#8OgNqP z6>yJn*{XuVu>oJ%xx-GT**0-iJk72?&d#3P+r;X2Qdy_Y4%0$;CB7>|*Ig=+LT%H_ zW^_x`^P|JuB9)$xwPpE-D83K2`5&<7l)G%+u3q2iv@g&E0l_nO6;ldyzzBcNYw z%)P-E7?tN);A)$*(;TSZltvu{A{|m$#7T%4 z1znO(?wcn`x-Z`E+_gQzUW`m^C%V$HcYOf=0X(DYmQ!s4&h#Po4qq`D2)Qb7kqw^2{MOT zHB3$Xy_K)>bVhi_d}GII(Ie1Pk(|A3lu?~l^-pznk&2KhxdhqkVSTu+J6XKOx;U#RIfRM6%}75Q))Gn<}vAz#yvF;Ur}m%(RAhS zKQ;G4fKseZMC5#TxGjoN72IpxE;8_$C6v{PT^#=tBP;}LAVSiZm5t62#L4AE)qj~_ zup}bvFl5NpCkUOQfF!=I@>Opx)_pO#loo_^2FP;a+<^wdHW|!ofTQE@$Q6Sv7G9%a z95Mk4SR6eUbTTpGcO`f}ci+ z*PG@6^>-=B7cFJ_BYNd28}&h#zrHefdNO<+s-oK~vrXKLtDJIqI3JoA>YGkxK!3<| z(b<_RLqt}}Z=7u%mbBjwwDWBil)%?uTJX>0)FLDE>*Z9H;GSp4I=RoGwemOV50-{A zBp&vC8d*l*DJ;r~7A~Vkq63w_3lVraxz|9s*#qNiQAuyh0EfYh^ThtwVQgjViflQU z^I<%S?5>{d-vfKrhA7&qnhuxga73@*oLRo+yN<@Uy@;zuT$D$?~=z!v`M)y?k6czUTC)yKY7r(g8ALt z-*dLLJ~lUAiQfNiFEU=e9VWX)1hXE`9pkb*T^=>SzSmnr9X_z2Wdt`198r-`eO@x> zE^@yB&h$B)Flwa&?Ki5n|DvgRce~TRyZZ2KKg-AEWD0z8Gg5XUdbtoX*52$l*NSfZ zd#$q!gwxi3(wRm@@%a|%rXmWvz4~$O5QNkId%a6XMBw_@?H2K>@bwR2^h`gOlUlIf z^+g#1y0Cqf>Fs=l-@4-KJ!cR##dH%!?Ebh@aFywG8CYZ@Spyks3ywcU2Ywv{WqF?G z8J$piZ+8beQVLwdy8>HrD7{bCx>hOQU5ngGCEpq~Jom+9zd2otXvKN=*cYPO@oUA= zcqx*U$_IXFB6_=n&)Ifj zVkUat8q^6kyy|eNoaa!<=w@`Ez`=~^<+qq1-21ydgi&IA#z**P3Hzn zOUy)Uv%}ywz1r*$45Tc`n|)@bF88-YOm@v&E<33&c}O;|urm!_Amfj51ap-4aFE0y z)Kr?;&$!*d3nVYex0VXK!?2@TBri*jU5l(l@`@)Hm^J)NUFgI*lGH||Qd;{~ig@Wvu zhlHuO-y5JVadxr%fhRmK3en9}1TlH6S9AyinFEjbFq_x zelw1z;h60k@pOJO>042U&2|b#{anGQy1kiE%|uLKsnC;~O=qIc-yg)`!N9?I7QI>q z#g;bGJWqkC!);v0h0;LvAKz;*j720|kbbR3+d zsO$84=wmYl_$3e`km{BC>WJN|FNKPmiGu@Ob>#EBsMx%69iulErpD;6^rD8nqLAHF z*;S<{$NL6)sjga#%k|b`-qD@Q1G`g*=qnEx%@}P~7UOVm4fGYd$s%~qd5v+lkH3z@ zz(;?W_)fW5&+-~OKFULMhBAwb2xr3tJj-q;F&dAV5uGm#RFWr0(-|qj08y^y&AeYu zv1;1jmCd)qB)02nV~FOybz$@yB_CL%`)HZlp6PI1gXLJbuFO9>b$J%%*qWpR`Y3v+h7&bRYUhPk z_SAFFwo{#`7ccTAfir2PPd|+~l@OLS;9Y8`LcZ~>+7Qk&`LVG>URBPh@Gq2j3G3PS z4;{(nP>k{g?zf2QT{8SUtj=Z9J{@N={M9qGBGsE!daGuh%4#;q8fvJjITy$4SaUp9 z_oKi)S0#ve-uB~-BCvkPv1r3FU7CBc-n~53i|hf|OUBkr_taA0@Wt-CiC9iGtbDS> z_cKI!VV9%yB*=>SAD(N)1@-Md9<)AAJs$ee)a<^a8C6ujiWX4+#;ig~7M>?>;%p3! z7g(}W_=7e5F8ddlj9)reim{qx*@;s~=jAG$8E4HsvxK@w+jaXP;cD$&+LJS*u_#n$ zAR>thAVuUEu2e_cehxk~Um?`~DA;7>{K6o_LHc+->I z=;B5$?Hli4oE+B?2*i(R~P=4Y>Br2J-P2ScV`jB?q_Z7ZfJIjW3JBNr|+Kp9s|#%plxAkV!La zKTBAF?qDA}={;+9PLx)#qmRUN_hwEen){DvrpZ$N;C(xrK=40*_ZdVtm;kA4bx z488o-Mx`_sd;kqRuvSp|ZhQy)z+aKN;eFR01}t`%HPA!7-|R^#;MrK#@+`$3+<_!u z2m=HuiyH|X$kgp!D(ydxHFyxQFmwSpkh~N0IHTi(4{j7|U)pj^m!ju*_kNl7Ht7kVEGAP}9)F|AsF#Gl_gQPiyx!D>>yIDtWpWrxt|8kJ z(W>*sDU(_T0V^9@T|xMMPwlGr=H|PNC2bWZ7cGhJFTR(`%lZz-wmWo5t9>5{D{8g7 zsXgsIr>!7?DH!q?^D*@AnMI8pVGt%sTwMH4aB`kdt$0deqMO5Hjz^vc4cIWNYr-q? zFgm+3CW-5vv9e~7%DYsInG6rVEQuuns&ZE6%EJ|DQms*%beOhYe;r~ws|f(yQ8G3~ zO*NvhtV_e2335YBIYRb5lZM1|-3|LEeP)_wd3!h!hT!*T8bODl+K9TJc(FmOipal{ zCfaa9Ob7{t_gR%E=n_gXy*ov^sxno32d56pW_fj~K7xy$LT~p9bYL+_0=b6Lu8aU} zD_*aeuZJ?QlAkay`z{j$?3vkIAfiZu)bbqH^GSK0Qr;!&Y|-Im`3Ctd>gxH`C~ah|SX6(P7IFu% z*`!gb6OGuIqfvO(0=_G|_*nbJNK#5>9*}uVG|b%n+B;7@&eht*T0?ScP)&X zr5&vW#e&kzT*)eV`B$ufAw$G=2Ea$9^3aTK|#{m94D(No!z3 z9Sr;$-6ohB&_pzMdWWUqDRX+DXxS_{d+wo`gB;_v7;@rUYTvu_^}T7#$nqHYhOPJq zX;I@xL2i4G!lS_n4cGZ@uEkj^ZY?|C^)li1+muI3MA+WhCbmVV$Kx<`V~a~FT`oA{ z9D&6E*0Nw6Aj15VVL_2S_>KyYyi3DeDQN`D3Gs`JI6C+I>1Dd=T`zif_BeRj4;(av z7KsxGPHq_x(Qh}?9`JpXmVtLH-wYp{bkv-rczkcGxq=<%ZK88lWTqN)ILKG;MiLMQ zUSv|I`n)VEQu zubV0fc#is@3G2k>`^kj*SAdV{5Y2=gyz*YM9oH!}JFil9$BKGm`?I9xjSG3Yr57VQ zP@u<*n2iHze$=EL$s2x4uQzpRkmH|PW?+wzmm5>KzUcsNCWR@Ba=E@0io-3(fTz$h zb2$99`C zZ&eY&l!l4H56JaJ?$?d~&h-`~P8b8>#`#T*um@E9AG+?taswb$v&Pg0HPRZTO+;(~ zCpT%O-%4Uxl)?E0ewEF4;y*bmF z$?#x4T7%(&T3igQWida^{I7i%u<+QG1ta3H?Ib)$WtBRJih9rl)VO-e1n#uyX13qE zamg8f*VHjLD_-ew%o>^UhooW6yOg7k_m|F~Zr+O3A8^c-lYF_|rp6jPKR`N$QOTk< z*;c2r$d9!Z^{+6!S`D$~p{KGKi$INMI`GDsq+?-oU1U4+NnCj+E#ptZ_2Zq0GBMJR zXGPWtd72)zAy9N^YcbxXS1>Xl-BQNC!-vQ=rq8Hi@e>ad`nT`!*Kau|=AxfVal;na zutX?AJE)RI9*THig72>DEDjP0AQ$13Gg;*%V!PI<6Mp&U_>2ZK=d*qVd$*(vNDZi>bz(( zf_OEt*#3IUvG!BpV#-^<<*)H}oYnzKJWHk$khEEcgABQdS1+=wB!(%8GPx}u8=|<~ z_)8HVCm%xyeWL8Eh7c)P+xDpF`Ix^z3uM$VljXUuR4+Ex5Ppn*awv=~K>)M*3+r2UbB;CXN*SOYHa{+a+Eth6)qd4*gx3q1h@rkNHflBvy%X|Nf zVQe(d2Jfy^Hr<-1+)bi!js80>s26;F7nR;Cabsm-C+OL=st!H)&>~)-qcS4=JBeax z2iY@G=uUB-nAQYjQk&qCGi6Q|P`T+2!TtW&w34C!Jlest~ za*w4TQ>Je>i49H#?5>1Y_(OO0EKW{8yR>{9taG|IALOZM4hEhJ(a1(9{R-i($aq99Pq8F$k8S@v#J&*00cDWh6x(kh*z zIhUGUbNIE?i%_aNn-RQr6tN_UdIs!^Gg2gCSKGl^yPH&qn9SP^kU!@szqHFn*Tr41 zj%Cowo9z#ESUu>g9)JpU%ZBG$?BARMKKN)2cVn;s!QY`S?TDv_Mpg4Pp*ba-7U1hV zo2GZq5F-vR=TS|_^gDS!4{?zW;6XZkQsK7wRRvF(ois`N`)7(W)Jj}XRaWcFu(IqcYppIgA561|!wv6x z=tfo4ufne#D2z6&Ua_j=`Y>1_7|03{_0tG8C4c%q_0z?CY+aX1wBhmuLO;^UtGQbk z;KkF+)YW5NUo(a}Sa1>bopQLcGEqG_-P4M2*-)5e7;N=nOGgTRBJyzXu)6|)A3R`o z00i#`lP@=HTxS&nvv+uq0k}WAl~i+Bh#PN0-7Pf81Z6p>fR9wIpS{$H#P3l)3g6{0BwaofR$BfpV=fEkq_pg6YoXaf?C+3ZRBG?xt8&#ju>I%ZW zdS0lM=6`4Utg3EgVsrS}Hhnq0jd9Wnetd1@_&@)NpZg*M-!EP4w zzVLdP7Erw~I-WOh0Ha)CqF!+r>f=LowA+GuFYjU-o0Nbi=+G&oV1P<~)4Iqfyia`U*i9ULwijbzjgi-x6l#c- z_F9}Fu-EgWt8>lYTz~&rX~>rdu0PS5kk3q~mH0-(^zaY_`(?o~Wf)+Nz1kxIQB8e| zSZ#kuiYBI#U`*ucuq^F?hcF#cuVct2_^9Lhp(G^_A3hX(E#c3|78s56lln7Ky3Kc2 zBMt&hbb{Ly!7~m2DQ^*~HA&b~v!Pt|^DAmMak!e7#tgy03gf^7A}_f;ID&4KKqK!o zcGBwhYac+)aV|}E`rTMU3OGjjS{DU~MC@O>;x(n?xS=sT7(jB1ca6;#onavDPRe2_ zx$~?HsJdM|$VwY5+TZue9{knjeC1a>+t~5Xk1iFSA1RV5M zYgtB$xJ$KXpGD}$x-v+!>jHw01XsCHu4aP6NQ7T(pOw^yU)w1f3@a1I_~6e;WRk9B zieXW2o4b6vO9%%W!V?r$)U7k1Bh+L7&Id&lZ=HFFBs^TJ2Eq7}xj3-45}hp%KNsS5d-<3q{QHm9J_8j9X6nV+T12>C=tB_}8lB*Orww4*$ zUkeqm>!c(f+g-9%b~4H40+BXY0v$&+hpjh265jBzS3OhX?X&U5G`GfdnUHb?pEuY7 zl%cAC;cwC&%?F)Nkrb^5XO&1cK;JL5#k_NZ^HRG39{@xzQwjpS^~<6m8GuiePB`bX zqbL!=bQh(Bp>zG*bO^4FCw`L*M*CdeIBsd8Wazdr!6p*^KQQ(PU6_lyKFb_^y=+Qc z%llOv+65^1fHTz3+MZaIDLpv=`L&9MKwFfIvq4OS-X=JEQNn9TvD=ADU zXM#|=NsUTy+{;Q(xZQlam=jKo2`7Ksj7;{*Gd|J}d`wKExS|s_UGi{w3ymX;LxZoQ zU0%ZeLvAu~eU$nz7&I9$(ig^u)%6@Q;0}tj4IY6AI?d zTE*#~8442ur6s7p{N}F!FYUgbj=lFliw4mD2`z>9_);h%mIC#6ID~f@WXt zR1QcW7qXm?j-Mpwyjwo{NxpNwxsHq&+bwOg<{&X_W}NH}U}zw0;@a8L!7F3UmnGI9 zaw@W+kU)8vtKipgI!jjs1D}jRjvlV}!4m}O`TA?#X9j~()sh1*Okr1YcanYNWpK*KEL!@JituWp*XoQP1j~}0MYYdR3tyx~cK4n1;)-yaY}Fpjc*2b|j#@XH>mN~Z zvvFV+<*U`dYFK?ekz`~!wzk=G`hdkwT&&=fb4h%=ct*Ww8RbH*0`dGw2?epBX>#dQ zrzl%8|8|=mtD_B$H{7X3x3;ye5$q%ZuX_cov?#I&c19=dK;A+w2)6W{EvKFTzOA|fGJZ-U7` zfUS1Cv3a+>M5N5II-Rv<;iN{36 z_$Lg)MDKnufQK$6>P$|;fz3u2{ujOXE>VQbj0MAZro7apq1q{e+B;_*bWuBxA6_RM zbD~iqY+@F2DR-;2@h6`XE%3Ib7blalX3RC_{`}hEILVw)2O0=7)5X z=;qMK)4j8#h!0-B?$tw&r#^D{zf6)S*mkl;;NT*)wasVhrACso!`gOSyJG{=W|gL5 zb5gdoe*;}cWNVXiGBt*Yp%=eZ-hTWpvaF3+j>AuMPv`}Mq^)%EI1DMxS7Uti(v&NP zklK>rxlXZjwv~}9yWLs8yOS4wW~ycY(s|qaPF-gWO(spRF?mXPCs=UGG;2=??K^5= zr(Rz_0`geiv+pe^VWm>LYyAYWQweRyCM5b2juLbu_A>Kw0;@jGbvv%b=0}hr0dUN6 zbDYen0_sc*dRqtRKFiNT0 zX&I_h7yE~`@RNRuv z0!ux{y_Y;&`M)mG=!2xUEJhUNVj``%qD&l#9D&xwm8i>@t%bZGdTecyn-QefVqC+T zn5uad5lpl6n}u?zU1P`ma$L2-VbZ#`%55YFp3gluoLAwP=vUk>(!^HeIKW1IK z6CLKEbs$Tk>{Zw9-om2I#G-Ni{-P(xJ;%+Ibg{j{^Y--(`JZmfJL^;r}9Rjf7ncM@FKgf)p zFUgZ9$07^MlLrfw+i5?s=cD_B$tYs@``89~F$jVvnsh1R;bK{U zpwj{_=~{=KJ6HT8EydK+QHc{tirQVqbe_k|>lMXJt)ro_oBf#AF20>+VVOZcs7zi} zPM-fVyD$`$Z2KU`6Y11uEm!w#N#5&XWN+uhyMSNvQb>HPj;4P<;EHXX4}@a%aa1vC zBEJa1))ZH{@dBV!+b)Mwkkh|5o>tm<)sm}O^gE?OVo2){&q~LBG>pj0BJy`pGm&HG z#q_yu#`Rl$l!Pai$o&_U#in5{%~jyg(JYGPl^-usD9eP7SX5e`Z^B`2(GWprsN7>g zvz&)YKWCc8Tsf3W_QMlMQCoRw*1mGx{K>s?*&c?VK4%sB&K_-jAu3ET8B@IFV?&4J zJ>*sC_l<&6q%v!(>e;!A3nn9=lnGb|f*;E0l1XkDEx&ArsR~(!DZx;^ zMI#BFpT33t9?$2lr$kvg?Z$PbWNgunwWZQfWMTQzbId&|^?&HT9~p0*#do$;$rC;wga$Loo3}+ackYLxVD6p+Jtk5o=373pS-Li4R9CguQEpa84x(B>BW#=E6IiQ6}?=_ftEzEap#n>5@ER(WL}%vTaRk`;rCmG>Yhm40`sSjxWV7ZxAZ~4b zxH}2O=&;bEv4@)Dwy^N@wT%lKmvf{r*V9N|j9_7L2S$Y-@-y2O3QYwbAFF0~3bbqH zb7Rj4B|*R3X5aj7sUFa-$(J{DC}87105(VLHw!{n{T}b7;2TPlSXcc~RI4lu2yyG* z+ZFbBu-hHYf-T*sB7R*~b@#pP3Tgkn?AP{4=68Mr_C8c?Kb;Z1o4S2mQ|-9!&wBis z<$HD*DtRnwML79IFwlRPh*hkAYw#HmVWr zvWfUVNACPB?e}QukBC+hrLsS~r??~$?zK1scNEdwrtVCDSfTu+6*d(t?Eev;MJ$2G zq6}fhpDtHgbUU`fErST`_m4k2V7*tZrnQ{ne`M7iWz?_E#ZubSsM4m#J1+@F<2FwT zG%4Zz)SFuOAGxsSU%TrU_Ruz{@NTW(HKQDl1^5BqGJ!(le3~cac1tJ!D~-$k=UH!R zIO`Vm=jwns@j8RX6bBm195qC*2WBaRwoLvIojVKY}|pPF`oS)8-9 zVX-#dF-+~N6(&??R`_;Zb1UAbeVEOX-|S!B=S~DVjvmHZ`_%H87+ju`y2pPEb0lx6v=>`eEHxne(i%F%|$UL2ElN$5YsN&LS+5B>*H%d?+OM z%_GRYJ$8zUJu9qxum6|)UU{?TtyzQMpxFRMv7rP4O1$h&%yHV^WO~d5;xi^ z^xoJ;_p6^Pjc9`y3!l#hMv;@$GPs`Qk&*G5Wi4IrfR(9kW&)#p-asyAzi*K3$4!9D zn{K+`8z~>`O|7LIt-1rfHLyF>p6}lucjf`xSlIuWR_**R1XfX@l4-P{&S;r=&CMD@xWdY?(_wVpFh z7V%Mj{1uN2CLm)bl0~yJ3j9$2K~rUH=jtfs<)Klna@+Nq*vbr?=`w2G=I4*rP=0?V z%IRb>Slr6W+H8YzQuYZeJM_HDfzzeTpy#(Cy;#6Pw^F_PdHu1g#1$Gml1ejlc3^%H zqvabJ(P(!DFf~v5@80tg{u}{}dKK-%qxM!PwzU5W0AFLnUwAeDM$){GYLp(g5Eao^ zjT-Y#iJ_15m|5OIn7m^Pe~MC~W0$2tI8>nWZ+U(TA1*xDUaWM_<7=PF;+7S8 z$JX#$Cn~hBbK!w%`jviLfXMz4*5~nd%9`*H;Z|eosL^*RUT;q2;-QP8Rqp3n8Yp$> zfs@JNXFiw{DZk*ZU-&kegXrE_q09fhFdflRM)_so@A;ucnryC6`^7J5okrVGIl{ULMF+8AL#zekQ|7Lzb88sQN4 zVI@T9gCctG6?^`iPlvEg-%HFnt^8&2f7I7vm;ZUpK)WFaX0hc4kV-Leq_XZH>^@5L z`e!~L8eay}PMX-qXYa0OSu7QjkVKx+LLIe;l}87YD828x1rPR!h3!1+>~#p0=bgARv313A7;W(7J7&FBBmF}@lH)~3$&K|D z39sd=);tUHY9}M=izaWKQiE zH6e9CD%Ax0%x?$#QK2f+(roL`a)L=+(6-Lj7A=>o^$#0Pd@kpCFzFs{S05jSh&}J7 zhj2u$Pi5VCBlwmQ?k7fB+u`f7t)$r_L*YK&C-1fkdLtY~udRyUE81tjJmZ)%a|p*& zJZCP5SG7}@6MUOWWPD^M9(^z8P~87MDc8VW(#!?Y|E^5XI1v=*K})}K`N08ZG2-qF_4;B8K9rHzO}JqnH?p1w-f`U z(5d}7%Y+IM=dXhW?w(?m*2tMp`xI`R?l>%2hRLP342&%J?o)`Z4|{17bNbYJYq-Z_QzI$bs1VV5co`fLC6S9L`nb3FE$jO>F%luOC zeM5VI?!WDbHFD!=Cc|M6aUX}|G9$O zH4iw(iT&rG#(%^i&jA~1`G0>Qema!VL;v%P_pkQDCoKj=Vv_ytu8_{ZG+?xo zd_9-WX!y2c*ccDnwj=+$HGdA`R7i*6)3J%5S3UN1eKvf}7T%BJi$WkGduF4HO8JOJ zwIr))S-}`f8()>WRt?pg&M#Jtl;qh+_Q_ceX82d1V{QO((5Td^=V9hZ4*njm8FQ1( zs!?9_v#4X$B30cXNvl^e#S#``_-!K1dVD1Q=%Dbg5oyQ}>nu0EURt5r^>umWM>?Zbr;9vI?%JAIA|BPsUGAg4@&)`b6meJkQ zSC2!jN8=9fuQ@puUX}#6(y_2BE--yuHC(7qn}o>2i**$KPo9%X!2S0s1}#9lidXl? zW1RETo#O+y?H4MK@jfora}Ejy)F9n|b?b7DIMC!ZQ3c)5r{kQ}=12Bw|K7&qjuQ_` zAZHtO;&5B+~!tnd6Vh*iZj@H*ZJze>DVBj%Wxo!MCf#s{grM4~you9;9f% zc#AGVQKMRfBkHtjnPsRHvHgJCw9mC_}r!&gLfmvg_ zIw$NOB4lW8|MEJ+ zZP*BoD{%O}MS17i&hlsG8{qrqAliHpmvz^(d(MCtwhfY=C$f9lplJ7@Q6S~<^X{lZ zS%Q6Iz05Gbs85aTUO+b)orpW-VwnE&a2I`grvn+Zwnh4SYWk=&X+P2Ry4b+AHiRZ* z8e|}>XQMd?m^b;AHQzY-*-2#jlSoX zVFJnQhIj6e&t?%ge?9u?_0@CPNRP)H{?1)sl@56^jAH#O2p^Fg*f)s1FDf#aT+g$A zslL4RVSwgxWmYATRO=HCd}`#eP!6G|mNoy3iThy~Q|9%cs_(DBzg{n9zJb#D?c@4r zMu9dP)WH^O_VITpFiV9~_ElTB7_fZsPl{nQt6|>C5ZS;Ba9`uDC6D;3| zG%ChNSTSVCO@K`~>eal{ZcM6GYA5aw8A@!?934H5DXc7T$f|#~f|AS1z%6mE6$cIk z#BA}8gx0PM(c=x716>ReyeLuWz7!S9y0i55XOIfY!pdOlDDufQpJ_eWY8xS+-KzR~ z(#HB&H)!4O6)?1vMz*}+^-7~ncgx`kxbpkKPukf5K(UR};PMZl`lLS!_E>6tPSJFO zkBI5qZ=tz%-lliazM|{530VT{X@Li`A?Be^H|xeB-ky~ASZu^c>3L5(rsosQ<+pad zQbi>yJi^v)L@`CTu!4_@`Zt2AZ2Rl7C!`85piD)8&o zL;F2+>I3R7GX?W(Cpx`o^Z}nidfhxFP_!#M>M}zERQ!S&sl$i^JXJQLCfyv`C5Uus z@j#@PoJmcCE~C#P2+y^LFGnNQ0fis8;Fu>dQ7Ga!*1pP6@29E*&&UjsuGGq&g&z*( zTU};GUEEbFA3oY(7NIU@1l9)%xfd5}Hlu6VR|08#X#PxmkIYjx#y8Gnwvsh|8-qo% z)SxF$0sDqzaS%pDlbWK-yzkJ>^69HBA?D1I-K`2h>y)*UpUqsRa7f~?wr#CP7C!&L z;^G_W1vF;$O`c{ULc0UI*9zGU9*(!;UMb9D{zpeV7R9>Tzkxm*XznTF;*=;eQN_6#}dXk{&{au=h-cl_1OR4Rv{0*}s_3&ext;oc8?^E@oji$fLDT`~C z7q+_gYf)j@1XeD(MSQ}+W>3L5M6WkQXvPDTm%h$V86C_^fH>b(5y1z#okL;wySpqZ z66ayxIH2g~VPAnM7aGK>p-=Bc%Z%Ieo>7}CvECzTIpirRW^<4mq#p^x6E`{!-aWET z#X)LQ}v>YBR=7bBewZ<;X4K7#AgyY$^Ji)k> zEypFC0PB&J7CG1l@-Jcj=dMGQ)xhxLZ_2Lih`oLK=%w!>D&pM`E0v}-kZ;DpHZs`} zHjhBEl)N0sbQUrtXRz6U;xK@oKl8Q}k3s5MR~ie-=y#|6sxcXAshtlKS;rEQoJv8A z8`Y=dLyi=A_78dZeyS^(!7QYc{*{JuOr`lUFGh3YVw>WOtgIm6X!ee(*7v=sVAWZs z%Gwm>&w0LNP11&esfalZAlzSsF5+pC?JR$-JCgdm>BI9bW)Is3(@|pZzMw=-6N{#% zl|I~bkZ($j8C*ngB(vYBcHFfdCe`)Vd~2eIN~RCbSZ)G&c2ptcVK6mZCN~<=2x3%l z`2n%E%ezy5Qo-Elup=p<2rMDG%gTfB?3si8=S3XFF7VvA&E1wY<20|p*q~x1*9?c= zKF?P5s$lD+mXa@yU!Sp*3GJ@0{0x@Uc*3UT!bqj=D0|w2RA(Dmw?~Fqh#4eyvCacvel-`Me6Ss2sUSONhozF-bEG$&#b}D-Ux# zdL2fcC;#h|2!<&z3ByUY7mbg*uh$McquQtHugZ8Ow+)qwHWDLG_Xm?7 zXSa@c4B4<`E`T%fD;X)2&D{^bhG{oD*(G+mmfzL^%huMYwCrfeTTqhHD7_N#P;K z!pc#D?Xk^Zh8r1!unA(Ra!fJ<{kFDl+C_YKHc~KkIE3EA4lx?^)jkvj@?0R0b*}RBP+`*_Xmt`(_d*3NH?`} zfmexY{7x-}T_UxMC%)G$s=)^oPkn*_WU{L8=zp2c!U}nDfT|T!_xW_nq(w|H=sxGY z08s=39!A8>g0RIHsOHiOmnc6;%g@vf|BV&_ztVO*tEhd20>|7yg9r=hAF+{IriSACxiISBrqS}&RrGP&5c`jA2uHAvm-)5QmLNT^^3HGH zKGzED8N4f7z3(@z;V~Z?ZvKQ|4QFt)=6$bBK$`VfcG7k=Yw&N|)T{*9VN<7fbnFJs z;s(Ua(RXfk{x;;;z5M+<4)SCVbsokkjTh$;_Qp`YWN6^W^HR1TYdV&4miP3Bv!TF8 zomH=K;t>;mss52LdD~A5iRtx4xhcQ0ywAuUFa55m{%th(ZUFu6hNWvq_Tir;bDZ8$ zs=h_;>$=dzd>TmO4UYx%#AN#YdL^?WwdNgTi#Su0gokA2X`*3hKZVf6$jYw}gh80p zapMP~gR&_Glnv$BmgQ8}k2lefD-b*!A}W?@{Vw?b=hd8RL|xXyry!KiP|d4fb$lfH zX;G`I^_obrK%E|sLJDqI_Yiub{HdryUg^Z7C8(jIh^mhfK|I6={ zU*6vUK16lQr#SLR4zJ6wq0Siu$sB^)^Js2u>RGch|K+s(-HJyy{j@zX{$Dm$Vp&9#$u7R?6i$2Mh` zVhFwQKhNMnJR?j3E;u7OK>4qr1%sQcydoUwcbkn2eD!}m*Fl_INfwE{gu?{--;T?} zMx@2`WZfBetg zR=cBSc`w0#?tbFHH#AcCpse-eAO$VP2f-p3lnDefyLtRS*4{gw?Z5jU{(S0FEv+hw zqG*k(-PWd|t*X|ZwJK`w+A|W}ilTPymZAhftRPWEZLu|k*fSC{K}7Df*L8ir*Y9`V zf8O~cd3Z?Pukk*wbDrmU&ifqCtO#LcJ=`_EUcR>fUPKB#Ce<6PK7RPlB&5EsTj^EX9)ERJ^Q~j<$A7lMqbZthCO5HkS$MS{{%vUX zf)ejrmt9YK((A(MAxZko-}mWER}LnBIA2J3?w#!OPaT_0c$Alv&v}~GzsRo1=X7y; zokKT<4?hFXV4=%Sw7Dq3=MH@WiFc%eg#WW@eH7c3BI3umr8u^8zp;dg$&{Y0lO6PL zf@X{gCX(!fYKaabz1P$I*J$-+a%uz$R;J0a;dKzl6yk0E^Dx=p<43KjIXQ+o9>^yB zA-+a~ImC7at1-%7tmB@-qBiy)A%RZ2^hP@?(-$xSbZWu6Jgs>u<22*07X zH~^!m*`+>IaDZKC39-}0DPQK6B%JS9IMed?LGFeJXDr_BQPvp#b?=b&^Ba32!fn#J zNz@yYfm~OZghu%VzM^nvr@y>))Gce+pPU?O_)_B}n=d~Mp%~Y{-z+XyFiih9wKp2f zB^IzrT! z$^-#?-VG-q-9ms$p=z;PoIe*3 z4`gO;dPp$8mQU1aQ2JbEJ|4V(aqlp5>=NGW>Z?m7ES`@04jT{VGF6YvzC@dtR^JZWK1=-NypeKmlg(4UH9p0G zGKPBjU?k(gsL}r6!yBDRmg8;(Z3{S>UC+x0(8l=3U*^tmiaZg2>$?x(XcE4*^cTTQ z>-28QMfw4mByJe;ghCrq-p|PP5>Mvy>w08cHbT?c10%ha`ran}U*elb#4^Rpj(L>Q zyWJv(4hUDPqZkvBn!=P0yT9;}enT>8oS4m~weu}m^Ql)KT>D2n>9$9ku;^XOvDv40 zlJ2|lXqlV>3)d#^C5bOYA05cO~Mr-5BwVNe=i=Ke{%O{U|3q35kyQ|OlLjQS} zj~L!1?5KX3+2lc$*_*HgyLDQDSFd%eSV7&y;I z-6IMJE^U229ei0+Cn+w#y-*;|!K&RzkvaD2SMev^`R!FH@6D`FxpxB}+$zy$@0}b@ z`9An)$y2vA(f{7R6@49CIfG%SbvxA~waFUV`XcNqwWwRb)!Mx7oCa;0PGZLQU#G8i z=5QFS)2wg%`8)CC_!VyntIwyq()vT+pH9AW=lHfR6O|;92+-PRJmQ?;FOhO%9%Tk} zcU9)ezfiqgR-4FcIlf{(yw+p%Rn`t3jI+vIDR>Bz^L z2}X}V3vnZ{!-o#tYV1|7$0%_x4rVMwNGCU<&PZ>&DYTwN)U4YUraiU~x+h3y0=6&p z?gY_|5&e;neu=bN^BWr}kJ2ja7K{FCfvQe+uyamgm15p+@v$BG=EA**D98#57q*(M zB_&zi9HbFj6naiKkY>Xb%ib$Qd84g+_X|rv)f=m z2)@QNSu@eZ)`F?$m3k6)8w0p!U2+CLvvqMFA{>}6tP8l^HjD-E}w1EUE*?!sO`paL^qdbw;ClE80@(`TFNq z;TG;5MFgoPYu_T$bJBjW16ovSG;x{)uS=wAiB&q+~p z4N+yG4QRUdUy6lSB|V#^$FpaYUpB-)OMK6l9eer#bTs8GbiJog#3+M5@zVOGF}^|W zil#0V@*s6m>W&F#cv7N0?5r-QyK$;4^z|e)X+OcKO5!G2x9uwLe6&1Mdw9DWbd^uw zs{!wmbFAbi_ws)ks9n>)9W!B8Tw|Hl!Vy(~Fim{)xrFLc%8H-A(Lg8ezq7JJ0zU+Y zZkb(7z>eNKy)XXJ;Q^D>HwXvl!n33Kn3!+YT%Fu!5&;i39i4@+=G>lPEwCgL*|*|J zKZJNEuX2n03*LCBd2%?xY|pR=fdUfrTp{n0D@!Rj`5^6+0rWuS<&iAqbXF#xPk+rB zl#p>P_hkNQG8Ho6)Wxv*$aP2#wd}(4)_QQ2TNSs%F6eWW|GteHr`bk=|K8;b)`FYFy^Sl6u&`-7jxfdVkmpTS<7ItlyLKL4+4IV81llOqPsHQ{qB*A=~JG zPFMa15>KCQ?EVv&Fj11CYfH_NCYunV(tMn3^_uioS(N?F_rL!Bq3EFNL-@&i-t7nN zWMqWTY+7>W@=2`7pRii(^k_OB!I%V?xLR$O+-U#X1nEpqPhQ8JmBz$=n-cpU0aMDr z?;akPj^p{lpVVLdF_00c((f{O&X)WXZM!IrSum73cpSS%Io&N^o$p47^9~ee{^_&S4 zTSEEs$G_h4((3M$9{tT!k^bLq%$ffKWg|bACj%z*MJRzsTMT3{sk@`ba;EvA_}ouV z%q#U;9iQIu$7_KB&?OS)Ob~?sQO6FX?p8mX`i*#sZj3y zcfUCp#UbfyAW{Hqj3H`dZ$#r*elTRSXyA&+{56E4`E392YU<3h-RHgI(;36T9nzaz zsd){nmMvjpg(Z6i#*?KNdxbUht4M>2F-rpb(_pU!_!x8}ddAH2(U+#Ru{iix_$EAZA!PJlFJPnXee}YXvL5&(ysI znCg0qZH~yj+oTh16i*tWcyFb7!0%43e>RRcG}aO;D>ZbofTkd$9oV|(l`0INGyZ`= zYs{ClJ7)Ljn(B&ShX4tciKzk5(VXCrKbP{)7#AmrDrOw$0u(osqnY#m3!VIhHVO89}97xK12HSsC(Shk2i>3_$>BD-0cg{dOOcEkKL^e z`QBL+cWW`-FnD16q3CZZ;Nz0$mEo~hsh1w#6TlSrRipq;ua7Fdv@T&Ux^#)_9#G4W z;ppMIb;r0c5Xu5|EO`^SbiM)#{mwERt1JrWsCt?+Gp^+LvBun!JM86+w?e6>4()PH z+;v-)tKKwU&b3UfYeboQrC7+{O@K4%JEQ^r%~n^fy<#5Lb{(zC1t;Q8y0i*e3`yd_c{Bx(Ii+a=JXr$ zpi~^pGEK+r5vyApxOYwP@#)~PYWvsMa&6h5i4J@Hv(bp7i3)Uw5Jlm0yKK)p%r}*;KEI3WQZFBNZ(FyNxMr)8wfXX7ZOz9*OH=2vOq!)wPjCKMcw;|e zhVTHEN5TfBLOQ~zG?>Y`IcP&oqK755S12_=AXTK4po5W~J~Y&SJO}BhHoHG5(a=~8 zJ*1?{ee-=%^zqTSG?>qlIpymct1mit`MQ(Nl`x58HJNM^-*2SJi0bM^SC+l88nP`E zPwcVd!qm?gglbluIua28^1o$+xeY1`@!Y^Up=ElQYdEJ6J(Kv`nLY}nTaq>L{o2ggBfjjo zHppTJEQ0*_)xbI1MB9~j>WQi)t~aW%vJ&Coa)CI7q{-9nj+l)#1_0rs7%dhIr zxNtR5R&HG9Bk43w7Fc}o+`J!HErWB${jpDQt*>{Mnz=+|m_tQwO3n_V25}@dnD*JQ z&qkR21LWAVcl2?SPL_rA`$G2N)B=52DfBzruxAHH;52;5_J{8p)Re1szx3SM-IIkg zf0qx7m@0hzd(s>Xy{rIZALq(1g+IxAo3tbU#{lIOz556Vm zku5aH=C3q(qojh)EoU1m8GcyGvH)#(C(nK@=Id28ABk(CNyV2qjjRH9AfN3Hbt?V{ zhGt!S$5mEXjiCxvc&%F|-`h+PuRGF^4zQZn7AgbKL=%beS{87sox_> z(Wm<#Cqk$h0->MLhinVtae8=#f@2{YPv|gGBT+2NNeYaZOF8#PU7o)BKX{B=k9Ishc=F4Riy@;eEhVU zUy&OrmDaSug-9dah7?}K6V<&mx#o(*5$L=zSm*MR+mQK$`M`_K{6?$oh$`r<=1Ics z+F=W&K*P1sF-5Q?TSpM@U~OqKWa0UrBhiRx6m^pA5zwEMi=tz}JM1<0?f!D<_+iuy zNp9RsI`ic>Zs5gnW>pmz?LM-IQuNpBbOql0maLHX z&xJ9uk=Pv?Jl3+rTZ-w7O)_4oWJ)INqR#I$iEEAC|Alx≧<&5d5vIfd3WSq30p} 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
_0RkKr0K<-08Gq@i#5ZTTwCVG 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 TRCI_t3II}K@}J8^^uPTth0Vb? literal 0 HcmV?d00001 diff --git a/images/identity_broker_flow.png b/images/identity_broker_flow.png new file mode 100755 index 0000000000000000000000000000000000000000..74739a2a3f5764b67c002a699cd1c688910cd0e5 GIT binary patch literal 21625 zcmeHvXH-<(wq>CpC<>S`5dBm@q5_hGh=72A1j$Lsl2eg`pr9Z@Ns^H$IZBQqk~5Nu zD4C)_axQw6-uLdk-~DdC*JJeP(PMO z7m5uHPpVF;&$7I@8TPSgMkdoyI_03P0Ey~b^09A^ zmQpSpU85+^d3~cL_P(EAB9jd|W}L=odx?`{?sjc$8>M!qug$0hX`t$?f7EbQC5mE4-oScO-T6tut>43efbf)Dhx7NJMp*F`#Acos>*g!Z)~Ugwb8Cd`=DX^=32P44 zS{=sSN}Amt(e;+wqm{GO!y+S1*dvEiRS}2@eSQ9tjXFXaX7!>^D!JNK&YS8*#@+iX zHRIEw$mJ1}+n3LsKkw$|=71SaskYYA(z3BB=r-oO8qnO_Y;SMxMf=j%cW!2;ncyM! z+S=Ne`g(Ju!sExcpMJsD(HYOtstBYJ#(sH4>_yAT#g&?p^6KTw%cp%VGATdQ7&g0r zU#HJ5S--Km8p&=TWpDqPmdIsm>CKxrt7~hg&YT&|d+J@3(k>oZgfOf=FtPRQ4^sd9 z{7Gk=prC+2sNY%qkJZ)g{aI?&)z#ujcLW8s#$GjKL?0w62$PHEF&Bu_VO=#*|%pi*T&@!3cN*9Go`o<36x0@AP|)I zUh?PhC{j~XZ*Fe(VD|R*ppogqm3etx9O_Jp^{aMFc)?JnU%W*5Y|VHi{z zl9H0jUm&Fx;ISCtfua5S^=m4AByJRQ8d)RENxJr~(S=A>T}J0bwIQVrRY~g-eP_wL zyl^i;s!{4DDstr?#^1K?>d}1gHPPuKXNRT1J9hJr!y2WC?Hd{zY^3Go-&MXfIx2?% zQSVDSUSQA)FI-HXlE+F{S-HPzdn~hPJTEVgRA?umpr9Z>Kfj5NMVgz*_6%enA4=f(8h^|?#Gj?Q>tkG1LMHLd;{ z9zBRi-Y3q$WDV1BhVfkEam1og%&y4gQ}7eOq~>7+u2W? zr@U_KeS4d(m^M2%H!v^&gYw(AZ&IJ(C1id4C_;w6(7PuUFne%tu(rM)O_^{ix`D`x zjD|+os3Qgf6CBgi`cC`&E0wmpYct=!e}}&AO_eb%pg~_#?Hd_6rhc0|MbC6y_12j# zulA5kB?O`tFNTV>8$WukRi8a2IoZ(#chqe3NY7fnP>b)y9`0+@$ds9*it&!0czp_u zynFX9#I6^=4*0O<^8DyvPFPS-urrpQ-tU>1*sHX(xygFpFvg=F{%n6-zs~QlOi4)@ z^X}a>du<(^qZX!Id;)?ir+vbhRHSerLTq(!6Mf~%6?u7i?lDI_J3Bk*O$NVcE_1)P zZ~M@jhkKi?9UbAtMMK6G4SpBL#>Qkwx?&pM6{)>t@caDvb8ng)_vO=gczCVhEFm;u z(b4>lKXt3LY0jN1Kw{L(w9^0K*`s~s7jV!1OovM@M*$Dv+28x-Kv1pLI+p+Kum8}$)~d;crDNE}y$A=yJdYzO9)i-#o*#Fv)kk~&lLO25 zBM(^GV zv$+j?3-Q4gJDw8U6WtJ>MB4)mDDvzm^O(wPKHV5kdz`a#mVg?OV6ap9>(V^DsC1ol zTPjkx8*|pLR{O3O#`gT6^v5;2edYjnSA>N18#AM-2aSpFrF+Ds4{)vX6fKo1=Fs`1 z*A0zGFwne-`*y;nCId>c)t-46cjFJl2DsK1y*D-BC&xX6di`hIBO%oP{lomn!u~JM z4_}RyO|wOwgzsCl^$rmbed)X&>l$4nd;%J;*`ZUyL5iGp3cM=-ZJV`OE04V}(RMx7 zPUHE&f?d`av}dq05{>MylcnP>aE7PS6`rf1&wP0inh58Q;vN+KS1(p{5+#RwuuK)1 z8DV2_x8uQIX@+QO?29(!58r@aM72f^$u||G@l)?YX!tzQuYUV+ zu&p0~7dVDc)f*-0BH|s)r=4zT8b=IYMI$}Q$(BZr)sfuehY@HIq&r6r&pRw}en@s( z2cvk#bM}wHG6LE2o=Clwa;lT0Rw6e}l+>CW>xzqNLMAdq$%)?(sI?EiJaR1U&@^MI1wike&Q6!|mIq+2-vjsCw6dt^fSh zOWzQ~eID)(`Gdim0Rm+U}>3_Y49}Q+ z_7s9jk>8*~`2@dzBfG(IOy^x4ha9zw2p)MCeSTkjet&AdzLz=sxrXLTb938WqNK4r z)`{7zifrODtOMzadaOFt0+wTyLT-Do9yByI8jX}%15`9|E6MgaY@r`D=A^rE1D2ce z`%e%Fcg*83l$V#7_ZE0obINLj)Q7P(st71={ zd|#bvoSK@t#Hu;Jl!z7OTOcH*2EgF7Ts9Y@MS?Jn7~~qxIV#Q>AsFISU2o6PEc-Dt zbMwd%;_oZsOFlk6S5NzlA1*rphPWt}pOa$&AQI3zECdjE&%0wAADV5M71GFGsKM@` z-4FK`Hur*qgB`}4Bo0sZkML#hUlPkNF6IKna{JeD>sESkv2vA-2$^z@=9LQ!#`elJKfhBtIy(NxlGmTPsWUM#g`MJ9QCw&qnXXMaxNw1z z*X9O2z0q7p?A8W6r3hJ^>soVPUtdN>h9zKSNF^?LP-m#CrP&{O(K2gS^02Y7(c_M} zrgzt+!ec(AqSDgRGwsO~EJ7AGq%$)! z0O{c9CwP4-?MeFW^`ws*`o%^Qfhq1$e0^UD5)MB&YWs{zh%TPe?f+>w>gB~ z_YB1r^ii_|G(M7^@fTX%bas=G2`G9|)Rt5vu`3aM_&U+?=R}?L)VJNeJ@E$*mIm`h zt7d2WO$t5ye*jQ+p7Emn@QAK#^k7nEc~p!OebSOWGLTv@DmeIO^!S0e5_MF=(<_3` z8?)`vV)7$JCW@}EmAg49xR$R~0nP}ali_n%j%hy@Dx2B!1BA(Y)yt>s; zm_4Mq$Za2))Xm_R*wXkRN+Ycu8`h5rWh~+GIeYeOKU!|l#i5*B0L7+NZr93E^14N| zaNcTrc~sQr^jR@$cv@c)s)DhshDMom8-HX<@AJaj>y3L-D>^r zW{o4 zBny2F2V}&%^(&R@9W$*FDk>@flI5bgWGqUCf@q1Xt*sjasZ5QH$?)sy>qW`%g@tS2 z{nHUXlZ)lr5AyeymXczG`N+fsAN>6N6>~?vOgD#|KY!le&yQ8BoYSa-aAkk;ott;etM<$B)tiAg1=axJzpMEmTgPxC)Xv|MX2q6_*%l)1W}Prxm%k5;=MI*W^o!z2jc9=l9M6&n_I)9;zN zIc8&__sj`Vh#(Ey`tZ;Y5SiWB>>*2D)8g8Pjs@rpd4_XUwN8!u(9lpKLyl_x7ZeJ0 z4L3VdQ|a#9k>9&-@a$RQfqRU?3^{*xZm!2nn2MK|*Xa}WEn!T*qgUL@P~qG=3FpH948@vTfn7CC#nwIsz}Bjfrly5Nf2GgCgi>SYv1tzfeevY9mAa* z5RCEM5=}miD7x!=*nS7rQXZ=R0v06+7Q{BJm_9MVhxObv&jQx)1S;7MZ> z)z>rxE`WB(7H=K1D*p_vSo3z6g*94<#j?7Sq#! zQremHZ49E(QCA->u^cBAK6pGVbmvZYeZAhn&MM4wx4jLuQmd!@7XYm%;9*v^P9Xxn zH2xetHlBi*cyN%&0|VqglCu9|nEVrZHm)~I>s?6JsadWip&FzB*uM3*fnyPZNfzS| zUxo`SmCE4qp?e`C*HMvd1Nk^~nDABbSE92td19!;`D0)T4(>&d{7TzuWpm;%kSVB^ z!?*Hg7l%k>MeI%>YGumoiWTK9Pm`8ReNz0EPN+%FCRe+l$%hgtFdfL*U#{qEZOsHS ztW#k9k%2*qV33rY-1f%CBRRPeqbaVaK$h~0V%=qjsvEaf*VkRRF@TP@bcka(wt*h%X8(Z!*Q6EY{XQk(yk&pbzSr)%%Mg#?Q!dL_*WX3(Kq-43j@(AdS zqN1YUU^4Hzyk`xk((@A%bicgBwF@pwCG36x*t2gxJu_2UR+j5(08pU3yk$8#vMJOz z;T!;yzN9qa8fGMge_}~zwoO`v8L4t$!hikx)zQi6m5-0bU|!wqDk0^wju>7b2Vu$L zciu2|cgKDUpon%QQt{cEXd$z>XLdXgQ-)czV^dR8tHEyOMvs`aeYmqywH?RcN5O4D z$zk|*#KQVCL1BVfw~)n1>5m^jGF5V`w}wqceM!QGRkBpA$KAGJ5d)06`i4Hv5hmjI z5|v?~x}Y1b3c2n8l3~-X{16kve0R*ckqVZUfgG*OjEpE~Ek~z7(paY#0kL=>rPCg) zP-$}GE-O_gCMJuUgGu=Z?vlo0}^rDCqt=;Dfn& zw)0`XUIdKchSpYTZ1?Q#f5{$}^?@7%*af);ZsE+#G*x@b#jnCQJWtz%T%PXwC@LZ% zg5#jRb2BkBZ)|Vprl+43%TG=H27K?QPY=smv1SglZC4hMzy=D~iv2TF`^hr*JuY^d z%SIIdoFyb6NZ;nunf+l12;G&PyW4QxLEcAniYphw-J%83(n zG1S+O;j@=YC%jlmHsU31PyxiOWC;@^V`WvO>J7sZ0Al1N4$Uk$Ed;4lG(ZhBogZuparOpWNYU} z^rV&joxWYHfk3@@_`yLzQ88%%jkyx&l+>)x=d?Brs7YvliDQ>Fy1r;ILU2fS!HP=2 z(Fzhu7y$q&`H@SHGrH)si7e{u3r1nQ@S5}_`~5n0b{ys8`EDpiRU8)Rebs* zY!&Ej@Faq$!-$P7{-O7u0y8>V;UH`^aW6zesyBaEQ&CCjhFm}3obqz@=fbwLZ(SeS z^Tj&ROBFuV*H3opl(ER|F@Nyj<>nG4Ir$byGLX-5adAoM5Gt=o7@SkO)mffjRMcn8 zsa<9xX7FJajqD-ZnXU*8%;=eX|KU+8NCOlB;%K~#`3W|B$a98r3JTbTgvNAlVZAqB6H5)92@gDB}l-iC$x%+PHz+BQA@P z9mvGhI3WYrJKP?>BxXI|^)a_dAiJyIm~f&9HL5h#FMQq|HL z1wn#NHs(`xl~f7HDAYo(j!&O{+^t{~Pg-5?6wZYS$jt1z(Jc|ZM1S}06ZiFJz`3u_ zb*kh_q*z0Ui;Rq9tk=xbt@|XOG|m0EjV8xVDU3wL%*;$%TN^IFg+akMv=F>^k!ttV zgt#U>D$->iQvxac6RwGt$0^h);x0L-Z_Y;8{^%UQ0QI}1R-$;TEzx$9SlXC+sN)Qg zG8TlJRtGh+ks1$=-5#0Zzp=Q9AAXah3yLMME``xlL*TWvT%pVTkgHP@_wL=gUY7X0z;k)q! z`xX)-JV|8sw30eQMdB`zEX}Ckfxv&9rxVQ>*R|O`=Yl%a<32w%7oaa zTkUZTy!}5BMW@F@2t2pCvUKUM16{@14}Wd{%shy9j~I8N`Pn5z5j|j@qHA7Mo=9=H zR`LD3<6T&IkS;nP31hr~LtXaOahw&$QHEE5=k8L*eWC$Yk^dSK0@0WM8LOokM?m>^go7~qvbL}%*Ztz-UFQN%kzXZZxO&-(H{cB6yk`?~ zejWn0`#x&?>gf~Sbw5$#*kV}k++2(fJ0s%amKPQx5{rq5I(`%6T z{q_PxL_mVmKfO$O--L)|Fk*R*Qc-8!^!8D=yb-=944tlS!PT$lYYt}EAZvglDJd!5 z@yAIc6@Bk!ef1KH(TpdV>>M02bRmVU)?zwto8KXh#b}91zc!44+=7J`^)YFG0Ps_f zG@H|JQ3*8qqrHI|^)AVOQP>q+fN@Y)R|j&cPFFSm*{eR)ztGoZwrXtWWWDQxKYW-+ zqbp1YSkt?om5J@iV+Rh#{#Rh9$G&fRPf*XDBDJ8;xz&4%*!>k1;kSSZ0b#6dZr;5b zFw2xc!h3-n1Ezv)AcAJJV3E%N><;R$a_-}*IP$)l=if76{dabBB*M6hBY231NT^0X z+|dhX1I)ZO1H>SpWuR4x5<(jMFM)etW*T<@k*MGN{-(lyPm1*R%6NQitd^1zEP`}* zg|-Iu;Qm0A@Y^pc1yKvaeFyZ9AVkLsx)jqAaTs;D!UFK5IJDoLnfwJ3@-&EW#Ftp# zQVTjmd{vkNhz+DrG+a_ub+D@|I6OSHpsL-%V2e~Sg(gMslTu9?=;5IJBVj3Glo0<{ za?_?ll;o9|%k$@p;H_X~E2su8S5i_Eu=ta|JvHQsfIc4@6wO`1n{a(bVP)27u9C)t z{*Yt=tA)X}Yu9={lAJtwi;YcXd~Ej00>A@p?KnGrZf-d!Yt;y^379U)?J2`z6t>))UVIyB;ql&&tzjTfkR=?Gw_>`cZgonYBl!aWb@>k3=vaPU$*cR-`0)g2Ps zv)9EhpFXj0fL!d8Ofizb0J*&BI|RVntP+)GB$vm=+8X;xFA!sHE@2iL9FKM-;9Uq& zNDP0B`;MTXCzZK%{~o%cpUD_U6&zxho>JcTn{& z9OcNVM#qn^+hDtBjxX776vlRY$(B2;uzJ*O0j&nqWw6Ee($G45CZ}lp_6<~n7y+l> zBKjJLt&D;L{r&Dg>j)w7Uh{{TF%Q58@XB}eCgdR@T>LIuSqEhNH5OMWDb2>Rov$p8 za+!XRI%J>{bs1d8Y1z&j^Ve1q^YR{BIP^iYX#h^1;U2jSJ+@N4Z!uhCA`?EKk85~k z@|M7LM9gb5-@s*+n!WG9w8O-JBb-%hI9Eq_mv!HRUQAO{6M75MEjZwVre;i^5P(=n z+!7NL;T^O`a!5P}#^a z4UkeQ%gf74O9ut`KrNV=o8wkn|5x@R69?Yfucj&pOEu<6!pnvXc?TQ|Q6qpU-62hc zSqlf4V{9stU}99rrb)}l$jHfoI{*t$tUG6=v}j^*h(U@YN?#VMp0oRh*+4)*0QLo4 z=+X)#h7YDmuR!1fSf>HL1ssgCPKx*`)OCG+feoATADu7hWD7 zp6k~|A3I9O^?>&P%mAvK7N}x#7}sTGW!{9O{pd}YcmIIpEK@9IX#O3TEA&b4gV?8( zA+ZHMoP$~JntUOQ7`bSaX4hG+ZYu0ty|4QuLf@;mj+8gysPZG zVd%m`1_;8+66rpe6C3#`71%AXPdoySW9TztUR5Ag3zTNR-I7z95EA1;KS93_Upmq=jcOdw!Yic$lml1w2Bp5({^w05ayGou zTYvlAzm?Y$=OjyFOKxgU z9!ZMO1gQb&Dt>6^PnyM68_?>li2oCG)gCdhbmSWo)@uD-pcdBqt^IQYkoX${Q)U09 z{Cm1gt|%b#9z@|Gwj0W+5QDS?n$K7fCH3W02{H#Km3)nT>mRz}PpIni-}5FyA}C+q zYS4N(;0HgNPOI&p3di|M&V9OUNIAQ74p9NxGRY80*9EUw4cfsvttQ1&G}KlGkS$HH5+N-_4mm;K;1>V;wT;&}SNR_!91O5$)vKKs_K1*H z)^G*gPLn@C@qRN-x2TQ#)vV&FUVpS==eRz9ZNR(BnlVLjEhb+6*W1b>=q@QY177tk zd8QS6p$@|<;~D{j?pJ^R_dsk1Xqh|N9}x&bxMjxx_M{wzhlesn5(3eP`-MK1;@hb8 znIJoYS`1xIzwPR^b?!#Qz_TNrFq59!Q@4GOZYuf<&7c65#SlaGT-Qm)!D%>~$#J}# zfG0xTh=!&X#3fDsj-}DLZ54n#6h#(^o3=o`#xsKayx9rWhHa_pnUhxeQzaJ z>ns8_{7k%HUNP>pMjqR!$CZF@z(j+6uRmfgwN4fo2m-1i*~32mX|=wtuDl;J7xfaq zy$zt=?;Z}CMus$R)Mb!TQ~Vs9Z|b(ZQ6uk?t^AzEkTQHzr2i%My!gwvAGV@R#DvLD z9%-3S7*f))l{K@>VhX9_HtqWd)>s)^n5eNc^(wiVPcqu;>+3t`xt%(ur;hko9V%vy z%&&}F9^_UWs*}C++4H$e+zQ4vXffdb~qc(RD zG9lGNk=4~7aNEJ3Gd^GRUU_J)ORW1IO=Wsil5Kxkw-h)U>}%|kxUo5O;7vGTw1`F< zwMWgM(WabNdwY9lpvS?Sng}k{-JP9Bk?birDg`VsKp1@d_z}nfQ2ltFH$MFwZ{S_u zm9e;ESp(cMx8)e~$`8=+0C3f~?iMJR0}gORXO{p@WZ5qJJ6QF4tfCST6JrMMR&hNW zo3%&|ql3dkP!?|pAN*+W2R&cGfA=fO>zeewIkwv#Q4lMAzWdJLI;ZiBt;sfhMaZR_ z`wr`*^W?#mJZct4XkQPvNm4dD;$@`tfQDfepXth0)tc5VX~pu*rPP(gpy(?qR>`$k zw=?Aq!2>edE(KdeUXPWPwmdxcYb4^``)0#?6vjtKSEyYY2hBZ(x4zJ52d_w}hfW)9 zgjjg&E<`l@zlVYUumSgZ%`o2lz)Y>BU_&_VXs=F(oA-}(A+2EB_?K1$9quH2h3QN3!p{tLR^Mk0+RLBQT3FGpq2j?Ncsah9$MAPu7{fg zA@ARpBQeiCJ_9qyZ#CiBR}USuzP1KFR5$=4zK@LL{iV+zIW(65Jqp~JcO94{rT0JA z$P(_!(V6?Fg?3oeoOE!s^puuY4_9>hB26lPwCAeEX+cuXZGzLnb@)70P#m?sJdH z`(*=l@7|$x;jE4&e}c)$Nq`gk4Q%eUse3kNDfm*1!P+d}avS?v)d+`uPRy(PqO%lFtEhgYxi>i

r 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 Yc_&{j_2)SNJXwdq)78&qol`;+023O}B>(^b literal 0 HcmV?d00001 diff --git a/images/update-server-config-dialog.png b/images/update-server-config-dialog.png new file mode 100755 index 0000000000000000000000000000000000000000..5b07227859b9f2bdf4d79a925d14164d31057000 GIT binary patch literal 67031 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 z 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 Xaw}v!LXB literal 0 HcmV?d00001 diff --git a/topics/cache.adoc b/topics/cache.adoc new file mode 100755 index 0000000000..02326fb3fc --- /dev/null +++ b/topics/cache.adoc @@ -0,0 +1,58 @@ += Server Cache + +By default, Keycloak caches realm metadata and users. +There are two separate caches, one for realm metadata (realm, application, client, roles, etc...) and one for users. +These caches greatly improves the performance of the server. + +== Eviction and Expiration + +By default the user cache contains a maximum of 10000 entries. +This is not 10000 users, but 10000 entries in the cache. +You can change the maximum number of entries by editing the server configuration `standalone.xml` or `standalone-ha.xml`. +Locate the element `cache-container name="keycloak"` and change the eviction policy for the `users` cache. +For more information see https://docs.jboss.org/author/display/WFLY10/Infinispan+Subsystem[Infinispan Subsystem documentation]. + +== Disabling Caches + +To disable the realm or user cache, you must edit the `keycloak-server.json` file in your distribution. +Here's what the config looks like initially. + + +[source] +---- + + "userCache": { + "infinispan" : { + "enabled": true + } + }, + + "realmCache": { + "infinispan" : { + "enabled": true + } + }, +---- + +To disable the cache set the enabled field to false for the cache you want to disable: +[source] +---- + + "userCache": { + "infinispan" : { + "enabled": false + } + }, + + "realmCache": { + "infinispan" : { + "enabled": false + } + }, +---- + +== Clear Caches + +To clear the realm or user cache, go to the Keycloak admin console Realm Settings->Cache Config page. +On this page you can clear the realm cache or the user cache. +This will clear the caches for all realms and not only the selected realm. diff --git a/topics/openshift.adoc b/topics/openshift.adoc new file mode 100755 index 0000000000..690fc8b675 --- /dev/null +++ b/topics/openshift.adoc @@ -0,0 +1,44 @@ +[[_openshift]] + += Running Keycloak Server on OpenShift + +Keycloak provides a OpenShift cartridge to make it easy to get it running on OpenShift. +If you don't already have an account or don't know how to create applications go to https://www.openshift.com/ first. +You can create the Keycloak instance either with the web tool or the command line tool, both approaches are described below. + +WARNING: It's important that immediately after creating a Keycloak instance you open the `Administration Console` and login to reset the password. +If this is not done anyone can easily gain admin rights to your Keycloak instance. + +== Create Keycloak instance with the web tool + +. Open https://openshift.redhat.com/app/console/applications and click on `Add Application`. +. Scroll down to the bottom of the page to find the `Code Anything` section. +. Insert `http://cartreflect-claytondev.rhcloud.com/github/keycloak/openshift-keycloak-cartridge` into the `URL to a cartridge definition` field and click on `Next`. +. Fill in the following form and click on `Create Application`. +. Click on `Continue to the application overview page`. +. Under the list of applications you should find your Keycloak instance and the status should be `Started`. +. Click on it to open the Keycloak servers homepage. + +== Create Keycloak instance with the command-line tool + +. Run the following command from a terminal: + +[source] +---- +rhc app create http://cartreflect-claytondev.rhcloud.com/github/keycloak/openshift-keycloak-cartridge +---- + +. Replace `` with the name you want (for example keycloak). + +Once the instance is created the rhc tool outputs details about it. +Open the returned `URL` in a browser to open the Keycloak servers homepage. + +== Next steps + +The Keycloak servers homepage shows the Keycloak logo and `Welcome to Keycloak`. +There is also a link to the `Administration Console`. +Open that and log in using username `admin` and password `admin`. +On the first login you are required to change the password. + +TIP: On OpenShift Keycloak has been configured to only accept requests over https. +If you try to use http you will be redirected to https. diff --git a/topics/preface.adoc b/topics/preface.adoc new file mode 100755 index 0000000000..fb0c9657df --- /dev/null +++ b/topics/preface.adoc @@ -0,0 +1,20 @@ += Preface + +In some of the example listings, what is meant to be displayed on one line does not fit inside the available page width.These lines have been broken up. A '\' at the end of a line means that a break has been introduced to fit in the page, with the following lines indented. +So: + +[source] +---- +Let's pretend to have an extremely \ +long line that \ +does not fit +This one is short +---- +Is really: + +[source] +---- +Let's pretend to have an extremely long line that does not fit +This one is short +---- + diff --git a/topics/proxy.adoc b/topics/proxy.adoc new file mode 100755 index 0000000000..fc82e140af --- /dev/null +++ b/topics/proxy.adoc @@ -0,0 +1,238 @@ +[[_proxy]] += Keycloak Security Proxy + +Keycloak has an HTTP(S) proxy that you can put in front of web applications and services where it is not possible to install the keycloak adapter. +You can set up URL filters so that certain URLs are secured either by browser login and/or bearer token authentication. +You can also define role constraints for URL patterns within your applications. + +== Proxy Install and Run + +Download the keycloak proxy distribution from the Keycloak download pages and unzip it. +[source] +---- + +$ unzip keycloak-proxy-dist.zip +---- + +To run it you must have a proxy config file (which we'll discuss in a moment). +[source] +---- + +$ java -jar bin/launcher.jar [your-config.json] +---- + +If you do not specify a path to the proxy config file, the launcher will look in the current working directory for the file named `proxy.json` + +== Proxy Configuration + +Here's an example configuration file. +[source] +---- + +{ + "target-url": "http://localhost:8082", + "send-access-token": true, + "bind-address": "localhost", + "http-port": "8080", + "https-port": "8443", + "keystore": "classpath:ssl.jks", + "keystore-password": "password", + "key-password": "password", + "applications": [ + { + "base-path": "/customer-portal", + "error-page": "/error.html", + "adapter-config": { + "realm": "demo", + "resource": "customer-portal", + "realm-public-key": "MIGfMA0GCSqGSIb", + "auth-server-url": "http://localhost:8081/auth", + "ssl-required" : "external", + "principal-attribute": "name", + "credentials": { + "secret": "password" + } + } + , + "constraints": [ + { + "pattern": "/users/*", + "roles-allowed": [ + "user" + ] + }, + { + "pattern": "/admins/*", + "roles-allowed": [ + "admin" + ] + }, + { + "pattern": "/users/permit", + "permit": true + }, + { + "pattern": "/users/deny", + "deny": true + } + ] + } + ] +} +---- + +=== Basic Config + +The basic configuration options for the server are as follows: + +target-url:: + The URL this server is proxying _REQUIRED._. + +send-access-token:: + Boolean flag. + If true, this will send the access token via the KEYCLOAK_ACCESS_TOKEN header to the proxied server. _OPTIONAL._. + Default is false. + +bind-address:: + DNS name or IP address to bind the proxy server's sockets to. _OPTIONAL._. + The default value is _localhost_ + +http-port:: + Port to listen for HTTP requests. + If you do not specify this value, then the proxy will not listen for regular HTTP requests. _OPTIONAL._. + +https-port:: + Port to listen for HTTPS requests. + If you do not specify this value, then the proxy will not listen for HTTPS requests. _OPTIONAL._. + +keystore:: + Path to a Java keystore file that contains private key and certificate for the server to be able to handle HTTPS requests. + Can be a file path, or, if you prefix it with `classpath:` it will look for this file in the classpath. _OPTIONAL._. + If you have enabled HTTPS, but have not defined a keystore, the proxy will auto-generate a self-signed certificate and use that. + +buffer-size:: + HTTP server socket buffer size. + Usually the default is good enough. _OPTIONAL._. + +buffers-per-region:: + HTTP server socket buffers per region. + Usually the default is good enough. _OPTIONAL._. + +io-threads:: + Number of threads to handle IO. + Usually default is good enough. + _OPTIONAL._. + The default is the number of available processors * 2. + +worker-threads:: + Number of threads to handle requests. + Usually the default is good enough. _OPTIONAL._. + The default is the number of available processors * 16. + +=== Application Config + +Next under the `applications` array attribute, you can define one or more applications per host you are proxying. + +base-path:: + The base context root for the application. + Must start with '/' _REQUIRED._. + +error-page:: + If the proxy has an error, it will display the target application's error page relative URL _OPTIONAL._. + This is a relative path to the base-path. + In the example above it would be `/customer-portal/error.html`. + +adapter-config:: + _REQUIRED._. + Same configuration as any other keycloak adapter. + See <<_adapter_config,Adapter Config>> + +==== Constraint Config + +Next under each application you can define one or more constraints in the `constraints` array attribute. +A constraint defines a URL pattern relative to the base-path. +You can deny, permit, or require authentication for a specific URL pattern. +You can specify roles allowed for that path as well. +More specific constraints will take precedence over more general ones. + +pattern:: + URL pattern to match relative to the base-path of the application. + Must start with '/' _REQUIRED._. + You may only have one wildcard and it must come at the end of the pattern. + Valid `/foo/bar/*` and `/foo/*.txt` Not valid: `/*/foo/*`. + +roles-allowed:: + Array of strings of roles allowed to access this url pattern. _OPTIONAL._. + +methods:: + Array of strings of HTTP methods that will exclusively match this pattern and HTTP request. _OPTIONAL._. + +excluded-methods:: + Array of strings of HTTP methods that will be ignored when match this pattern. _OPTIONAL._. + +deny:: + Deny all access to this URL pattern. _OPTIONAL._. + +permit:: + Permit all access without requiring authentication or a role mapping. _OPTIONAL._. + +permit-and-inject:: + Permit all access, but inject the headers, if user is already authenticated._OPTIONAL._. + +authenticate:: + Require authentication for this pattern, but no role mapping. _OPTIONAL._. + +=== Header Names Config + +Next under the list of applications you can override the defaults for the names of the header fields injected by the proxy (see Keycloak Identity Headers). This mapping is optional. + +keycloak-subject:: + e.g. + MYAPP_USER_ID + +keycloak-username:: + e.g. + MYAPP_USER_NAME + +keycloak-email:: + e.g. + MYAPP_USER_EMAIL + +keycloak-name:: + e.g. + MYAPP_USER_ID + +keycloak-access-token:: + e.g. + MYAPP_ACCESS_TOKEN + +== Keycloak Identity Headers + +When forwarding requests to the proxied server, Keycloak Proxy will set some additional headers with values from the OIDC identity token it received for authentication. + +KEYCLOAK_SUBJECT:: + User id. + Corresponds to JWT `sub` and will be the user id Keycloak uses to store this user. + +KEYCLOAK_USERNAME:: + Username. + Corresponds to JWT `preferred_username` + +KEYCLOAK_EMAIL:: + Email address of user if set. + +KEYCLOAK_NAME:: + Full name of user if set. + +KEYCLOAK_ACCESS_TOKEN:: + Send the access token in this header if the proxy was configured to send it. + This token can be used to make bearer token requests. Header field names can be configured using a map of `header-names` in configuration file: +[source] +---- + +{ + "header-names" { + "keycloak-subject": "MY_SUBJECT" + } +} +---- diff --git a/topics/server-installation.adoc b/topics/server-installation.adoc new file mode 100755 index 0000000000..697f2483e6 --- /dev/null +++ b/topics/server-installation.adoc @@ -0,0 +1,610 @@ +[[_server_installation]] + += Installation and Configuration of Keycloak Server + +== Installation + +Keycloak Server has three downloadable distributions. +To run the Keycloak server you need to have Java 8 already installed. + +* keycloak-.[zip|tar.gz] +* keycloak-overlay-.[zip|tar.gz] +* keycloak-demo-.[zip|tar.gz] + +[[_server_install]] +=== Install Standalone Server + +For production and for non-JavaEE developers we recommend using the standalone Keycloak server. +All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. + +To install first download either the zip or tar.gz and extract. +Then start by running either: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +[[_overlay_install]] +=== Install on existing WildFly or JBoss EAP + +Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. +Once downloaded extract into the root directory of your installation. + +To add Keycloak to existing standalone.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install.cli +---- +To add Keycloak to existing standalone-ha.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli +---- +If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. + +=== Install Development Bundle + +The demo bundle contains everything you need to get started with Keycloak including documentation and examples. +To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. +Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. +You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. + +To start WildFly with Keycloak run: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +== Configuring the Server + +Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. +Specifically: + +* Configuring Keycloak to use a production database +* Setting up SSL/HTTPS +* Enforcing HTTPS connections + +=== Admin User + +To access the admin console to configure Keycloak you need an account to login. +There is no built in user, instead you have to first create an admin account. +This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. + +The `add-user` script creates a temporary file with the details of the user, which are imported at startup. +To add a user with this script run: + +[source] +---- + +bin/add-user.[sh|bat] -r master -u -p +---- +Then restart the server. +For `keycloak-overlay`, please make sure to use: + +[source] +---- +bin/add-user-keycloak.[sh|bat] -r master -u -p +---- + +=== Relational Database Configuration + +You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. +You might also want to tweak the configuration settings of the datasource. +Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. + +Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- +"connectionsJpa": { + "default": { + "dataSource": "java:jboss/datasources/KeycloakDS", + "databaseSchema": "update" + } +}, +---- +Possible configuration options are: + +dataSource:: + JNDI name of the dataSource + +jta:: + boolean property to specify if datasource is JTA capable + +driverDialect:: + Value of Hibernate dialect. + In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. + +databaseSchema:: + Specify if schema should be updated or validated. + Valid values are "update" and "validate" ("update is default). + +showSql:: + Specify whether Hibernate should show all SQL commands in the console (false by default) + +formatSql:: + Specify whether Hibernate should format SQL commands (true by default) + +globalStatsInterval:: + Will log global statistics from Hibernate about executed DB queries and other things. + Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. + +schema:: + Specify the database schema to use + +===== Tested databases + +Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. +Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. +You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). + +.Tested databases +[cols="1,1,1", frame="all", options="header"] +|=== +| Database +| JDBC driver +| Hibernate Dialect + + + + + + +|=== + +=== MongoDB based model + +Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. +To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: + +[source] +---- + +"eventsStore": { + "provider": "jpa", + "jpa": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "jpa" +}, + +"user": { + "provider": "${keycloak.user.provider:jpa}" +}, +---- +to: + +[source] +---- + +"eventsStore": { + "provider": "mongo", + "mongo": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "mongo" +}, + +"user": { + "provider": "mongo" +}, +---- +And at the end of the file add the snippet like this where you can configure details about your Mongo database: + +[source] +---- + +"connectionsMongo": { + "default": { + "host": "127.0.0.1", + "port": "27017", + "db": "keycloak", + "connectionsPerHost": 100, + "databaseSchema": "update" + } +} +---- +All configuration options are optional. +Default values for host and port are localhost and 27017. +Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. +If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. + +Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. +Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. +Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. +Supported long option is `maxAutoConnectRetryTime`. +See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. + +Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. +In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. +Please note that the database specified within the URI is only used for authentication. +To change the database used by keycloak you have to set `db` property as before. +Therefore, a configuration like the following + +[source] +---- + +"connectionsMongo": { + "default": { + "uri": "mongodb://user:password@127.0.0.1/authentication", + "db": "keycloak" + } +} +---- +will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. + +==== MongoDB Replica Sets + +In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. + +=== Outgoing Server HTTP Requests + +Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. +Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. +This is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- + +"connectionsHttpClient": { + "default": {} +}, +---- +Possible configuration options are: + +establish-connection-timeout-millis:: + Timeout for establishing a socket connection. + +socket-timeout-millis:: + If an outgoing request does not receive data for this amount of time, timeout the connection. + +connection-pool-size:: + How many connections can be in the pool (128 by default). + +max-pooled-per-route:: + How many connections can be pooled per host (64 by default). + +connection-ttl-millis:: + Maximum connection time to live in milliseconds. + Not set by default. + +max-connection-idle-time-millis:: + Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. + Set to -1 to disable this checking and the background thread. + +disable-cookies:: + `true` by default. + When set to true, this will disable any cookie caching. + +client-keystore:: + This is the file path to a Java keystore file. + This keystore contains client certificate for two-way SSL. + +client-keystore-password:: + Password for the client keystore. + This is _REQUIRED_ if `client-keystore` is set. + +client-key-password:: + _Not supported yet, but we will support in future versions. Password for the client's key. + This is _REQUIRED_ if `client-keystore` is set. + +[[_truststore]] +=== Securing Outgoing Server HTTP Requests + +When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. +That is necessary in order to prevent man-in-the-middle attacks. + +How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. +By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ + Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. + +Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. +Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. +The default JavaMail API implementation used to send out emails behaves in this way, for example. + +You can add your truststore configuration by using the following template: + +[source] +---- + +"truststore": { + "file": { + "file": "path to your .jks file containing public certificates", + "password": "password", + "hostname-verification-policy": "WILDCARD", + "disabled": false + } +} +---- + +Possible configuration options are: + +file:: + The value is the file path to a Java keystore file. + HTTPS requests need a way to verify the host of the server they are talking to. + This is what the trustore does. + The keystore contains one or more trusted host certificates or certificate authorities. + Truststore file should only contain public certificates of your secured hosts. + This is _REQUIRED_ if `disabled` is not true. + +password:: + Password for the truststore. + This is _REQUIRED_ if `disabled` is not true. + +hostname-verification-policy:: + `WILDCARD` by default. + For HTTPS requests, this verifies the hostname of the server's certificate. + `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. + *.foo.com. `STRICT` CN must match hostname exactly. + +disabled:: + If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. + If set to false, you must configure `file`, and `password` for the truststore. + +You can use _keytool_ to create a new truststore file and add trusted host certificates to it: + +[source] +---- + +$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer +---- + +[[_ssl_modes]] +=== SSL/HTTPS Requirement/Modes + +WARNING: Keycloak is not set up by default to handle SSL/HTTPS. +It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. + +Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. +If you try to access Keycloak from a non-IP adress you will get an error. + +Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. +Each adapter config should mirror this server-side setting. +See adapter config section for more details. + +external:: + Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. + If you try to access Keycloak from a non-IP adress you will get an error. + +none:: + Keycloak does not require SSL. + +all:: + Keycloak requires SSL for all IP addresses. + +=== SSL/HTTPS Setup + +First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. +Then configure the Keycloak Server to enforce HTTPS connections. + +==== Enable SSL on Keycloak + +The following things need to be done + +* keytool +* Enable Wildfly to use this certificate and turn on SSL/HTTPS. + +===== Creating the Certificate and Java Keystore + +In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. + +====== Self Signed Certificate + +In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. +Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. + + +[source] +---- + +$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 + Enter keystore password: secret + Re-enter new password: secret + What is your first and last name? + [Unknown]: localhost + What is the name of your organizational unit? + [Unknown]: Keycloak + What is the name of your organization? + [Unknown]: Red Hat + What is the name of your City or Locality? + [Unknown]: Westford + What is the name of your State or Province? + [Unknown]: MA + What is the two-letter country code for this unit? + [Unknown]: US + Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? + [no]: yes +---- + +You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. +For testing purposes, `localhost` should be used. +After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. + +If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. +You'll have to do a little set up first before doing this though. + +The first thing to do is generate a Certificate Request: + +[source] +---- + +$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq +---- + +Where `yourdomain` is a DNS name for which this certificate is generated for. +Keytool generates the request: + +[source] +---- + +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y +ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY +Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 +29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as +H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw +Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 +2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i +n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf +PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ +9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X +MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S +vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= +-----END NEW CERTIFICATE REQUEST----- +---- + +Send this ca request to your CA. +The CA will issue you a signed certificate and send it to you. +Before you import your new cert, you must obtain and import the root certificate of the CA. +You can download the cert from CA (ie.: root.crt) and import as follows: + +[source] +---- + +$ keytool -import -keystore keycloak.jks -file root.crt -alias root +---- + +Last step is import your new CA generated certificate to your keystore: + +[source] +---- + +$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer +---- + +===== Installing the keystore to WildFly + +Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. +First step is to move the keystore file to a directory you can reference in configuration. +I like to put it in `standalone/configuration`. +Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. + +To the `security-realms` element add: + +[source] +---- + + + + + + + + +---- + +Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: + +[source] +---- + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. + +==== Enable SSL on a Reverse Proxy + +Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. +It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. +Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. +Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. + +===== Configure WildFly + +. Open `standalone/configuration/standalone.xml` in your favorite editor. + +. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: + +[source] +---- + + ... + + ... + +---- + +Then add a new `socket-binding` element to the `socket-binding-group` element: + +[source] +---- + + + ... + + ... + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. + +== Keycloak server in Domain Mode + +In domain mode, you start the server with the "domain" command instead of the "standalone" command. +In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. +Inside domain.xml, you will see more than one profile. +The Keycloak subsystem is defined for all initial profiles. + +THe server is also added to server profiles. +By default two servers are started in the main-server-group which uses the full profile. + +You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. + +To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. +See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. + +== Installing Keycloak Server as Root Context + +The Keycloak server can be installed as the default web application. +In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. + +To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. + +[source] +---- + + + + + + +---- + +`keycloak-server.war` is the runtime name of the Keycloak server application. +Note that the WAR file does not exist as a file. +If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. + + + +NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. +To fix this on the server side, you will need to export your database to json, make corrections, and then import. +Client-side `keycloak.json` files will need to be updated manually as well. From 4928867cfe51a9ad08df8702cd22bdd1e13b0020 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Mon, 18 Apr 2016 15:30:26 -0400 Subject: [PATCH 003/149] move --- topics/clustering.adoc | 164 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100755 topics/clustering.adoc diff --git a/topics/clustering.adoc b/topics/clustering.adoc new file mode 100755 index 0000000000..130c7c3256 --- /dev/null +++ b/topics/clustering.adoc @@ -0,0 +1,164 @@ += Clustering + +To improve availability and scalability Keycloak can be deployed in a cluster. + +It's fairly straightforward to configure a Keycloak cluster, the steps required are: + +* Configure a shared database +* Configure Infinispan +* Enable realm and user cache invalidation +* Enable distributed user sessions +* Start in HA mode + +== Configure a shared database + +Keycloak doesn't replicate realms and users, but instead relies on all nodes using the same database. +This can be a relational database or Mongo. +To make sure your database doesn't become a single point of failure you may also want to deploy your database to a cluster. + +=== DB lock + +Note that Keycloak supports concurrent startup by more cluster nodes at the same. +This is ensured by DB lock, which prevents that some startup actions (migrating database from previous version, importing realms at startup, initial bootstrap of admin user) are always executed just by one cluster node at a time and other cluster nodes need to wait until the current node finishes startup actions and release the DB lock. + +By default, the maximum timeout for lock is 900 seconds, so in case that second node is not able to acquire the lock within 900 seconds, it fails to start. +The lock checking is done every 2 seconds by default. +Typically you won't need to increase/decrease the default value, but just in case it's possible to configure it in `standalone/configuration/keycloak-server.json`: + +[source,json] +---- +"dblock": { + "jpa": { + "lockWaitTimeout": 900, + "lockRecheckTime": 2 + } +} +---- +or similarly if you're using Mongo (just by replace `jpa` with `mongo`) + +== Configure Infinispan + +Keycloak uses http://www.infinispan.org/[Infinispan] caches to share information between nodes. + +For realm and users Keycloak uses a invalidation cache. +An invalidation cache doesn't share any data, but simply removes stale data from remote caches and makes sure all nodes re-load data from the database when it is changed. +This reduces network traffic, as well as preventing sensitive data (such as realm keys and password hashes) from being sent between the nodes. + +User sessions and login failures supports either distributed caches or fully replicated caches. +We recommend using a distributed cache. +A distributed cache splits user sessions into segments where each node holds one or more segment. +It is possible to replicate each segment to multiple nodes, but this is not strictly necessary since the failure of a node will only result in users having to log in again. +If you need to prevent node failures from requiring users to log in again, set the `owners` attribute to 2 or more for the `sessions` cache of `infinispan/Keycloak` container as described below. + +The infinispan container is set by default in `standalone/configuration/keycloak-server.json`: + +[source,json] +---- + +"connectionsInfinispan": { + "default" : { + "cacheContainer" : "java:jboss/infinispan/Keycloak" + } +} +---- + +As you can see in this file, the realmCache, userCache and userSession providers are configured to use infinispan by default, which applies for both cluster and non-cluster environment. + +For non-cluster configuration (server executed with `standalone.xml` ) is the infinispan container `infinispan/Keycloak` just uses local infinispan caches for realms, users and userSessions. + +For cluster configuration, you can edit the configuration of `infinispan/Keycloak` container in `standalone/configuration/standalone-ha.xml` (or `standalone-keycloak-ha.xml` if you are using overlay or demo distribution) . + +== Start in HA mode + +To start the server in HA mode, start it with: + +[source] +---- +# bin/standalone --server-config=standalone-ha.xml +---- +or if you are using overlay or demo distribution with: + +[source] +---- +# bin/standalone --server-config=standalone-keycloak-ha.xml +---- + +Alternatively you can copy `standalone/config/standalone-ha.xml` to `standalone/config/standalone.xml` to make it the default server config. + +== Enabling cluster security + +By default there's nothing to prevent unauthorized nodes from joining the cluster and sending potentially malicious messages to the cluster. +However, as there's no sensitive data sent there's not much that can be achieved. +For realms and users all that can be done is to send invalidation messages to make nodes load data from the database more frequently. +For user sessions it would be possible to modify existing user sessions, but creating new sessions would have no affect as they would not be linked to any access tokens. +There's not too much that can be achieved by modifying user sessions. +For example it would be possible to prevent sessions from expiring, by changing the creation time. +However, it would for example have no effect adding additional permissions to the sessions as these are rechecked against the user and application when the token is created or refreshed. + +In either case your cluster nodes should be in a private network, with a firewall protecting them from outside attacks. +Ideally isolated from workstations and laptops. +You can also enable encryption of cluster messages, this could for example be useful if you can't isolate cluster nodes from workstations and laptops on your private network. +However, encryption will obviously come at a cost of reduced performance. + +To enable encryption of cluster messages you first have to create a shared keystore (change the key and store passwords!): + +[source] +---- + +# keytool -genseckey -alias keycloak -keypass -storepass \ + -keyalg Blowfish -keysize 56 -keystore defaultStore.keystore -storetype JCEKS +---- + +Copy this keystore to all nodes (for example to standalone/configuration). Then configure JGroups to encrypt all messages by adding the `ENCRYPT` protocol to the JGroups sub-system (this should be added after the `pbcast.GMS` protocol): + +[source] +---- + + + ... + + + + ${jboss.server.config.dir}/defaultStore.keystore + + PASSWORD + PASSWORD + keycloak + + ... + + + ... + + + + ${jboss.server.config.dir}/defaultStore.keystore + + PASSWORD + PASSWORD + keycloak + + ... + + ... + +---- +See the http://www.jgroups.org/manual/index.html#ENCRYPT[JGroups manual] for more details. + +== Troubleshooting + +Note that when you run cluster, you should see message similar to this in the log of both cluster nodes: + +[source] +---- +INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-10,shared=udp) +ISPN000094: Received new cluster view: [node1/keycloak|1] (2) [node1/keycloak, node2/keycloak] +---- +If you see just one node mentioned, it's possible that your cluster hosts are not joined together. + +Usually it's best practice to have your cluster nodes on private network without firewall for communication among them. +Firewall could be enabled just on public access point to your network instead. +If for some reason you still need to have firewall enabled on cluster nodes, you will need to open some ports. +Default values are UDP port 55200 and multicast port 45688 with multicast address 230.0.0.4. +Note that you may need more ports opened if you want to enable additional features like diagnostics for your JGroups stack. +Keycloak delegates most of the clustering work to Infinispan/JGroups, so consult EAP or JGroups documentation for more info. From 9fd3be93b789ace831edba7ab44631c90387db29 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:28:39 -0400 Subject: [PATCH 004/149] test templating --- SUMMARY.adoc | 2 +- book.json | 5 +++++ topics/intro.adoc | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100755 book.json create mode 100755 topics/intro.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index b8b0dc4a3a..443cf8e809 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -4,7 +4,7 @@ :imagesdir: images . link:topics/preface.adoc[Preface] - . link:topics/Overview.adoc[Overview] + . link:topics/intro.adoc[Introduction] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] diff --git a/book.json b/book.json new file mode 100755 index 0000000000..27f230c7fc --- /dev/null +++ b/book.json @@ -0,0 +1,5 @@ +{ + "variables": { + "project.name": "Keycloak" + } +} \ No newline at end of file diff --git a/topics/intro.adoc b/topics/intro.adoc new file mode 100755 index 0000000000..a70e0d59d2 --- /dev/null +++ b/topics/intro.adoc @@ -0,0 +1,4 @@ += Introduction + +The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting +up the {{book.product.name}} server. \ No newline at end of file From ea1d2b2b37347ccc1d348eeffc2eba66a3854281 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:30:44 -0400 Subject: [PATCH 005/149] test templating --- topics/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/intro.adoc b/topics/intro.adoc index a70e0d59d2..5765b941c1 100755 --- a/topics/intro.adoc +++ b/topics/intro.adoc @@ -1,4 +1,4 @@ = Introduction The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{book.product.name}} server. \ No newline at end of file +up the {{ book.product.name }} server. \ No newline at end of file From 1010ed0fb478d33c52d4826c16ebe4464b140b6e Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:37:56 -0400 Subject: [PATCH 006/149] test teplate --- topics/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/intro.adoc b/topics/intro.adoc index 5765b941c1..f22959585d 100755 --- a/topics/intro.adoc +++ b/topics/intro.adoc @@ -1,4 +1,4 @@ = Introduction The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{ book.product.name }} server. \ No newline at end of file +up the {{book.project.name}} server. \ No newline at end of file From 123b928805dc639dba53b40761d4615fe7016c06 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:39:30 -0400 Subject: [PATCH 007/149] test teplate --- topics/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/intro.adoc b/topics/intro.adoc index f22959585d..a4b3d75f83 100755 --- a/topics/intro.adoc +++ b/topics/intro.adoc @@ -1,4 +1,4 @@ = Introduction The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{book.project.name}} server. \ No newline at end of file +up the {{ book.project.name }} server. \ No newline at end of file From a7e986c019e56e36ed1e8e2b0da2364a14f02d29 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:41:19 -0400 Subject: [PATCH 008/149] test teplate --- topics/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/intro.adoc b/topics/intro.adoc index a4b3d75f83..b344828ecd 100755 --- a/topics/intro.adoc +++ b/topics/intro.adoc @@ -1,4 +1,4 @@ = Introduction The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{ book.project.name }} server. \ No newline at end of file +up the {{ project.name }} server. \ No newline at end of file From cb775a6ae4b48978f969f2e6cdde41e950d67a62 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:43:15 -0400 Subject: [PATCH 009/149] test teplate --- topics/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/intro.adoc b/topics/intro.adoc index b344828ecd..6e0f3bd7c9 100755 --- a/topics/intro.adoc +++ b/topics/intro.adoc @@ -1,4 +1,4 @@ = Introduction The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{ project.name }} server. \ No newline at end of file +up the {{ project.name }} server. why not work? {{ book.project.name }} \ No newline at end of file From 76a3c9e3ae5c7716ebb2713a5f517bba54c40e5a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 11:54:06 -0400 Subject: [PATCH 010/149] test book.json --- SUMMARY.adoc | 2 +- book.json | 1 + topics/intro.adoc | 4 ---- topics/overview.adoc | 4 ++++ 4 files changed, 6 insertions(+), 5 deletions(-) delete mode 100755 topics/intro.adoc create mode 100755 topics/overview.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 443cf8e809..589b55e613 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -4,7 +4,7 @@ :imagesdir: images . link:topics/preface.adoc[Preface] - . link:topics/intro.adoc[Introduction] + . link:topics/overview.adoc[Overview] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] diff --git a/book.json b/book.json index 27f230c7fc..aecadcd87c 100755 --- a/book.json +++ b/book.json @@ -1,4 +1,5 @@ { + "title": "intall and conf", "variables": { "project.name": "Keycloak" } diff --git a/topics/intro.adoc b/topics/intro.adoc deleted file mode 100755 index 6e0f3bd7c9..0000000000 --- a/topics/intro.adoc +++ /dev/null @@ -1,4 +0,0 @@ -= Introduction - -The purpose of this guide is to walk through everything that needs to be installed and configred prior to first booting -up the {{ project.name }} server. why not work? {{ book.project.name }} \ No newline at end of file diff --git a/topics/overview.adoc b/topics/overview.adoc new file mode 100755 index 0000000000..8fcf6a0a8a --- /dev/null +++ b/topics/overview.adoc @@ -0,0 +1,4 @@ += Introduction + +The purpose of this guide is to walk through everything that needs to be installed and configured prior to first booting +up the {{ project.name }} server. \ No newline at end of file From 628fb437ff7213a4d1e9f5b40fc6a6cf9d6a81ce Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:18:03 -0400 Subject: [PATCH 011/149] subchapters --- SUMMARY.adoc | 1 + topics/overview.adoc | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 589b55e613..e5a0feb6bd 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,6 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] + . link:topics/server-installation.adoc#_overlay_install[Install on existing WildFly or JBoss EAP] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/topics/overview.adoc b/topics/overview.adoc index 8fcf6a0a8a..6bdd3131be 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -1,4 +1,9 @@ -= Introduction += Guide Overview -The purpose of this guide is to walk through everything that needs to be installed and configured prior to first booting -up the {{ project.name }} server. \ No newline at end of file +The purpose of this guide is to walk through the steps that need to be completed prior to booting up the +Keycloak server for the first time. If you just want to test drive Keycloak, it pretty much runs out of the box with its +own embedded and local-only database. For + actual deployments that are going to be run in production you'll need to decide how you want to manage server configuration + at runtime (standalone or domain mode), configure a shared database you will use for Keycloak, set up encryption and HTTPS, + and finally set up Keycloak to run in a cluster. This guide walks through each and every aspect of any pre-boot + decisions and setup you must do prior to deploying Keycloak. \ No newline at end of file From edb577634ecb917fe339c9fb0ce167375c8f392d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:37:52 -0400 Subject: [PATCH 012/149] subchapters --- SUMMARY.adoc | 2 ++ topics/installation.adoc | 6 ++++++ topics/overview.adoc | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100755 topics/installation.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index e5a0feb6bd..49413d93f3 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,5 +1,7 @@ == Keycloak Reference Guide +:toc: + //. link:topics/templates/document-attributes.adoc[] :imagesdir: images diff --git a/topics/installation.adoc b/topics/installation.adoc new file mode 100755 index 0000000000..49baa7d8c3 --- /dev/null +++ b/topics/installation.adoc @@ -0,0 +1,6 @@ += Installation + +This chapter shows you how to install Keycloak and walks you through the directory structure of an installation. + +== Unpackaging Keycloak + diff --git a/topics/overview.adoc b/topics/overview.adoc index 6bdd3131be..d61e41d79f 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -6,4 +6,6 @@ own embedded and local-only database. For actual deployments that are going to be run in production you'll need to decide how you want to manage server configuration at runtime (standalone or domain mode), configure a shared database you will use for Keycloak, set up encryption and HTTPS, and finally set up Keycloak to run in a cluster. This guide walks through each and every aspect of any pre-boot - decisions and setup you must do prior to deploying Keycloak. \ No newline at end of file + decisions and setup you must do prior to deploying Keycloak. + + Testing templating {book.project.name} and {project.name} \ No newline at end of file From ca2478e09b38a372f039c01da3f0efc650d6fd93 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:39:58 -0400 Subject: [PATCH 013/149] subchapters --- SUMMARY.adoc | 2 -- topics/overview.adoc | 1 - 2 files changed, 3 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 49413d93f3..e5a0feb6bd 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,7 +1,5 @@ == Keycloak Reference Guide -:toc: - //. link:topics/templates/document-attributes.adoc[] :imagesdir: images diff --git a/topics/overview.adoc b/topics/overview.adoc index d61e41d79f..64136a69d4 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -8,4 +8,3 @@ own embedded and local-only database. For and finally set up Keycloak to run in a cluster. This guide walks through each and every aspect of any pre-boot decisions and setup you must do prior to deploying Keycloak. - Testing templating {book.project.name} and {project.name} \ No newline at end of file From 5b2718a17f6faf98752cb378a9dddc9c8124090e Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:46:39 -0400 Subject: [PATCH 014/149] subchapters --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index e5a0feb6bd..835034c10e 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,7 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] - . link:topics/server-installation.adoc#_overlay_install[Install on existing WildFly or JBoss EAP] + .. link:++topics/server-installation.adoc#_overlay_install++[Install on existing WildFly or JBoss EAP] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] From 6cd722e728cbbf211fee1b9ca493faaee9c125f6 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:48:52 -0400 Subject: [PATCH 015/149] subchapters --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 835034c10e..ebb8c38b76 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,7 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] - .. link:++topics/server-installation.adoc#_overlay_install++[Install on existing WildFly or JBoss EAP] + .. <<_server_install>> . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] From e30925aae6a32abb5e854d717b50f7a6210c606d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 12:55:16 -0400 Subject: [PATCH 016/149] subchapters --- SUMMARY.adoc | 2 +- topics/installation.adoc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index ebb8c38b76..cfd2b3ea0e 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,7 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] - .. <<_server_install>> + . link:topics/installation.adoc[Installation and Configuration of Keycloak Server] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/topics/installation.adoc b/topics/installation.adoc index 49baa7d8c3..021e608749 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -4,3 +4,4 @@ This chapter shows you how to install Keycloak and walks you through the directo == Unpackaging Keycloak +<<_server_install>> \ No newline at end of file From 58b27cdcddc734b12e2258e5258f83c047befdfd Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 13:03:30 -0400 Subject: [PATCH 017/149] subchapters --- SUMMARY.adoc | 2 +- topics/preface.adoc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index cfd2b3ea0e..a8f59995e7 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,5 +1,5 @@ == Keycloak Reference Guide - +:project.name: Keycloak //. link:topics/templates/document-attributes.adoc[] :imagesdir: images diff --git a/topics/preface.adoc b/topics/preface.adoc index fb0c9657df..bff1bd89ad 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -18,3 +18,4 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- +Test if attribute is working {product.name} \ No newline at end of file From ceead8b1210760317ef9d1bef0e8fa158a6a047f Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 13:05:00 -0400 Subject: [PATCH 018/149] subchapters --- topics/preface.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/preface.adoc b/topics/preface.adoc index bff1bd89ad..78141bd6b1 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -2,7 +2,7 @@ In some of the example listings, what is meant to be displayed on one line does not fit inside the available page width.These lines have been broken up. A '\' at the end of a line means that a break has been introduced to fit in the page, with the following lines indented. So: - +:product.name: Keycloak [source] ---- Let's pretend to have an extremely \ From 278d43577e34f581a5552001c21a4e34c67d4f1d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 13:08:45 -0400 Subject: [PATCH 019/149] subchapters --- topics/preface.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/topics/preface.adoc b/topics/preface.adoc index 78141bd6b1..71cfb56d83 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,8 +1,9 @@ +:project.name: Keycloak + = Preface In some of the example listings, what is meant to be displayed on one line does not fit inside the available page width.These lines have been broken up. A '\' at the end of a line means that a break has been introduced to fit in the page, with the following lines indented. So: -:product.name: Keycloak [source] ---- Let's pretend to have an extremely \ @@ -18,4 +19,4 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Test if attribute is working {product.name} \ No newline at end of file +Test if attribute is working {project.name} and {{project.name}} \ No newline at end of file From bb4f7bb68adb1d7786a374112bfd9c2e32290312 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 16:31:07 -0400 Subject: [PATCH 020/149] .. --- book.json | 7 ++++++- rhsso-images/files.png | Bin 0 -> 6330 bytes topics/preface.adoc | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) create mode 100755 rhsso-images/files.png diff --git a/book.json b/book.json index aecadcd87c..2d0e4cd49a 100755 --- a/book.json +++ b/book.json @@ -1,5 +1,10 @@ { - "title": "intall and conf", + "gitbook": "2.x.x", + "plugins": [ + "toggle-chapters", + "ungrey", + "splitter" + ], "variables": { "project.name": "Keycloak" } diff --git a/rhsso-images/files.png b/rhsso-images/files.png new file mode 100755 index 0000000000000000000000000000000000000000..b5843b21b77550c5a274f5eceb6a40bcc3933662 GIT binary patch literal 6330 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 Date: Wed, 20 Apr 2016 16:45:52 -0400 Subject: [PATCH 021/149] ... --- SUMMARY.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 SUMMARY.md diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100755 index 0000000000..fcaaf56205 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,6 @@ +# Summary + + +* [Preface](topics/preface.adoc) + + From 0c27a279927adbb3b3f640690600dd91903bffd6 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 16:48:25 -0400 Subject: [PATCH 022/149] ... --- SUMMARY.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SUMMARY.md b/SUMMARY.md index fcaaf56205..e0f16866ad 100755 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,4 +3,6 @@ * [Preface](topics/preface.adoc) +Test replacement {{book.project.name}} + From b427937d03d94445c934f30687744a4db6c05104 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 16:51:55 -0400 Subject: [PATCH 023/149] .. --- book.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/book.json b/book.json index 2d0e4cd49a..eeb58d9f80 100755 --- a/book.json +++ b/book.json @@ -1,11 +1,16 @@ { "gitbook": "2.x.x", + "structure": { + "readme": "README.adoc" + }, "plugins": [ "toggle-chapters", "ungrey", "splitter" ], "variables": { - "project.name": "Keycloak" + "project": { + "name": "Keycloak" + } } } \ No newline at end of file From a0bc94c1b30b9936aa6f1d3063c22d6cee79b417 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 17:14:50 -0400 Subject: [PATCH 024/149] ... --- SUMMARY.adoc | 2 +- SUMMARY.md | 8 - topics/clustering.adoc | 14 +- topics/installation.adoc | 611 +++++++++++++++++- .../installation/getting-files-community.adoc | 11 + topics/overview.adoc | 8 +- topics/preface.adoc | 1 - topics/server-installation.adoc | 610 ----------------- topics/system-requirements.adoc | 9 + 9 files changed, 633 insertions(+), 641 deletions(-) delete mode 100755 SUMMARY.md create mode 100755 topics/installation/getting-files-community.adoc delete mode 100755 topics/server-installation.adoc create mode 100755 topics/system-requirements.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index a8f59995e7..701c2ea4d9 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -5,7 +5,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] - . link:topics/server-installation.adoc[Installation and Configuration of Keycloak Server] + . link:topics/system-requirements.adoc[System Requirements] . link:topics/installation.adoc[Installation and Configuration of Keycloak Server] . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] . link:topics/cache.adoc[Server Cache] diff --git a/SUMMARY.md b/SUMMARY.md deleted file mode 100755 index e0f16866ad..0000000000 --- a/SUMMARY.md +++ /dev/null @@ -1,8 +0,0 @@ -# Summary - - -* [Preface](topics/preface.adoc) - -Test replacement {{book.project.name}} - - diff --git a/topics/clustering.adoc b/topics/clustering.adoc index 130c7c3256..2f644235dd 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -1,16 +1,4 @@ -= Clustering - -To improve availability and scalability Keycloak can be deployed in a cluster. - -It's fairly straightforward to configure a Keycloak cluster, the steps required are: - -* Configure a shared database -* Configure Infinispan -* Enable realm and user cache invalidation -* Enable distributed user sessions -* Start in HA mode - -== Configure a shared database +[[_clustering]] Keycloak doesn't replicate realms and users, but instead relies on all nodes using the same database. This can be a relational database or Mongo. diff --git a/topics/installation.adoc b/topics/installation.adoc index 021e608749..697f2483e6 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -1,7 +1,610 @@ -= Installation +[[_server_installation]] -This chapter shows you how to install Keycloak and walks you through the directory structure of an installation. += Installation and Configuration of Keycloak Server -== Unpackaging Keycloak +== Installation -<<_server_install>> \ No newline at end of file +Keycloak Server has three downloadable distributions. +To run the Keycloak server you need to have Java 8 already installed. + +* keycloak-.[zip|tar.gz] +* keycloak-overlay-.[zip|tar.gz] +* keycloak-demo-.[zip|tar.gz] + +[[_server_install]] +=== Install Standalone Server + +For production and for non-JavaEE developers we recommend using the standalone Keycloak server. +All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. + +To install first download either the zip or tar.gz and extract. +Then start by running either: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +[[_overlay_install]] +=== Install on existing WildFly or JBoss EAP + +Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. +Once downloaded extract into the root directory of your installation. + +To add Keycloak to existing standalone.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install.cli +---- +To add Keycloak to existing standalone-ha.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli +---- +If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. + +=== Install Development Bundle + +The demo bundle contains everything you need to get started with Keycloak including documentation and examples. +To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. +Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. +You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. + +To start WildFly with Keycloak run: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +== Configuring the Server + +Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. +Specifically: + +* Configuring Keycloak to use a production database +* Setting up SSL/HTTPS +* Enforcing HTTPS connections + +=== Admin User + +To access the admin console to configure Keycloak you need an account to login. +There is no built in user, instead you have to first create an admin account. +This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. + +The `add-user` script creates a temporary file with the details of the user, which are imported at startup. +To add a user with this script run: + +[source] +---- + +bin/add-user.[sh|bat] -r master -u -p +---- +Then restart the server. +For `keycloak-overlay`, please make sure to use: + +[source] +---- +bin/add-user-keycloak.[sh|bat] -r master -u -p +---- + +=== Relational Database Configuration + +You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. +You might also want to tweak the configuration settings of the datasource. +Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. + +Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- +"connectionsJpa": { + "default": { + "dataSource": "java:jboss/datasources/KeycloakDS", + "databaseSchema": "update" + } +}, +---- +Possible configuration options are: + +dataSource:: + JNDI name of the dataSource + +jta:: + boolean property to specify if datasource is JTA capable + +driverDialect:: + Value of Hibernate dialect. + In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. + +databaseSchema:: + Specify if schema should be updated or validated. + Valid values are "update" and "validate" ("update is default). + +showSql:: + Specify whether Hibernate should show all SQL commands in the console (false by default) + +formatSql:: + Specify whether Hibernate should format SQL commands (true by default) + +globalStatsInterval:: + Will log global statistics from Hibernate about executed DB queries and other things. + Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. + +schema:: + Specify the database schema to use + +===== Tested databases + +Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. +Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. +You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). + +.Tested databases +[cols="1,1,1", frame="all", options="header"] +|=== +| Database +| JDBC driver +| Hibernate Dialect + + + + + + +|=== + +=== MongoDB based model + +Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. +To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: + +[source] +---- + +"eventsStore": { + "provider": "jpa", + "jpa": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "jpa" +}, + +"user": { + "provider": "${keycloak.user.provider:jpa}" +}, +---- +to: + +[source] +---- + +"eventsStore": { + "provider": "mongo", + "mongo": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "mongo" +}, + +"user": { + "provider": "mongo" +}, +---- +And at the end of the file add the snippet like this where you can configure details about your Mongo database: + +[source] +---- + +"connectionsMongo": { + "default": { + "host": "127.0.0.1", + "port": "27017", + "db": "keycloak", + "connectionsPerHost": 100, + "databaseSchema": "update" + } +} +---- +All configuration options are optional. +Default values for host and port are localhost and 27017. +Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. +If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. + +Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. +Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. +Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. +Supported long option is `maxAutoConnectRetryTime`. +See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. + +Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. +In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. +Please note that the database specified within the URI is only used for authentication. +To change the database used by keycloak you have to set `db` property as before. +Therefore, a configuration like the following + +[source] +---- + +"connectionsMongo": { + "default": { + "uri": "mongodb://user:password@127.0.0.1/authentication", + "db": "keycloak" + } +} +---- +will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. + +==== MongoDB Replica Sets + +In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. + +=== Outgoing Server HTTP Requests + +Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. +Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. +This is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- + +"connectionsHttpClient": { + "default": {} +}, +---- +Possible configuration options are: + +establish-connection-timeout-millis:: + Timeout for establishing a socket connection. + +socket-timeout-millis:: + If an outgoing request does not receive data for this amount of time, timeout the connection. + +connection-pool-size:: + How many connections can be in the pool (128 by default). + +max-pooled-per-route:: + How many connections can be pooled per host (64 by default). + +connection-ttl-millis:: + Maximum connection time to live in milliseconds. + Not set by default. + +max-connection-idle-time-millis:: + Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. + Set to -1 to disable this checking and the background thread. + +disable-cookies:: + `true` by default. + When set to true, this will disable any cookie caching. + +client-keystore:: + This is the file path to a Java keystore file. + This keystore contains client certificate for two-way SSL. + +client-keystore-password:: + Password for the client keystore. + This is _REQUIRED_ if `client-keystore` is set. + +client-key-password:: + _Not supported yet, but we will support in future versions. Password for the client's key. + This is _REQUIRED_ if `client-keystore` is set. + +[[_truststore]] +=== Securing Outgoing Server HTTP Requests + +When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. +That is necessary in order to prevent man-in-the-middle attacks. + +How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. +By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ + Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. + +Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. +Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. +The default JavaMail API implementation used to send out emails behaves in this way, for example. + +You can add your truststore configuration by using the following template: + +[source] +---- + +"truststore": { + "file": { + "file": "path to your .jks file containing public certificates", + "password": "password", + "hostname-verification-policy": "WILDCARD", + "disabled": false + } +} +---- + +Possible configuration options are: + +file:: + The value is the file path to a Java keystore file. + HTTPS requests need a way to verify the host of the server they are talking to. + This is what the trustore does. + The keystore contains one or more trusted host certificates or certificate authorities. + Truststore file should only contain public certificates of your secured hosts. + This is _REQUIRED_ if `disabled` is not true. + +password:: + Password for the truststore. + This is _REQUIRED_ if `disabled` is not true. + +hostname-verification-policy:: + `WILDCARD` by default. + For HTTPS requests, this verifies the hostname of the server's certificate. + `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. + *.foo.com. `STRICT` CN must match hostname exactly. + +disabled:: + If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. + If set to false, you must configure `file`, and `password` for the truststore. + +You can use _keytool_ to create a new truststore file and add trusted host certificates to it: + +[source] +---- + +$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer +---- + +[[_ssl_modes]] +=== SSL/HTTPS Requirement/Modes + +WARNING: Keycloak is not set up by default to handle SSL/HTTPS. +It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. + +Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. +If you try to access Keycloak from a non-IP adress you will get an error. + +Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. +Each adapter config should mirror this server-side setting. +See adapter config section for more details. + +external:: + Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. + If you try to access Keycloak from a non-IP adress you will get an error. + +none:: + Keycloak does not require SSL. + +all:: + Keycloak requires SSL for all IP addresses. + +=== SSL/HTTPS Setup + +First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. +Then configure the Keycloak Server to enforce HTTPS connections. + +==== Enable SSL on Keycloak + +The following things need to be done + +* keytool +* Enable Wildfly to use this certificate and turn on SSL/HTTPS. + +===== Creating the Certificate and Java Keystore + +In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. + +====== Self Signed Certificate + +In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. +Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. + + +[source] +---- + +$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 + Enter keystore password: secret + Re-enter new password: secret + What is your first and last name? + [Unknown]: localhost + What is the name of your organizational unit? + [Unknown]: Keycloak + What is the name of your organization? + [Unknown]: Red Hat + What is the name of your City or Locality? + [Unknown]: Westford + What is the name of your State or Province? + [Unknown]: MA + What is the two-letter country code for this unit? + [Unknown]: US + Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? + [no]: yes +---- + +You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. +For testing purposes, `localhost` should be used. +After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. + +If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. +You'll have to do a little set up first before doing this though. + +The first thing to do is generate a Certificate Request: + +[source] +---- + +$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq +---- + +Where `yourdomain` is a DNS name for which this certificate is generated for. +Keytool generates the request: + +[source] +---- + +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y +ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY +Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 +29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as +H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw +Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 +2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i +n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf +PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ +9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X +MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S +vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= +-----END NEW CERTIFICATE REQUEST----- +---- + +Send this ca request to your CA. +The CA will issue you a signed certificate and send it to you. +Before you import your new cert, you must obtain and import the root certificate of the CA. +You can download the cert from CA (ie.: root.crt) and import as follows: + +[source] +---- + +$ keytool -import -keystore keycloak.jks -file root.crt -alias root +---- + +Last step is import your new CA generated certificate to your keystore: + +[source] +---- + +$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer +---- + +===== Installing the keystore to WildFly + +Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. +First step is to move the keystore file to a directory you can reference in configuration. +I like to put it in `standalone/configuration`. +Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. + +To the `security-realms` element add: + +[source] +---- + + + + + + + + +---- + +Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: + +[source] +---- + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. + +==== Enable SSL on a Reverse Proxy + +Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. +It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. +Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. +Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. + +===== Configure WildFly + +. Open `standalone/configuration/standalone.xml` in your favorite editor. + +. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: + +[source] +---- + + ... + + ... + +---- + +Then add a new `socket-binding` element to the `socket-binding-group` element: + +[source] +---- + + + ... + + ... + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. + +== Keycloak server in Domain Mode + +In domain mode, you start the server with the "domain" command instead of the "standalone" command. +In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. +Inside domain.xml, you will see more than one profile. +The Keycloak subsystem is defined for all initial profiles. + +THe server is also added to server profiles. +By default two servers are started in the main-server-group which uses the full profile. + +You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. + +To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. +See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. + +== Installing Keycloak Server as Root Context + +The Keycloak server can be installed as the default web application. +In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. + +To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. + +[source] +---- + + + + + + +---- + +`keycloak-server.war` is the runtime name of the Keycloak server application. +Note that the WAR file does not exist as a file. +If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. + + + +NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. +To fix this on the server side, you will need to export your database to json, make corrections, and then import. +Client-side `keycloak.json` files will need to be updated manually as well. diff --git a/topics/installation/getting-files-community.adoc b/topics/installation/getting-files-community.adoc new file mode 100755 index 0000000000..13d2be6ec3 --- /dev/null +++ b/topics/installation/getting-files-community.adoc @@ -0,0 +1,11 @@ += Getting Distribution Files + +Keycloak Server has three downloadable distributions. +To run the Keycloak server you need to have Java 8 already installed. + +* keycloak-.[zip|tar.gz] +* keycloak-overlay-.[zip|tar.gz] +* keycloak-demo-.[zip|tar.gz] + + + diff --git a/topics/overview.adoc b/topics/overview.adoc index 64136a69d4..87ab32f51e 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -1,10 +1,10 @@ = Guide Overview The purpose of this guide is to walk through the steps that need to be completed prior to booting up the -Keycloak server for the first time. If you just want to test drive Keycloak, it pretty much runs out of the box with its +{{book.project.name}} server for the first time. If you just want to test drive {{book.project.name}}, it pretty much runs out of the box with its own embedded and local-only database. For actual deployments that are going to be run in production you'll need to decide how you want to manage server configuration - at runtime (standalone or domain mode), configure a shared database you will use for Keycloak, set up encryption and HTTPS, - and finally set up Keycloak to run in a cluster. This guide walks through each and every aspect of any pre-boot - decisions and setup you must do prior to deploying Keycloak. + at runtime (standalone or domain mode), configure a shared database for {{book.project.name}} storage, set up encryption and HTTPS, + and finally set up {{book.project.name}} to run in a cluster. This guide walks through each and every aspect of any pre-boot + decisions and setup you must do prior to deploying the server. diff --git a/topics/preface.adoc b/topics/preface.adoc index 46e39e8ae6..3a0cd073cb 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -18,4 +18,3 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Test if attribute is working {{book.project.name}} \ No newline at end of file diff --git a/topics/server-installation.adoc b/topics/server-installation.adoc deleted file mode 100755 index 697f2483e6..0000000000 --- a/topics/server-installation.adoc +++ /dev/null @@ -1,610 +0,0 @@ -[[_server_installation]] - -= Installation and Configuration of Keycloak Server - -== Installation - -Keycloak Server has three downloadable distributions. -To run the Keycloak server you need to have Java 8 already installed. - -* keycloak-.[zip|tar.gz] -* keycloak-overlay-.[zip|tar.gz] -* keycloak-demo-.[zip|tar.gz] - -[[_server_install]] -=== Install Standalone Server - -For production and for non-JavaEE developers we recommend using the standalone Keycloak server. -All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. - -To install first download either the zip or tar.gz and extract. -Then start by running either: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -[[_overlay_install]] -=== Install on existing WildFly or JBoss EAP - -Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. -Once downloaded extract into the root directory of your installation. - -To add Keycloak to existing standalone.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install.cli ----- -To add Keycloak to existing standalone-ha.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli ----- -If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. - -=== Install Development Bundle - -The demo bundle contains everything you need to get started with Keycloak including documentation and examples. -To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. -Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. -You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. - -To start WildFly with Keycloak run: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -== Configuring the Server - -Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. -Specifically: - -* Configuring Keycloak to use a production database -* Setting up SSL/HTTPS -* Enforcing HTTPS connections - -=== Admin User - -To access the admin console to configure Keycloak you need an account to login. -There is no built in user, instead you have to first create an admin account. -This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. - -The `add-user` script creates a temporary file with the details of the user, which are imported at startup. -To add a user with this script run: - -[source] ----- - -bin/add-user.[sh|bat] -r master -u -p ----- -Then restart the server. -For `keycloak-overlay`, please make sure to use: - -[source] ----- -bin/add-user-keycloak.[sh|bat] -r master -u -p ----- - -=== Relational Database Configuration - -You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. -You might also want to tweak the configuration settings of the datasource. -Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. - -Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- -"connectionsJpa": { - "default": { - "dataSource": "java:jboss/datasources/KeycloakDS", - "databaseSchema": "update" - } -}, ----- -Possible configuration options are: - -dataSource:: - JNDI name of the dataSource - -jta:: - boolean property to specify if datasource is JTA capable - -driverDialect:: - Value of Hibernate dialect. - In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. - -databaseSchema:: - Specify if schema should be updated or validated. - Valid values are "update" and "validate" ("update is default). - -showSql:: - Specify whether Hibernate should show all SQL commands in the console (false by default) - -formatSql:: - Specify whether Hibernate should format SQL commands (true by default) - -globalStatsInterval:: - Will log global statistics from Hibernate about executed DB queries and other things. - Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. - -schema:: - Specify the database schema to use - -===== Tested databases - -Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. -Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. -You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). - -.Tested databases -[cols="1,1,1", frame="all", options="header"] -|=== -| Database -| JDBC driver -| Hibernate Dialect - - - - - - -|=== - -=== MongoDB based model - -Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. -To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: - -[source] ----- - -"eventsStore": { - "provider": "jpa", - "jpa": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "jpa" -}, - -"user": { - "provider": "${keycloak.user.provider:jpa}" -}, ----- -to: - -[source] ----- - -"eventsStore": { - "provider": "mongo", - "mongo": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "mongo" -}, - -"user": { - "provider": "mongo" -}, ----- -And at the end of the file add the snippet like this where you can configure details about your Mongo database: - -[source] ----- - -"connectionsMongo": { - "default": { - "host": "127.0.0.1", - "port": "27017", - "db": "keycloak", - "connectionsPerHost": 100, - "databaseSchema": "update" - } -} ----- -All configuration options are optional. -Default values for host and port are localhost and 27017. -Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. -If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. - -Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. -Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. -Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. -Supported long option is `maxAutoConnectRetryTime`. -See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. - -Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. -In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. -Please note that the database specified within the URI is only used for authentication. -To change the database used by keycloak you have to set `db` property as before. -Therefore, a configuration like the following - -[source] ----- - -"connectionsMongo": { - "default": { - "uri": "mongodb://user:password@127.0.0.1/authentication", - "db": "keycloak" - } -} ----- -will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. - -==== MongoDB Replica Sets - -In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. - -=== Outgoing Server HTTP Requests - -Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. -Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. -This is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- - -"connectionsHttpClient": { - "default": {} -}, ----- -Possible configuration options are: - -establish-connection-timeout-millis:: - Timeout for establishing a socket connection. - -socket-timeout-millis:: - If an outgoing request does not receive data for this amount of time, timeout the connection. - -connection-pool-size:: - How many connections can be in the pool (128 by default). - -max-pooled-per-route:: - How many connections can be pooled per host (64 by default). - -connection-ttl-millis:: - Maximum connection time to live in milliseconds. - Not set by default. - -max-connection-idle-time-millis:: - Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. - Set to -1 to disable this checking and the background thread. - -disable-cookies:: - `true` by default. - When set to true, this will disable any cookie caching. - -client-keystore:: - This is the file path to a Java keystore file. - This keystore contains client certificate for two-way SSL. - -client-keystore-password:: - Password for the client keystore. - This is _REQUIRED_ if `client-keystore` is set. - -client-key-password:: - _Not supported yet, but we will support in future versions. Password for the client's key. - This is _REQUIRED_ if `client-keystore` is set. - -[[_truststore]] -=== Securing Outgoing Server HTTP Requests - -When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. -That is necessary in order to prevent man-in-the-middle attacks. - -How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. -By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ - Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. - -Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. -Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. -The default JavaMail API implementation used to send out emails behaves in this way, for example. - -You can add your truststore configuration by using the following template: - -[source] ----- - -"truststore": { - "file": { - "file": "path to your .jks file containing public certificates", - "password": "password", - "hostname-verification-policy": "WILDCARD", - "disabled": false - } -} ----- - -Possible configuration options are: - -file:: - The value is the file path to a Java keystore file. - HTTPS requests need a way to verify the host of the server they are talking to. - This is what the trustore does. - The keystore contains one or more trusted host certificates or certificate authorities. - Truststore file should only contain public certificates of your secured hosts. - This is _REQUIRED_ if `disabled` is not true. - -password:: - Password for the truststore. - This is _REQUIRED_ if `disabled` is not true. - -hostname-verification-policy:: - `WILDCARD` by default. - For HTTPS requests, this verifies the hostname of the server's certificate. - `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. - *.foo.com. `STRICT` CN must match hostname exactly. - -disabled:: - If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. - If set to false, you must configure `file`, and `password` for the truststore. - -You can use _keytool_ to create a new truststore file and add trusted host certificates to it: - -[source] ----- - -$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer ----- - -[[_ssl_modes]] -=== SSL/HTTPS Requirement/Modes - -WARNING: Keycloak is not set up by default to handle SSL/HTTPS. -It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. - -Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. -If you try to access Keycloak from a non-IP adress you will get an error. - -Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. -Each adapter config should mirror this server-side setting. -See adapter config section for more details. - -external:: - Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. - If you try to access Keycloak from a non-IP adress you will get an error. - -none:: - Keycloak does not require SSL. - -all:: - Keycloak requires SSL for all IP addresses. - -=== SSL/HTTPS Setup - -First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. -Then configure the Keycloak Server to enforce HTTPS connections. - -==== Enable SSL on Keycloak - -The following things need to be done - -* keytool -* Enable Wildfly to use this certificate and turn on SSL/HTTPS. - -===== Creating the Certificate and Java Keystore - -In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. - -====== Self Signed Certificate - -In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. -Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. - - -[source] ----- - -$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 - Enter keystore password: secret - Re-enter new password: secret - What is your first and last name? - [Unknown]: localhost - What is the name of your organizational unit? - [Unknown]: Keycloak - What is the name of your organization? - [Unknown]: Red Hat - What is the name of your City or Locality? - [Unknown]: Westford - What is the name of your State or Province? - [Unknown]: MA - What is the two-letter country code for this unit? - [Unknown]: US - Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? - [no]: yes ----- - -You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. -For testing purposes, `localhost` should be used. -After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. - -If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. -You'll have to do a little set up first before doing this though. - -The first thing to do is generate a Certificate Request: - -[source] ----- - -$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq ----- - -Where `yourdomain` is a DNS name for which this certificate is generated for. -Keytool generates the request: - -[source] ----- - ------BEGIN NEW CERTIFICATE REQUEST----- -MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y -ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY -Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 -29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as -H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw -Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 -2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i -n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf -PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ -9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X -MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S -vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= ------END NEW CERTIFICATE REQUEST----- ----- - -Send this ca request to your CA. -The CA will issue you a signed certificate and send it to you. -Before you import your new cert, you must obtain and import the root certificate of the CA. -You can download the cert from CA (ie.: root.crt) and import as follows: - -[source] ----- - -$ keytool -import -keystore keycloak.jks -file root.crt -alias root ----- - -Last step is import your new CA generated certificate to your keystore: - -[source] ----- - -$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer ----- - -===== Installing the keystore to WildFly - -Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. -First step is to move the keystore file to a directory you can reference in configuration. -I like to put it in `standalone/configuration`. -Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. - -To the `security-realms` element add: - -[source] ----- - - - - - - - - ----- - -Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: - -[source] ----- - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. - -==== Enable SSL on a Reverse Proxy - -Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. -It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. -Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. -Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. - -===== Configure WildFly - -. Open `standalone/configuration/standalone.xml` in your favorite editor. - -. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: - -[source] ----- - - ... - - ... - ----- - -Then add a new `socket-binding` element to the `socket-binding-group` element: - -[source] ----- - - - ... - - ... - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. - -== Keycloak server in Domain Mode - -In domain mode, you start the server with the "domain" command instead of the "standalone" command. -In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. -Inside domain.xml, you will see more than one profile. -The Keycloak subsystem is defined for all initial profiles. - -THe server is also added to server profiles. -By default two servers are started in the main-server-group which uses the full profile. - -You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. - -To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. -See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. - -== Installing Keycloak Server as Root Context - -The Keycloak server can be installed as the default web application. -In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. - -To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. - -[source] ----- - - - - - - ----- - -`keycloak-server.war` is the runtime name of the Keycloak server application. -Note that the WAR file does not exist as a file. -If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. - - - -NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. -To fix this on the server side, you will need to export your database to json, make corrections, and then import. -Client-side `keycloak.json` files will need to be updated manually as well. diff --git a/topics/system-requirements.adoc b/topics/system-requirements.adoc new file mode 100755 index 0000000000..2d0ea122cb --- /dev/null +++ b/topics/system-requirements.adoc @@ -0,0 +1,9 @@ += System Requirements + +These are the requirements to run the {{book.project.name}} authentication server: + +* Java 8 JDK +* Network multicast support if you clustering {{book.project.name}}. + +{{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see +the <<_clustering,clustering>> section of this guide for more information. \ No newline at end of file From 39b2559e64c8a637b39f11984d84f9cf04b70030 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 17:49:18 -0400 Subject: [PATCH 025/149] more --- SUMMARY.adoc | 8 +- book.json | 5 +- topics/installation.adoc | 613 +----------------- .../distribution-files-community.adoc | 24 + .../distribution-files-product.adoc | 15 + .../installation/getting-files-community.adoc | 11 - topics/installation/system-requirements.adoc | 13 + topics/old-installation.adoc | 610 +++++++++++++++++ topics/system-requirements.adoc | 9 - 9 files changed, 675 insertions(+), 633 deletions(-) create mode 100755 topics/installation/distribution-files-community.adoc create mode 100755 topics/installation/distribution-files-product.adoc delete mode 100755 topics/installation/getting-files-community.adoc create mode 100755 topics/installation/system-requirements.adoc create mode 100755 topics/old-installation.adoc delete mode 100755 topics/system-requirements.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 701c2ea4d9..b63a7819d8 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -5,9 +5,11 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] - . link:topics/system-requirements.adoc[System Requirements] - . link:topics/installation.adoc[Installation and Configuration of Keycloak Server] - . link:topics/openshift.adoc[Running Keycloak Server on OpenShift] + . link:topics/installation.adoc[Installation] + .. link:topics/installation/system-requirements.adoc[System Requirements] + {% if community %}.. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] {% endif %} + {% if product %}.. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} + .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/proxy.adoc[Keycloak Security Proxy] diff --git a/book.json b/book.json index eeb58d9f80..2340e09a27 100755 --- a/book.json +++ b/book.json @@ -9,8 +9,11 @@ "splitter" ], "variables": { + "community": "true", + "product": "false", "project": { - "name": "Keycloak" + "name": "Keycloak", + "version": "1.9.3.Final-SNAPSHOT" } } } \ No newline at end of file diff --git a/topics/installation.adoc b/topics/installation.adoc index 697f2483e6..97769fdf49 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -1,610 +1,5 @@ -[[_server_installation]] += Installation -= Installation and Configuration of Keycloak Server - -== Installation - -Keycloak Server has three downloadable distributions. -To run the Keycloak server you need to have Java 8 already installed. - -* keycloak-.[zip|tar.gz] -* keycloak-overlay-.[zip|tar.gz] -* keycloak-demo-.[zip|tar.gz] - -[[_server_install]] -=== Install Standalone Server - -For production and for non-JavaEE developers we recommend using the standalone Keycloak server. -All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. - -To install first download either the zip or tar.gz and extract. -Then start by running either: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -[[_overlay_install]] -=== Install on existing WildFly or JBoss EAP - -Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. -Once downloaded extract into the root directory of your installation. - -To add Keycloak to existing standalone.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install.cli ----- -To add Keycloak to existing standalone-ha.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli ----- -If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. - -=== Install Development Bundle - -The demo bundle contains everything you need to get started with Keycloak including documentation and examples. -To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. -Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. -You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. - -To start WildFly with Keycloak run: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -== Configuring the Server - -Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. -Specifically: - -* Configuring Keycloak to use a production database -* Setting up SSL/HTTPS -* Enforcing HTTPS connections - -=== Admin User - -To access the admin console to configure Keycloak you need an account to login. -There is no built in user, instead you have to first create an admin account. -This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. - -The `add-user` script creates a temporary file with the details of the user, which are imported at startup. -To add a user with this script run: - -[source] ----- - -bin/add-user.[sh|bat] -r master -u -p ----- -Then restart the server. -For `keycloak-overlay`, please make sure to use: - -[source] ----- -bin/add-user-keycloak.[sh|bat] -r master -u -p ----- - -=== Relational Database Configuration - -You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. -You might also want to tweak the configuration settings of the datasource. -Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. - -Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- -"connectionsJpa": { - "default": { - "dataSource": "java:jboss/datasources/KeycloakDS", - "databaseSchema": "update" - } -}, ----- -Possible configuration options are: - -dataSource:: - JNDI name of the dataSource - -jta:: - boolean property to specify if datasource is JTA capable - -driverDialect:: - Value of Hibernate dialect. - In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. - -databaseSchema:: - Specify if schema should be updated or validated. - Valid values are "update" and "validate" ("update is default). - -showSql:: - Specify whether Hibernate should show all SQL commands in the console (false by default) - -formatSql:: - Specify whether Hibernate should format SQL commands (true by default) - -globalStatsInterval:: - Will log global statistics from Hibernate about executed DB queries and other things. - Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. - -schema:: - Specify the database schema to use - -===== Tested databases - -Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. -Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. -You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). - -.Tested databases -[cols="1,1,1", frame="all", options="header"] -|=== -| Database -| JDBC driver -| Hibernate Dialect - - - - - - -|=== - -=== MongoDB based model - -Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. -To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: - -[source] ----- - -"eventsStore": { - "provider": "jpa", - "jpa": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "jpa" -}, - -"user": { - "provider": "${keycloak.user.provider:jpa}" -}, ----- -to: - -[source] ----- - -"eventsStore": { - "provider": "mongo", - "mongo": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "mongo" -}, - -"user": { - "provider": "mongo" -}, ----- -And at the end of the file add the snippet like this where you can configure details about your Mongo database: - -[source] ----- - -"connectionsMongo": { - "default": { - "host": "127.0.0.1", - "port": "27017", - "db": "keycloak", - "connectionsPerHost": 100, - "databaseSchema": "update" - } -} ----- -All configuration options are optional. -Default values for host and port are localhost and 27017. -Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. -If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. - -Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. -Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. -Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. -Supported long option is `maxAutoConnectRetryTime`. -See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. - -Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. -In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. -Please note that the database specified within the URI is only used for authentication. -To change the database used by keycloak you have to set `db` property as before. -Therefore, a configuration like the following - -[source] ----- - -"connectionsMongo": { - "default": { - "uri": "mongodb://user:password@127.0.0.1/authentication", - "db": "keycloak" - } -} ----- -will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. - -==== MongoDB Replica Sets - -In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. - -=== Outgoing Server HTTP Requests - -Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. -Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. -This is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- - -"connectionsHttpClient": { - "default": {} -}, ----- -Possible configuration options are: - -establish-connection-timeout-millis:: - Timeout for establishing a socket connection. - -socket-timeout-millis:: - If an outgoing request does not receive data for this amount of time, timeout the connection. - -connection-pool-size:: - How many connections can be in the pool (128 by default). - -max-pooled-per-route:: - How many connections can be pooled per host (64 by default). - -connection-ttl-millis:: - Maximum connection time to live in milliseconds. - Not set by default. - -max-connection-idle-time-millis:: - Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. - Set to -1 to disable this checking and the background thread. - -disable-cookies:: - `true` by default. - When set to true, this will disable any cookie caching. - -client-keystore:: - This is the file path to a Java keystore file. - This keystore contains client certificate for two-way SSL. - -client-keystore-password:: - Password for the client keystore. - This is _REQUIRED_ if `client-keystore` is set. - -client-key-password:: - _Not supported yet, but we will support in future versions. Password for the client's key. - This is _REQUIRED_ if `client-keystore` is set. - -[[_truststore]] -=== Securing Outgoing Server HTTP Requests - -When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. -That is necessary in order to prevent man-in-the-middle attacks. - -How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. -By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ - Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. - -Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. -Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. -The default JavaMail API implementation used to send out emails behaves in this way, for example. - -You can add your truststore configuration by using the following template: - -[source] ----- - -"truststore": { - "file": { - "file": "path to your .jks file containing public certificates", - "password": "password", - "hostname-verification-policy": "WILDCARD", - "disabled": false - } -} ----- - -Possible configuration options are: - -file:: - The value is the file path to a Java keystore file. - HTTPS requests need a way to verify the host of the server they are talking to. - This is what the trustore does. - The keystore contains one or more trusted host certificates or certificate authorities. - Truststore file should only contain public certificates of your secured hosts. - This is _REQUIRED_ if `disabled` is not true. - -password:: - Password for the truststore. - This is _REQUIRED_ if `disabled` is not true. - -hostname-verification-policy:: - `WILDCARD` by default. - For HTTPS requests, this verifies the hostname of the server's certificate. - `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. - *.foo.com. `STRICT` CN must match hostname exactly. - -disabled:: - If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. - If set to false, you must configure `file`, and `password` for the truststore. - -You can use _keytool_ to create a new truststore file and add trusted host certificates to it: - -[source] ----- - -$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer ----- - -[[_ssl_modes]] -=== SSL/HTTPS Requirement/Modes - -WARNING: Keycloak is not set up by default to handle SSL/HTTPS. -It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. - -Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. -If you try to access Keycloak from a non-IP adress you will get an error. - -Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. -Each adapter config should mirror this server-side setting. -See adapter config section for more details. - -external:: - Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. - If you try to access Keycloak from a non-IP adress you will get an error. - -none:: - Keycloak does not require SSL. - -all:: - Keycloak requires SSL for all IP addresses. - -=== SSL/HTTPS Setup - -First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. -Then configure the Keycloak Server to enforce HTTPS connections. - -==== Enable SSL on Keycloak - -The following things need to be done - -* keytool -* Enable Wildfly to use this certificate and turn on SSL/HTTPS. - -===== Creating the Certificate and Java Keystore - -In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. - -====== Self Signed Certificate - -In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. -Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. - - -[source] ----- - -$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 - Enter keystore password: secret - Re-enter new password: secret - What is your first and last name? - [Unknown]: localhost - What is the name of your organizational unit? - [Unknown]: Keycloak - What is the name of your organization? - [Unknown]: Red Hat - What is the name of your City or Locality? - [Unknown]: Westford - What is the name of your State or Province? - [Unknown]: MA - What is the two-letter country code for this unit? - [Unknown]: US - Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? - [no]: yes ----- - -You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. -For testing purposes, `localhost` should be used. -After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. - -If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. -You'll have to do a little set up first before doing this though. - -The first thing to do is generate a Certificate Request: - -[source] ----- - -$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq ----- - -Where `yourdomain` is a DNS name for which this certificate is generated for. -Keytool generates the request: - -[source] ----- - ------BEGIN NEW CERTIFICATE REQUEST----- -MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y -ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY -Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 -29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as -H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw -Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 -2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i -n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf -PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ -9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X -MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S -vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= ------END NEW CERTIFICATE REQUEST----- ----- - -Send this ca request to your CA. -The CA will issue you a signed certificate and send it to you. -Before you import your new cert, you must obtain and import the root certificate of the CA. -You can download the cert from CA (ie.: root.crt) and import as follows: - -[source] ----- - -$ keytool -import -keystore keycloak.jks -file root.crt -alias root ----- - -Last step is import your new CA generated certificate to your keystore: - -[source] ----- - -$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer ----- - -===== Installing the keystore to WildFly - -Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. -First step is to move the keystore file to a directory you can reference in configuration. -I like to put it in `standalone/configuration`. -Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. - -To the `security-realms` element add: - -[source] ----- - - - - - - - - ----- - -Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: - -[source] ----- - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. - -==== Enable SSL on a Reverse Proxy - -Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. -It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. -Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. -Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. - -===== Configure WildFly - -. Open `standalone/configuration/standalone.xml` in your favorite editor. - -. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: - -[source] ----- - - ... - - ... - ----- - -Then add a new `socket-binding` element to the `socket-binding-group` element: - -[source] ----- - - - ... - - ... - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. - -== Keycloak server in Domain Mode - -In domain mode, you start the server with the "domain" command instead of the "standalone" command. -In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. -Inside domain.xml, you will see more than one profile. -The Keycloak subsystem is defined for all initial profiles. - -THe server is also added to server profiles. -By default two servers are started in the main-server-group which uses the full profile. - -You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. - -To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. -See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. - -== Installing Keycloak Server as Root Context - -The Keycloak server can be installed as the default web application. -In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. - -To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. - -[source] ----- - - - - - - ----- - -`keycloak-server.war` is the runtime name of the Keycloak server application. -Note that the WAR file does not exist as a file. -If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. - - - -NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. -To fix this on the server side, you will need to export your database to json, make corrections, and then import. -Client-side `keycloak.json` files will need to be updated manually as well. +This chapter reviews what binaries you need to install to run the {{book.project.name}} Server on a specific machine. +It describes the directory structure and files of the distribution. Finally, it describes how to install {{book.project.name}} +on the cloud if you prefer that type of deployment. \ No newline at end of file diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc new file mode 100755 index 0000000000..35fc8cead3 --- /dev/null +++ b/topics/installation/distribution-files-community.adoc @@ -0,0 +1,24 @@ += Installing Distribution Files + +The Keycloak Server has three downloadable distributions: + +* +keycloak-{{book.project.version}}.[zip|tar.gz]+ +* +keycloak-overlay-{{book.project.version}}.[zip|tar.gz]+ +* +keycloak-demo-{{book.project.version}}.[zip|tar.gz]+ + +The +keycloak-{{book.project.version}}.[zip|tar.gz]+ file is the server only distribution. It contains nothing other than the scripts and binaries +to run the Keycloak Server. + +The +keycloak-overlay-{{book.project.version}}.[zip|tar.gz]+ file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing +Wildfly or JBoss EAP distribution. We suggest that you do not use this file unless you want to install on top of a JBoss EAP distribution. + +The +keycloak-demo-{{book.project.version}}.[zip|tar.gz]+ contains a the server binaries, all documentation and all examples. It is preconfigured with both the +OIDC and SAML client application adapters and can deploy any of the distribution examples out of the box with no configuration. This distribution is only +recommended for those that want to test drive Keycloak. + +To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. + + + + + diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc new file mode 100755 index 0000000000..d94ef8ab4a --- /dev/null +++ b/topics/installation/distribution-files-product.adoc @@ -0,0 +1,15 @@ += Installing Distribution Files + +The Keycloak Server is contained in one distribution file: + +* +RH-SSO-{{book.project.version}}.[zip|tar.gz]+ + +The +RH-SSO-{{book.project.version}}.[zip|tar.gz]+ file is the server only distribution. It contains nothing other than the scripts and binaries +to run the Keycloak Server. + +To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. + + + + + diff --git a/topics/installation/getting-files-community.adoc b/topics/installation/getting-files-community.adoc deleted file mode 100755 index 13d2be6ec3..0000000000 --- a/topics/installation/getting-files-community.adoc +++ /dev/null @@ -1,11 +0,0 @@ -= Getting Distribution Files - -Keycloak Server has three downloadable distributions. -To run the Keycloak server you need to have Java 8 already installed. - -* keycloak-.[zip|tar.gz] -* keycloak-overlay-.[zip|tar.gz] -* keycloak-demo-.[zip|tar.gz] - - - diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc new file mode 100755 index 0000000000..604389e97a --- /dev/null +++ b/topics/installation/system-requirements.adoc @@ -0,0 +1,13 @@ += System Requirements + +These are the requirements to run the {{book.project.name}} authentication server: + +* Can run on any operating system that runs Java +* Java 8 JDK +* zip or gzip and tar +* Network multicast support if you are clustering {{book.project.name}}. +* At least 512M of RAM +* At least 1G of diskspace + +{{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see +the <<../clustering.adoc#,clustering>> section of this guide for more information. \ No newline at end of file diff --git a/topics/old-installation.adoc b/topics/old-installation.adoc new file mode 100755 index 0000000000..697f2483e6 --- /dev/null +++ b/topics/old-installation.adoc @@ -0,0 +1,610 @@ +[[_server_installation]] + += Installation and Configuration of Keycloak Server + +== Installation + +Keycloak Server has three downloadable distributions. +To run the Keycloak server you need to have Java 8 already installed. + +* keycloak-.[zip|tar.gz] +* keycloak-overlay-.[zip|tar.gz] +* keycloak-demo-.[zip|tar.gz] + +[[_server_install]] +=== Install Standalone Server + +For production and for non-JavaEE developers we recommend using the standalone Keycloak server. +All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. + +To install first download either the zip or tar.gz and extract. +Then start by running either: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +[[_overlay_install]] +=== Install on existing WildFly or JBoss EAP + +Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. +Once downloaded extract into the root directory of your installation. + +To add Keycloak to existing standalone.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install.cli +---- +To add Keycloak to existing standalone-ha.xml server config run: + +[source] +---- + +bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli +---- +If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. + +=== Install Development Bundle + +The demo bundle contains everything you need to get started with Keycloak including documentation and examples. +To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. +Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. +You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. + +To start WildFly with Keycloak run: + +[source] +---- +keycloak-/bin/standalone.sh +---- +or: + +[source] +---- +keycloak-/bin/standalone.bat +---- + +== Configuring the Server + +Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. +Specifically: + +* Configuring Keycloak to use a production database +* Setting up SSL/HTTPS +* Enforcing HTTPS connections + +=== Admin User + +To access the admin console to configure Keycloak you need an account to login. +There is no built in user, instead you have to first create an admin account. +This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. + +The `add-user` script creates a temporary file with the details of the user, which are imported at startup. +To add a user with this script run: + +[source] +---- + +bin/add-user.[sh|bat] -r master -u -p +---- +Then restart the server. +For `keycloak-overlay`, please make sure to use: + +[source] +---- +bin/add-user-keycloak.[sh|bat] -r master -u -p +---- + +=== Relational Database Configuration + +You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. +You might also want to tweak the configuration settings of the datasource. +Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. + +Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- +"connectionsJpa": { + "default": { + "dataSource": "java:jboss/datasources/KeycloakDS", + "databaseSchema": "update" + } +}, +---- +Possible configuration options are: + +dataSource:: + JNDI name of the dataSource + +jta:: + boolean property to specify if datasource is JTA capable + +driverDialect:: + Value of Hibernate dialect. + In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. + +databaseSchema:: + Specify if schema should be updated or validated. + Valid values are "update" and "validate" ("update is default). + +showSql:: + Specify whether Hibernate should show all SQL commands in the console (false by default) + +formatSql:: + Specify whether Hibernate should format SQL commands (true by default) + +globalStatsInterval:: + Will log global statistics from Hibernate about executed DB queries and other things. + Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. + +schema:: + Specify the database schema to use + +===== Tested databases + +Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. +Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. +You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). + +.Tested databases +[cols="1,1,1", frame="all", options="header"] +|=== +| Database +| JDBC driver +| Hibernate Dialect + + + + + + +|=== + +=== MongoDB based model + +Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. +To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: + +[source] +---- + +"eventsStore": { + "provider": "jpa", + "jpa": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "jpa" +}, + +"user": { + "provider": "${keycloak.user.provider:jpa}" +}, +---- +to: + +[source] +---- + +"eventsStore": { + "provider": "mongo", + "mongo": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "mongo" +}, + +"user": { + "provider": "mongo" +}, +---- +And at the end of the file add the snippet like this where you can configure details about your Mongo database: + +[source] +---- + +"connectionsMongo": { + "default": { + "host": "127.0.0.1", + "port": "27017", + "db": "keycloak", + "connectionsPerHost": 100, + "databaseSchema": "update" + } +} +---- +All configuration options are optional. +Default values for host and port are localhost and 27017. +Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. +If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. + +Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. +Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. +Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. +Supported long option is `maxAutoConnectRetryTime`. +See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. + +Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. +In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. +Please note that the database specified within the URI is only used for authentication. +To change the database used by keycloak you have to set `db` property as before. +Therefore, a configuration like the following + +[source] +---- + +"connectionsMongo": { + "default": { + "uri": "mongodb://user:password@127.0.0.1/authentication", + "db": "keycloak" + } +} +---- +will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. + +==== MongoDB Replica Sets + +In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. + +=== Outgoing Server HTTP Requests + +Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. +Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. +This is configured in the `standalone/configuration/keycloak-server.json`. +By default the setting is like this: + +[source] +---- + +"connectionsHttpClient": { + "default": {} +}, +---- +Possible configuration options are: + +establish-connection-timeout-millis:: + Timeout for establishing a socket connection. + +socket-timeout-millis:: + If an outgoing request does not receive data for this amount of time, timeout the connection. + +connection-pool-size:: + How many connections can be in the pool (128 by default). + +max-pooled-per-route:: + How many connections can be pooled per host (64 by default). + +connection-ttl-millis:: + Maximum connection time to live in milliseconds. + Not set by default. + +max-connection-idle-time-millis:: + Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. + Set to -1 to disable this checking and the background thread. + +disable-cookies:: + `true` by default. + When set to true, this will disable any cookie caching. + +client-keystore:: + This is the file path to a Java keystore file. + This keystore contains client certificate for two-way SSL. + +client-keystore-password:: + Password for the client keystore. + This is _REQUIRED_ if `client-keystore` is set. + +client-key-password:: + _Not supported yet, but we will support in future versions. Password for the client's key. + This is _REQUIRED_ if `client-keystore` is set. + +[[_truststore]] +=== Securing Outgoing Server HTTP Requests + +When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. +That is necessary in order to prevent man-in-the-middle attacks. + +How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. +By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ + Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. + +Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. +Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. +The default JavaMail API implementation used to send out emails behaves in this way, for example. + +You can add your truststore configuration by using the following template: + +[source] +---- + +"truststore": { + "file": { + "file": "path to your .jks file containing public certificates", + "password": "password", + "hostname-verification-policy": "WILDCARD", + "disabled": false + } +} +---- + +Possible configuration options are: + +file:: + The value is the file path to a Java keystore file. + HTTPS requests need a way to verify the host of the server they are talking to. + This is what the trustore does. + The keystore contains one or more trusted host certificates or certificate authorities. + Truststore file should only contain public certificates of your secured hosts. + This is _REQUIRED_ if `disabled` is not true. + +password:: + Password for the truststore. + This is _REQUIRED_ if `disabled` is not true. + +hostname-verification-policy:: + `WILDCARD` by default. + For HTTPS requests, this verifies the hostname of the server's certificate. + `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. + *.foo.com. `STRICT` CN must match hostname exactly. + +disabled:: + If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. + If set to false, you must configure `file`, and `password` for the truststore. + +You can use _keytool_ to create a new truststore file and add trusted host certificates to it: + +[source] +---- + +$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer +---- + +[[_ssl_modes]] +=== SSL/HTTPS Requirement/Modes + +WARNING: Keycloak is not set up by default to handle SSL/HTTPS. +It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. + +Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. +If you try to access Keycloak from a non-IP adress you will get an error. + +Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. +Each adapter config should mirror this server-side setting. +See adapter config section for more details. + +external:: + Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. + If you try to access Keycloak from a non-IP adress you will get an error. + +none:: + Keycloak does not require SSL. + +all:: + Keycloak requires SSL for all IP addresses. + +=== SSL/HTTPS Setup + +First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. +Then configure the Keycloak Server to enforce HTTPS connections. + +==== Enable SSL on Keycloak + +The following things need to be done + +* keytool +* Enable Wildfly to use this certificate and turn on SSL/HTTPS. + +===== Creating the Certificate and Java Keystore + +In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. + +====== Self Signed Certificate + +In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. +Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. + + +[source] +---- + +$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 + Enter keystore password: secret + Re-enter new password: secret + What is your first and last name? + [Unknown]: localhost + What is the name of your organizational unit? + [Unknown]: Keycloak + What is the name of your organization? + [Unknown]: Red Hat + What is the name of your City or Locality? + [Unknown]: Westford + What is the name of your State or Province? + [Unknown]: MA + What is the two-letter country code for this unit? + [Unknown]: US + Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? + [no]: yes +---- + +You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. +For testing purposes, `localhost` should be used. +After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. + +If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. +You'll have to do a little set up first before doing this though. + +The first thing to do is generate a Certificate Request: + +[source] +---- + +$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq +---- + +Where `yourdomain` is a DNS name for which this certificate is generated for. +Keytool generates the request: + +[source] +---- + +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y +ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY +Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 +29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as +H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw +Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 +2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i +n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf +PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ +9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X +MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S +vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= +-----END NEW CERTIFICATE REQUEST----- +---- + +Send this ca request to your CA. +The CA will issue you a signed certificate and send it to you. +Before you import your new cert, you must obtain and import the root certificate of the CA. +You can download the cert from CA (ie.: root.crt) and import as follows: + +[source] +---- + +$ keytool -import -keystore keycloak.jks -file root.crt -alias root +---- + +Last step is import your new CA generated certificate to your keystore: + +[source] +---- + +$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer +---- + +===== Installing the keystore to WildFly + +Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. +First step is to move the keystore file to a directory you can reference in configuration. +I like to put it in `standalone/configuration`. +Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. + +To the `security-realms` element add: + +[source] +---- + + + + + + + + +---- + +Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: + +[source] +---- + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. + +==== Enable SSL on a Reverse Proxy + +Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. +It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. +Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. +Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. + +===== Configure WildFly + +. Open `standalone/configuration/standalone.xml` in your favorite editor. + +. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: + +[source] +---- + + ... + + ... + +---- + +Then add a new `socket-binding` element to the `socket-binding-group` element: + +[source] +---- + + + ... + + ... + +---- + +Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. + +== Keycloak server in Domain Mode + +In domain mode, you start the server with the "domain" command instead of the "standalone" command. +In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. +Inside domain.xml, you will see more than one profile. +The Keycloak subsystem is defined for all initial profiles. + +THe server is also added to server profiles. +By default two servers are started in the main-server-group which uses the full profile. + +You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. + +To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. +See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. + +== Installing Keycloak Server as Root Context + +The Keycloak server can be installed as the default web application. +In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. + +To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. + +[source] +---- + + + + + + +---- + +`keycloak-server.war` is the runtime name of the Keycloak server application. +Note that the WAR file does not exist as a file. +If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. + + + +NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. +To fix this on the server side, you will need to export your database to json, make corrections, and then import. +Client-side `keycloak.json` files will need to be updated manually as well. diff --git a/topics/system-requirements.adoc b/topics/system-requirements.adoc deleted file mode 100755 index 2d0ea122cb..0000000000 --- a/topics/system-requirements.adoc +++ /dev/null @@ -1,9 +0,0 @@ -= System Requirements - -These are the requirements to run the {{book.project.name}} authentication server: - -* Java 8 JDK -* Network multicast support if you clustering {{book.project.name}}. - -{{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <<_clustering,clustering>> section of this guide for more information. \ No newline at end of file From 40dc3eb513b9ee02b9fc891c45b620c973b0617c Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 17:52:40 -0400 Subject: [PATCH 026/149] more --- SUMMARY.adoc | 8 ++++++-- book.json | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index b63a7819d8..2e9f16dabb 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -7,8 +7,12 @@ . link:topics/overview.adoc[Overview] . link:topics/installation.adoc[Installation] .. link:topics/installation/system-requirements.adoc[System Requirements] - {% if community %}.. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] {% endif %} - {% if product %}.. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} + {% if community %} + .. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] + {% endif %} + {% if product %} + .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] + {% endif %} .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/book.json b/book.json index 2340e09a27..987aaa4c3f 100755 --- a/book.json +++ b/book.json @@ -9,8 +9,8 @@ "splitter" ], "variables": { - "community": "true", - "product": "false", + "community": true, + "product": false, "project": { "name": "Keycloak", "version": "1.9.3.Final-SNAPSHOT" From 6eb1d4f03c38ab0bab43eab2d0779e699774dcfe Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 17:57:26 -0400 Subject: [PATCH 027/149] more --- topics/preface.adoc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/topics/preface.adoc b/topics/preface.adoc index 3a0cd073cb..485aff32dc 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -18,3 +18,21 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- +{% if community %} + community set +{% else %} + community VARIABLE NOT SET +{% endif %} + +{% if book.community %} + book.community set +{% else %} + book.community VARIABLE NOT SET +{% endif %} + +{% if product %} + PRODUCT! +{% else %} + product VARIABLE NOT SET +{% endif %} + From 5862beacef43effee7ebd2237c97de483f6b3760 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 17:58:41 -0400 Subject: [PATCH 028/149] more --- topics/installation/system-requirements.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 604389e97a..93a2b0ded9 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -10,4 +10,4 @@ These are the requirements to run the {{book.project.name}} authentication serve * At least 1G of diskspace {{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <<../clustering.adoc#,clustering>> section of this guide for more information. \ No newline at end of file +the <> section of this guide for more information. \ No newline at end of file From 31ddcd6c4db7b057cb2fbca81706b6dbab0b623d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:01:07 -0400 Subject: [PATCH 029/149] more --- SUMMARY.adoc | 4 ++-- topics/installation/system-requirements.adoc | 2 +- topics/preface.adoc | 18 ------------------ 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 2e9f16dabb..c2abfc1b0b 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -7,10 +7,10 @@ . link:topics/overview.adoc[Overview] . link:topics/installation.adoc[Installation] .. link:topics/installation/system-requirements.adoc[System Requirements] - {% if community %} + {% if book.community %} .. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] {% endif %} - {% if product %} + {% if book.product %} .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} .. link:topics/openshift.adoc[Installing on OpenShift] diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 93a2b0ded9..18c9abdcfd 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -10,4 +10,4 @@ These are the requirements to run the {{book.project.name}} authentication serve * At least 1G of diskspace {{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <> section of this guide for more information. \ No newline at end of file +the <> section of this guide for more information. \ No newline at end of file diff --git a/topics/preface.adoc b/topics/preface.adoc index 485aff32dc..3a0cd073cb 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -18,21 +18,3 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -{% if community %} - community set -{% else %} - community VARIABLE NOT SET -{% endif %} - -{% if book.community %} - book.community set -{% else %} - book.community VARIABLE NOT SET -{% endif %} - -{% if product %} - PRODUCT! -{% else %} - product VARIABLE NOT SET -{% endif %} - From e6de9dd05a4c0c3c2c3ec46734ea2fd6ec75d270 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:04:17 -0400 Subject: [PATCH 030/149] more --- topics/installation/directory-structure.adoc | 2 ++ .../installation/distribution-files-community.adoc | 12 ++++++------ topics/installation/distribution-files-product.adoc | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) create mode 100755 topics/installation/directory-structure.adoc diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc new file mode 100755 index 0000000000..885a864ee2 --- /dev/null +++ b/topics/installation/directory-structure.adoc @@ -0,0 +1,2 @@ += Distribution Directory Structure + diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 35fc8cead3..5fe3b8a7d3 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -2,17 +2,17 @@ The Keycloak Server has three downloadable distributions: -* +keycloak-{{book.project.version}}.[zip|tar.gz]+ -* +keycloak-overlay-{{book.project.version}}.[zip|tar.gz]+ -* +keycloak-demo-{{book.project.version}}.[zip|tar.gz]+ +* 'keycloak-{{book.project.version}}.[zip|tar.gz]' +* 'keycloak-overlay-{{book.project.version}}.[zip|tar.gz]' +* 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' -The +keycloak-{{book.project.version}}.[zip|tar.gz]+ file is the server only distribution. It contains nothing other than the scripts and binaries +The 'keycloak-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries to run the Keycloak Server. -The +keycloak-overlay-{{book.project.version}}.[zip|tar.gz]+ file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing +The 'keycloak-overlay-{{book.project.version}}.[zip|tar.gz]' file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing Wildfly or JBoss EAP distribution. We suggest that you do not use this file unless you want to install on top of a JBoss EAP distribution. -The +keycloak-demo-{{book.project.version}}.[zip|tar.gz]+ contains a the server binaries, all documentation and all examples. It is preconfigured with both the +The 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' contains a the server binaries, all documentation and all examples. It is preconfigured with both the OIDC and SAML client application adapters and can deploy any of the distribution examples out of the box with no configuration. This distribution is only recommended for those that want to test drive Keycloak. diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc index d94ef8ab4a..8608a574d8 100755 --- a/topics/installation/distribution-files-product.adoc +++ b/topics/installation/distribution-files-product.adoc @@ -2,9 +2,9 @@ The Keycloak Server is contained in one distribution file: -* +RH-SSO-{{book.project.version}}.[zip|tar.gz]+ +* 'RH-SSO-{{book.project.version}}.[zip|tar.gz]' -The +RH-SSO-{{book.project.version}}.[zip|tar.gz]+ file is the server only distribution. It contains nothing other than the scripts and binaries +The 'RH-SSO-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries to run the Keycloak Server. To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. From 28d5952f4e7eab5ce25b04ff5a3bc0874447a71e Mon Sep 17 00:00:00 2001 From: patriot1burke Date: Wed, 20 Apr 2016 18:11:31 -0400 Subject: [PATCH 031/149] Update SUMMARY.adoc --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100755 => 100644 SUMMARY.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc old mode 100755 new mode 100644 index c2abfc1b0b..09c3fa8cda --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,7 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/installation.adoc[Installation] - .. link:topics/installation/system-requirements.adoc[System Requirements] + .. link:topics/installation/system-requirements.adoc[System Requirements test] {% if book.community %} .. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] {% endif %} From fc5e47c2a38074f311aec38a525165d5d9490ac9 Mon Sep 17 00:00:00 2001 From: patriot1burke Date: Wed, 20 Apr 2016 18:12:07 -0400 Subject: [PATCH 032/149] Update SUMMARY.adoc --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 09c3fa8cda..c2abfc1b0b 100644 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -6,7 +6,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] . link:topics/installation.adoc[Installation] - .. link:topics/installation/system-requirements.adoc[System Requirements test] + .. link:topics/installation/system-requirements.adoc[System Requirements] {% if book.community %} .. link:topics/installation/distribution-files-community.adoc[Installing Distribution Files] {% endif %} From cb22ec0b8cd5b83ed3cbae92c2e322f3d800f8ba Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:17:10 -0400 Subject: [PATCH 033/149] more --- SUMMARY.adoc | 1 + book.json | 1 + topics/installation/directory-structure.adoc | 4 ++++ 3 files changed, 6 insertions(+) mode change 100644 => 100755 SUMMARY.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc old mode 100644 new mode 100755 index 09c3fa8cda..187e2312f8 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -13,6 +13,7 @@ {% if book.product %} .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} + .. link:topics/installation/directory-structre.adoc .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/book.json b/book.json index 987aaa4c3f..3c205f04f5 100755 --- a/book.json +++ b/book.json @@ -11,6 +11,7 @@ "variables": { "community": true, "product": false, + "images": "rhsso-images", "project": { "name": "Keycloak", "version": "1.9.3.Final-SNAPSHOT" diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 885a864ee2..d8a5008760 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -1,2 +1,6 @@ = Distribution Directory Structure +This chapter walks you through the directory structure of the server distribution. + +.Distribution Directory Structure +image::{{book.images}}/files.png \ No newline at end of file From be53d6c1ae14a1f9812b37ecd2b1aadbd8d03820 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:18:04 -0400 Subject: [PATCH 034/149] more --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 37e9a3f3f2..990a0c8ef0 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -13,7 +13,7 @@ {% if book.product %} .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} - .. link:topics/installation/directory-structre.adoc + .. link:topics/installation/directory-structure.adoc .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] From 1a22fb852c97b959713a0f952cce8195e22c142b Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:19:33 -0400 Subject: [PATCH 035/149] more --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 990a0c8ef0..aca2fbd531 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -13,7 +13,7 @@ {% if book.product %} .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} - .. link:topics/installation/directory-structure.adoc + .. link:topics/installation/directory-structure.adoc[Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] From 185ace9a6de80ad80fd747be0d7f8fd2ac070762 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:20:42 -0400 Subject: [PATCH 036/149] more --- topics/installation/directory-structure.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index d8a5008760..9d903bb3b8 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -3,4 +3,4 @@ This chapter walks you through the directory structure of the server distribution. .Distribution Directory Structure -image::{{book.images}}/files.png \ No newline at end of file +image:{{book.images}}/files.png \ No newline at end of file From 3d848eee2b19071488e194cf937862834d390874 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:24:22 -0400 Subject: [PATCH 037/149] more --- SUMMARY.adoc | 7 ++----- topics/installation/directory-structure.adoc | 8 +++++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index aca2fbd531..2dba1058d3 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,7 +1,4 @@ -== Keycloak Reference Guide -:project.name: Keycloak -//. link:topics/templates/document-attributes.adoc[] -:imagesdir: images += Summary . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] @@ -13,7 +10,7 @@ {% if book.product %} .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} - .. link:topics/installation/directory-structure.adoc[Directory Structure] + .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 9d903bb3b8..bf811f2d83 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -3,4 +3,10 @@ This chapter walks you through the directory structure of the server distribution. .Distribution Directory Structure -image:{{book.images}}/files.png \ No newline at end of file +image:{{book.images}}/files.png[alt="distribution"] + +image:rhsso-images/files.png[alt="distribution"] + +image:../../rhsso-images/files.png[alt="distribution"] + +image:fake/../../rhsso-images/files.png[alt="distribution"] From 4a1d41d6d403c0e3ccaae1b19b3f6676454fcf9a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:34:16 -0400 Subject: [PATCH 038/149] more --- topics/installation/directory-structure.adoc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index bf811f2d83..f457592c20 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -2,11 +2,9 @@ This chapter walks you through the directory structure of the server distribution. -.Distribution Directory Structure -image:{{book.images}}/files.png[alt="distribution"] +. +.Distribution Directory Structure image:rhsso-images/files.png[alt="distribution"] -image:../../rhsso-images/files.png[alt="distribution"] -image:fake/../../rhsso-images/files.png[alt="distribution"] From 3e13c8d7de9cf36f076eff03920808b9d022c4dc Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 18:37:02 -0400 Subject: [PATCH 039/149] more --- keycloak-images/files.png | Bin 0 -> 6369 bytes topics/installation/directory-structure.adoc | 32 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) create mode 100755 keycloak-images/files.png diff --git a/keycloak-images/files.png b/keycloak-images/files.png new file mode 100755 index 0000000000000000000000000000000000000000..c1e2933037cb4a450f1d556efbccf304782eddff GIT binary patch literal 6369 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 Date: Wed, 20 Apr 2016 18:39:07 -0400 Subject: [PATCH 040/149] more --- topics/installation/directory-structure.adoc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index aa0a67e086..6eeed20f7a 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -3,33 +3,33 @@ This chapter walks you through the directory structure of the server distribution. .Distribution Directory Structure -{% if product %} +{% if book.product %} . image:rhsso-images/files.png[alt="distribution"] -{% elif %} +{% else %} image:keycloak-images/files.png[alt="distribution"] {% endif %} .Distribution Directory Structure2 -{% if product %} +{% if book.product %} . image:../rhsso-images/files.png[alt="distribution"] -{% elif %} +{% else %} image:../keycloak-images/files.png[alt="distribution"] {% endif %} .Distribution Directory Structure3 -{% if product %} +{% if book.product %} . image:../../rhsso-images/files.png[alt="distribution"] -{% elif %} +{% else %} image:../../keycloak-images/files.png[alt="distribution"] {% endif %} .Distribution Directory Structure4 -{% if product %} +{% if book.product %} . image:fake/../../rhsso-images/files.png[alt="distribution"] -{% elif %} +{% else %} image:fake/../../keycloak-images/files.png[alt="distribution"] {% endif %} From b1df510921c8f184d4f3770ce608f811f551c219 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 20 Apr 2016 19:00:27 -0400 Subject: [PATCH 041/149] more --- topics/installation/directory-structure.adoc | 49 +++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 6eeed20f7a..94f09a1a10 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -2,35 +2,38 @@ This chapter walks you through the directory structure of the server distribution. -.Distribution Directory Structure -{% if book.product %} -. image:rhsso-images/files.png[alt="distribution"] -{% else %} -image:keycloak-images/files.png[alt="distribution"] -{% endif %} - - -.Distribution Directory Structure2 -{% if book.product %} -. image:../rhsso-images/files.png[alt="distribution"] -{% else %} -image:../keycloak-images/files.png[alt="distribution"] -{% endif %} - - -.Distribution Directory Structure3 +.distribution directory structure {% if book.product %} . image:../../rhsso-images/files.png[alt="distribution"] {% else %} image:../../keycloak-images/files.png[alt="distribution"] {% endif %} +Let's examine some of the purposes of each directory + +_bin/_:: + This contains various scripts to either boot the server or perform some other management action on the server. + +_domain/_:: + This contains configuration files and working directory when running {{book.project.name}} in <>. + +_modules/_:: + These are all the Java libraries used by the server. + +_providers/_:: + If you are writing extensions to keycloak, you can put your extensions here. See the link:http://not-implemented-yet[Server Developer Guide] for more information on this. + +_standalone/_:: + This contains configuration files and working directory when running {{book.project.name}} in <>. + +_themes/_:: + This directory contains all the html, style sheets, javascript files, and images used to display any UI screen displayed by the server. + Here you can modify an existing theme or create your own. See the link:http://not-implemented-yet[Server Developer Guide] for more information on this. + + + + + -.Distribution Directory Structure4 -{% if book.product %} -. image:fake/../../rhsso-images/files.png[alt="distribution"] -{% else %} -image:fake/../../keycloak-images/files.png[alt="distribution"] -{% endif %} From eeefce31e140237eb1ebd9f8ebde0a9e7dabb080 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 09:03:05 -0400 Subject: [PATCH 042/149] more --- README.adoc | 4 ++-- topics/installation/directory-structure.adoc | 4 ++-- topics/preface.adoc | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.adoc b/README.adoc index ef17956cad..7dc043c74a 100755 --- a/README.adoc +++ b/README.adoc @@ -1,10 +1,10 @@ -Keycloak Server Installation and Configuration Guide +{{book.project.name}} Server Installation and Configuration Guide ====================== image:images/keycloak_logo.png[alt="Keycloak"] -*Keycloak* _Documentation_ for {{book.versions.swarm}} +*{{book.project.name}}* _Documentation_ for {{book.project.version}} http://www.keycloak.org diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 94f09a1a10..99b074bffa 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -15,7 +15,7 @@ _bin/_:: This contains various scripts to either boot the server or perform some other management action on the server. _domain/_:: - This contains configuration files and working directory when running {{book.project.name}} in <>. + This contains configuration files and working directory when running {{book.project.name}} in <>. _modules/_:: These are all the Java libraries used by the server. @@ -24,7 +24,7 @@ _providers/_:: If you are writing extensions to keycloak, you can put your extensions here. See the link:http://not-implemented-yet[Server Developer Guide] for more information on this. _standalone/_:: - This contains configuration files and working directory when running {{book.project.name}} in <>. + This contains configuration files and working directory when running {{book.project.name}} in <>. _themes/_:: This directory contains all the html, style sheets, javascript files, and images used to display any UI screen displayed by the server. diff --git a/topics/preface.adoc b/topics/preface.adoc index 3a0cd073cb..f8329fe951 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,3 +1,4 @@ +:test: yes = Preface @@ -16,5 +17,7 @@ Is really: ---- Let's pretend to have an extremely long line that does not fit This one is short ----- +---- + +Are attributes supported? {test} From 623280844442602b593d221ad8a576696813941d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 09:12:51 -0400 Subject: [PATCH 043/149] more --- document-attributes.adoc | 3 +++ topics/preface.adoc | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100755 document-attributes.adoc diff --git a/document-attributes.adoc b/document-attributes.adoc new file mode 100755 index 0000000000..2b5779488a --- /dev/null +++ b/document-attributes.adoc @@ -0,0 +1,3 @@ +:attributes: yes + +Include worked! diff --git a/topics/preface.adoc b/topics/preface.adoc index f8329fe951..09e1b44343 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,4 +1,4 @@ -:test: yes +include::document-attributes.adoc[] = Preface @@ -19,5 +19,5 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Are attributes supported? {test} +Are attributes supported? {attributes} From 75e6ae0f1341fb1a20e14d470b6ffd8bc64e6cff Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 09:14:17 -0400 Subject: [PATCH 044/149] more --- topics/preface.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/preface.adoc b/topics/preface.adoc index 09e1b44343..b35331f602 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,4 +1,4 @@ -include::document-attributes.adoc[] +include::../document-attributes.adoc[] = Preface From 77f0eee7e904cf02f67c9d1aa869efff253158d8 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 09:38:53 -0400 Subject: [PATCH 045/149] more --- topics/preface.adoc | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/topics/preface.adoc b/topics/preface.adoc index b35331f602..ce57e049b7 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,4 +1,4 @@ -include::../document-attributes.adoc[] +:community: true = Preface @@ -19,5 +19,20 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Are attributes supported? {attributes} +Are ifdefs supported? + +ifdef::product[] + +product should not be here + +endif::product[] + +ifdef::community[] + +community should be here + +endif::community[] + + + From 32186bd07a95a65b5f749b6cddd2a4d6251fd60a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 09:57:30 -0400 Subject: [PATCH 046/149] more --- topics/preface.adoc | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/topics/preface.adoc b/topics/preface.adoc index ce57e049b7..302e9b41a0 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,4 +1,3 @@ -:community: true = Preface @@ -19,20 +18,6 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Are ifdefs supported? - -ifdef::product[] - -product should not be here - -endif::product[] - -ifdef::community[] - -community should be here - -endif::community[] - - +Attributes from book.json? {book.project.name} From e78628282a02f15b1c0dc4172c6f0174cbd3f6b3 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 10:26:04 -0400 Subject: [PATCH 047/149] more --- topics/cache.adoc | 8 ++++---- topics/clustering.adoc | 9 +++++---- topics/installation.adoc | 2 +- topics/installation/directory-structure.adoc | 2 +- .../installation/distribution-files-community.adoc | 2 +- .../installation/distribution-files-product.adoc | 2 +- topics/installation/system-requirements.adoc | 2 +- topics/openshift.adoc | 8 ++++---- topics/overview.adoc | 2 +- topics/preface.adoc | 3 +-- topics/proxy.adoc | 14 +++++++------- 11 files changed, 27 insertions(+), 27 deletions(-) diff --git a/topics/cache.adoc b/topics/cache.adoc index 02326fb3fc..c4e0293594 100755 --- a/topics/cache.adoc +++ b/topics/cache.adoc @@ -1,10 +1,10 @@ -= Server Cache +== Server Cache By default, Keycloak caches realm metadata and users. There are two separate caches, one for realm metadata (realm, application, client, roles, etc...) and one for users. These caches greatly improves the performance of the server. -== Eviction and Expiration +=== Eviction and Expiration By default the user cache contains a maximum of 10000 entries. This is not 10000 users, but 10000 entries in the cache. @@ -12,7 +12,7 @@ You can change the maximum number of entries by editing the server configuration Locate the element `cache-container name="keycloak"` and change the eviction policy for the `users` cache. For more information see https://docs.jboss.org/author/display/WFLY10/Infinispan+Subsystem[Infinispan Subsystem documentation]. -== Disabling Caches +=== Disabling Caches To disable the realm or user cache, you must edit the `keycloak-server.json` file in your distribution. Here's what the config looks like initially. @@ -51,7 +51,7 @@ To disable the cache set the enabled field to false for the cache you want to di }, ---- -== Clear Caches +=== Clear Caches To clear the realm or user cache, go to the Keycloak admin console Realm Settings->Cache Config page. On this page you can clear the realm cache or the user cache. diff --git a/topics/clustering.adoc b/topics/clustering.adoc index 2f644235dd..495b596536 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -1,4 +1,5 @@ [[_clustering]] +== Clustering Keycloak doesn't replicate realms and users, but instead relies on all nodes using the same database. This can be a relational database or Mongo. @@ -24,7 +25,7 @@ Typically you won't need to increase/decrease the default value, but just in cas ---- or similarly if you're using Mongo (just by replace `jpa` with `mongo`) -== Configure Infinispan +=== Configure Infinispan Keycloak uses http://www.infinispan.org/[Infinispan] caches to share information between nodes. @@ -56,7 +57,7 @@ For non-cluster configuration (server executed with `standalone.xml` ) is the in For cluster configuration, you can edit the configuration of `infinispan/Keycloak` container in `standalone/configuration/standalone-ha.xml` (or `standalone-keycloak-ha.xml` if you are using overlay or demo distribution) . -== Start in HA mode +=== Start in HA mode To start the server in HA mode, start it with: @@ -73,7 +74,7 @@ or if you are using overlay or demo distribution with: Alternatively you can copy `standalone/config/standalone-ha.xml` to `standalone/config/standalone.xml` to make it the default server config. -== Enabling cluster security +=== Enabling cluster security By default there's nothing to prevent unauthorized nodes from joining the cluster and sending potentially malicious messages to the cluster. However, as there's no sensitive data sent there's not much that can be achieved. @@ -133,7 +134,7 @@ Copy this keystore to all nodes (for example to standalone/configuration). Then ---- See the http://www.jgroups.org/manual/index.html#ENCRYPT[JGroups manual] for more details. -== Troubleshooting +=== Troubleshooting Note that when you run cluster, you should see message similar to this in the log of both cluster nodes: diff --git a/topics/installation.adoc b/topics/installation.adoc index 97769fdf49..a2f982f931 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -1,4 +1,4 @@ -= Installation +== Installation This chapter reviews what binaries you need to install to run the {{book.project.name}} Server on a specific machine. It describes the directory structure and files of the distribution. Finally, it describes how to install {{book.project.name}} diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 99b074bffa..8185828180 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -1,4 +1,4 @@ -= Distribution Directory Structure +=== Distribution Directory Structure This chapter walks you through the directory structure of the server distribution. diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 5fe3b8a7d3..34d2976175 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -1,4 +1,4 @@ -= Installing Distribution Files +=== Installing Distribution Files The Keycloak Server has three downloadable distributions: diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc index 8608a574d8..c81e06ccff 100755 --- a/topics/installation/distribution-files-product.adoc +++ b/topics/installation/distribution-files-product.adoc @@ -1,4 +1,4 @@ -= Installing Distribution Files +=== Installing Distribution Files The Keycloak Server is contained in one distribution file: diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 18c9abdcfd..bc3260f08e 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -1,4 +1,4 @@ -= System Requirements +=== System Requirements These are the requirements to run the {{book.project.name}} authentication server: diff --git a/topics/openshift.adoc b/topics/openshift.adoc index 690fc8b675..3213e02a42 100755 --- a/topics/openshift.adoc +++ b/topics/openshift.adoc @@ -1,6 +1,6 @@ [[_openshift]] -= Running Keycloak Server on OpenShift +== Running Keycloak Server on OpenShift Keycloak provides a OpenShift cartridge to make it easy to get it running on OpenShift. If you don't already have an account or don't know how to create applications go to https://www.openshift.com/ first. @@ -9,7 +9,7 @@ You can create the Keycloak instance either with the web tool or the command lin WARNING: It's important that immediately after creating a Keycloak instance you open the `Administration Console` and login to reset the password. If this is not done anyone can easily gain admin rights to your Keycloak instance. -== Create Keycloak instance with the web tool +=== Create Keycloak instance with the web tool . Open https://openshift.redhat.com/app/console/applications and click on `Add Application`. . Scroll down to the bottom of the page to find the `Code Anything` section. @@ -19,7 +19,7 @@ If this is not done anyone can easily gain admin rights to your Keycloak instanc . Under the list of applications you should find your Keycloak instance and the status should be `Started`. . Click on it to open the Keycloak servers homepage. -== Create Keycloak instance with the command-line tool +=== Create Keycloak instance with the command-line tool . Run the following command from a terminal: @@ -33,7 +33,7 @@ rhc app create http://cartreflect-claytondev.rhcloud.com/gith Once the instance is created the rhc tool outputs details about it. Open the returned `URL` in a browser to open the Keycloak servers homepage. -== Next steps +=== Next steps The Keycloak servers homepage shows the Keycloak logo and `Welcome to Keycloak`. There is also a link to the `Administration Console`. diff --git a/topics/overview.adoc b/topics/overview.adoc index 87ab32f51e..82e921621c 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -1,4 +1,4 @@ -= Guide Overview +== Guide Overview The purpose of this guide is to walk through the steps that need to be completed prior to booting up the {{book.project.name}} server for the first time. If you just want to test drive {{book.project.name}}, it pretty much runs out of the box with its diff --git a/topics/preface.adoc b/topics/preface.adoc index 302e9b41a0..5d4804787f 100755 --- a/topics/preface.adoc +++ b/topics/preface.adoc @@ -1,5 +1,5 @@ -= Preface +== Preface In some of the example listings, what is meant to be displayed on one line does not fit inside the available page width.These lines have been broken up. A '\' at the end of a line means that a break has been introduced to fit in the page, with the following lines indented. So: @@ -18,6 +18,5 @@ Let's pretend to have an extremely long line that does not fit This one is short ---- -Attributes from book.json? {book.project.name} diff --git a/topics/proxy.adoc b/topics/proxy.adoc index fc82e140af..9135b8f5f8 100755 --- a/topics/proxy.adoc +++ b/topics/proxy.adoc @@ -1,11 +1,11 @@ [[_proxy]] -= Keycloak Security Proxy +== Keycloak Security Proxy Keycloak has an HTTP(S) proxy that you can put in front of web applications and services where it is not possible to install the keycloak adapter. You can set up URL filters so that certain URLs are secured either by browser login and/or bearer token authentication. You can also define role constraints for URL patterns within your applications. -== Proxy Install and Run +=== Proxy Install and Run Download the keycloak proxy distribution from the Keycloak download pages and unzip it. [source] @@ -23,7 +23,7 @@ $ java -jar bin/launcher.jar [your-config.json] If you do not specify a path to the proxy config file, the launcher will look in the current working directory for the file named `proxy.json` -== Proxy Configuration +=== Proxy Configuration Here's an example configuration file. [source] @@ -81,7 +81,7 @@ Here's an example configuration file. } ---- -=== Basic Config +==== Basic Config The basic configuration options for the server are as follows: @@ -147,7 +147,7 @@ adapter-config:: Same configuration as any other keycloak adapter. See <<_adapter_config,Adapter Config>> -==== Constraint Config +===== Constraint Config Next under each application you can define one or more constraints in the `constraints` array attribute. A constraint defines a URL pattern relative to the base-path. @@ -182,7 +182,7 @@ permit-and-inject:: authenticate:: Require authentication for this pattern, but no role mapping. _OPTIONAL._. -=== Header Names Config +==== Header Names Config Next under the list of applications you can override the defaults for the names of the header fields injected by the proxy (see Keycloak Identity Headers). This mapping is optional. @@ -206,7 +206,7 @@ keycloak-access-token:: e.g. MYAPP_ACCESS_TOKEN -== Keycloak Identity Headers +=== Keycloak Identity Headers When forwarding requests to the proxied server, Keycloak Proxy will set some additional headers with values from the OIDC identity token it received for authentication. From 9515deaeabe9a01779aaef996a26fdaa0f1bd37b Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 11:15:52 -0400 Subject: [PATCH 048/149] more --- SUMMARY.adoc | 2 ++ book.json | 4 ++++ topics/clustering.adoc | 1 + topics/deployment-mode.adoc | 6 ++++++ topics/deployment-mode/standalone.adoc | 20 ++++++++++++++++++++ topics/installation/directory-structure.adoc | 3 ++- topics/installation/system-requirements.adoc | 2 +- 7 files changed, 36 insertions(+), 2 deletions(-) create mode 100755 topics/deployment-mode.adoc create mode 100755 topics/deployment-mode/standalone.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 2dba1058d3..b59b1656b0 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -12,6 +12,8 @@ {% endif %} .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] + . link:topics/deployment-mode.adoc[Choosing a Deployment Mode] + .. link:topics/deployment-mode/standalone.adoc[Standalone Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/proxy.adoc[Keycloak Security Proxy] diff --git a/book.json b/book.json index 3c205f04f5..5184921b31 100755 --- a/book.json +++ b/book.json @@ -12,6 +12,10 @@ "community": true, "product": false, "images": "rhsso-images", + "appserver": { + "name": "Wildfly", + "version": "10.0.0.Final" + }, "project": { "name": "Keycloak", "version": "1.9.3.Final-SNAPSHOT" diff --git a/topics/clustering.adoc b/topics/clustering.adoc index 495b596536..c430f17040 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -5,6 +5,7 @@ Keycloak doesn't replicate realms and users, but instead relies on all nodes usi This can be a relational database or Mongo. To make sure your database doesn't become a single point of failure you may also want to deploy your database to a cluster. +[[_clustering_db_lock]] === DB lock Note that Keycloak supports concurrent startup by more cluster nodes at the same. diff --git a/topics/deployment-mode.adoc b/topics/deployment-mode.adoc new file mode 100755 index 0000000000..d836d70938 --- /dev/null +++ b/topics/deployment-mode.adoc @@ -0,0 +1,6 @@ +== Choosing a Deployment Mode + +Before deploying {{book.project.name}} in a production environment you need to decide which type of deployment method +you are going to use. Will you run {{book.project.name}} within a cluster? Do you want a centralized way to manage +your server configurations? This is where deciding the deployment mode comes in. This decision + effects how you configure databases, configure caching and even how you boot the server. \ No newline at end of file diff --git a/topics/deployment-mode/standalone.adoc b/topics/deployment-mode/standalone.adoc new file mode 100755 index 0000000000..391c36e24c --- /dev/null +++ b/topics/deployment-mode/standalone.adoc @@ -0,0 +1,20 @@ +=== Standalone Mode + +Standalone mode is only useful when you want to run one, and only one {{book.project.name}} server instance. Standalone +instances contain all the configuration files they need locally. What this basically means is that any configuration done +must be done on the config files contained in the installed distribution on the machine the {{book.project.name}} is going to run on +{{book.project.name}} standalone mode is available pre-configured out of the box. It turns off clustering entirely +and turns any distributed caches into local-only ones. + +==== Standalone Boot Script + +When running the server in standalone mode, there is a specific script you need to run to boot the server depending on your +operating system. These scripts live in the _bin/_ directory of the server distribution. + +.Standalone Boot Scripts +{% if book.product %} +. image:../../rhsso-images/standalone-boot-files.png[alt="distribution"] +{% endif %} +{% if book.community %} +image:../../keycloak-images/standalone-boot-files.png[alt="distribution"] +{% endif %} diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 8185828180..01cc684c63 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -5,7 +5,8 @@ This chapter walks you through the directory structure of the server distributio .distribution directory structure {% if book.product %} . image:../../rhsso-images/files.png[alt="distribution"] -{% else %} +{% endif %} +{% if book.community %} image:../../keycloak-images/files.png[alt="distribution"] {% endif %} diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index bc3260f08e..05242d261b 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -10,4 +10,4 @@ These are the requirements to run the {{book.project.name}} authentication serve * At least 1G of diskspace {{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <> section of this guide for more information. \ No newline at end of file +the <> section of this guide for more information. \ No newline at end of file From 28a0e609297e07fdfe790f23587ce12020dca50a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 11:23:27 -0400 Subject: [PATCH 049/149] more --- book.json | 6 ++++-- topics/deployment-mode.adoc | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/book.json b/book.json index 5184921b31..67fbccc5ac 100755 --- a/book.json +++ b/book.json @@ -13,8 +13,10 @@ "product": false, "images": "rhsso-images", "appserver": { - "name": "Wildfly", - "version": "10.0.0.Final" + "name": "JBoss EAP", + "version": "6.4", + "admindoc": "Administration and Configuration Guide", + "admindoclink": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/" }, "project": { "name": "Keycloak", diff --git a/topics/deployment-mode.adoc b/topics/deployment-mode.adoc index d836d70938..c9c92f4a79 100755 --- a/topics/deployment-mode.adoc +++ b/topics/deployment-mode.adoc @@ -3,4 +3,8 @@ Before deploying {{book.project.name}} in a production environment you need to decide which type of deployment method you are going to use. Will you run {{book.project.name}} within a cluster? Do you want a centralized way to manage your server configurations? This is where deciding the deployment mode comes in. This decision - effects how you configure databases, configure caching and even how you boot the server. \ No newline at end of file + effects how you configure databases, configure caching and even how you boot the server. + +TIP: The {{book.project.name}} is built on top of the {{book.appserver.name}} Application Server. This guide will only + go over the basics for deployment within a specific mode. If you want specific information on this, a better place + to go would be the link:{{book.appserver.admindoclink}}[{{book.appserver.admindoc}}] \ No newline at end of file From b8fee79a2e5cf7e33236f3968f23272120b60069 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 11:26:09 -0400 Subject: [PATCH 050/149] more --- topics/deployment-mode/standalone.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/deployment-mode/standalone.adoc b/topics/deployment-mode/standalone.adoc index 391c36e24c..9d0acf3ac2 100755 --- a/topics/deployment-mode/standalone.adoc +++ b/topics/deployment-mode/standalone.adoc @@ -13,7 +13,7 @@ operating system. These scripts live in the _bin/_ directory of the server dist .Standalone Boot Scripts {% if book.product %} -. image:../../rhsso-images/standalone-boot-files.png[alt="distribution"] +image:../../rhsso-images/standalone-boot-files.png[alt="distribution"] {% endif %} {% if book.community %} image:../../keycloak-images/standalone-boot-files.png[alt="distribution"] From 078a61a4e0ab1c94c9d180a547e31120e9412902 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 11:27:18 -0400 Subject: [PATCH 051/149] more --- keycloak-images/standalone-boot-files.png | Bin 0 -> 6609 bytes rhsso-images/standalone-boot-files.png | Bin 0 -> 6260 bytes topics/deployment-mode/standalone.adoc | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100755 keycloak-images/standalone-boot-files.png create mode 100755 rhsso-images/standalone-boot-files.png diff --git a/keycloak-images/standalone-boot-files.png b/keycloak-images/standalone-boot-files.png new file mode 100755 index 0000000000000000000000000000000000000000..549f32755ee658915f9d4fe9175385b36890d869 GIT binary patch literal 6609 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 Date: Thu, 21 Apr 2016 12:36:12 -0400 Subject: [PATCH 052/149] more --- SUMMARY.adoc | 3 +- book.json | 23 +++++- keycloak-images/standalone-config-file.png | Bin 0 -> 9690 bytes .../standalone-json-config-file.png | Bin 0 -> 9523 bytes rhsso-images/standalone-config-file.png | Bin 0 -> 9689 bytes rhsso-images/standalone-json-config-file.png | Bin 0 -> 9426 bytes topics/deployment-mode/standalone.adoc | 20 ----- topics/installation/system-requirements.adoc | 2 +- ...ployment-mode.adoc => operating-mode.adoc} | 8 +- topics/operating-mode/standalone.adoc | 69 ++++++++++++++++++ topics/overview/recommended-reading.adoc | 10 +++ 11 files changed, 107 insertions(+), 28 deletions(-) create mode 100755 keycloak-images/standalone-config-file.png create mode 100755 keycloak-images/standalone-json-config-file.png create mode 100755 rhsso-images/standalone-config-file.png create mode 100755 rhsso-images/standalone-json-config-file.png delete mode 100755 topics/deployment-mode/standalone.adoc rename topics/{deployment-mode.adoc => operating-mode.adoc} (65%) create mode 100755 topics/operating-mode/standalone.adoc create mode 100755 topics/overview/recommended-reading.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index b59b1656b0..64cd39a1f2 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -2,6 +2,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] + . link:topics/overview/recommended-reading.adoc[Recommended Reading] . link:topics/installation.adoc[Installation] .. link:topics/installation/system-requirements.adoc[System Requirements] {% if book.community %} @@ -12,7 +13,7 @@ {% endif %} .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] - . link:topics/deployment-mode.adoc[Choosing a Deployment Mode] + . link:topics/deployment-mode.adoc[Choosing an Operation Mode] .. link:topics/deployment-mode/standalone.adoc[Standalone Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] diff --git a/book.json b/book.json index 67fbccc5ac..bef1d07e2f 100755 --- a/book.json +++ b/book.json @@ -15,8 +15,27 @@ "appserver": { "name": "JBoss EAP", "version": "6.4", - "admindoc": "Administration and Configuration Guide", - "admindoclink": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/" + "admindoc": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/" + } + }, + "caching": { + "name": "JBoss Data Grid", + "version": "???", + "admindoc": { + "name": "JBoss Data Grid Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Data_Grid/6.6/html/Administration_and_Configuration_Guide/index.html" + } + }, + "jpa": { + "name": "Hibernate", + "version": "???", + "admindoc": { + "name": "Hibernate Config", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Development_Guide/sect-Java_Persistence_API_JPA.html#sect-Configuration2" + } + }, "project": { "name": "Keycloak", diff --git a/keycloak-images/standalone-config-file.png b/keycloak-images/standalone-config-file.png new file mode 100755 index 0000000000000000000000000000000000000000..8f43a7f55c33804d085db5ec7c20dbd4a7cbdc67 GIT binary patch literal 9690 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 literal 0 HcmV?d00001 diff --git a/keycloak-images/standalone-json-config-file.png b/keycloak-images/standalone-json-config-file.png new file mode 100755 index 0000000000000000000000000000000000000000..39ea3bfdf29f9fe0e2764474eaa278b52b325b79 GIT binary patch literal 9523 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 literal 0 HcmV?d00001 diff --git a/rhsso-images/standalone-config-file.png b/rhsso-images/standalone-config-file.png new file mode 100755 index 0000000000000000000000000000000000000000..d77a81b82a1c4ec8cd7b2ba5fbf9fd367d2a587b GIT binary patch literal 9689 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 section of this guide for more information. \ No newline at end of file +the <> section of this guide for more information. \ No newline at end of file diff --git a/topics/deployment-mode.adoc b/topics/operating-mode.adoc similarity index 65% rename from topics/deployment-mode.adoc rename to topics/operating-mode.adoc index c9c92f4a79..9d27b3947b 100755 --- a/topics/deployment-mode.adoc +++ b/topics/operating-mode.adoc @@ -1,10 +1,10 @@ -== Choosing a Deployment Mode +== Choosing an Operating Mode -Before deploying {{book.project.name}} in a production environment you need to decide which type of deployment method +Before deploying {{book.project.name}} in a production environment you need to decide which type of operating mode you are going to use. Will you run {{book.project.name}} within a cluster? Do you want a centralized way to manage -your server configurations? This is where deciding the deployment mode comes in. This decision +your server configurations? This is where deciding the operating mode comes in. This decision effects how you configure databases, configure caching and even how you boot the server. TIP: The {{book.project.name}} is built on top of the {{book.appserver.name}} Application Server. This guide will only go over the basics for deployment within a specific mode. If you want specific information on this, a better place - to go would be the link:{{book.appserver.admindoclink}}[{{book.appserver.admindoc}}] \ No newline at end of file + to go would be the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] \ No newline at end of file diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc new file mode 100755 index 0000000000..5e3720c3f7 --- /dev/null +++ b/topics/operating-mode/standalone.adoc @@ -0,0 +1,69 @@ +=== Standalone Mode + +Standalone operating mode is only useful when you want to run one, and only one {{book.project.name}} server instance. Standalone +instances contain all the configuration files they need locally. What this basically means is that any configuration done +must be done on the config files contained in the installed distribution on the machine the {{book.project.name}} is going to run on +{{book.project.name}} standalone mode is available pre-configured out of the box. It turns off clustering entirely +and turns any distributed caches into local-only ones. + +==== Standalone Boot Script + +When running the server in standalone mode, there is a specific script you need to run to boot the server depending on your +operating system. These scripts live in the _bin/_ directory of the server distribution. + +.Standalone Boot Scripts +{% if book.product %} +image:../../rhsso-images/standalone-boot-files.png[] +{% endif %} +{% if book.community %} +image:../../keycloak-images/standalone-boot-files.png[] +{% endif %} + +To boot the server: + +.Linux/Unix +[source] +---- +$ .../bin/standalone.sh +---- + +.Windows +[source] +---- +> ...\bin\standalone.bat +---- + +==== Standalone Configuration + +The bulk of this guide walks you through how to configure infrastructure level aspects of {{book.project.name}}. These +aspects are configured in a configuration file that is specific to the application server that {{book.project.name}} is a +derivative of. In the standalone operation mode, this file lives in _.../standalone/configuration/standalone.xml_. + +.Standalone Config File +{% if book.product %} +image:../../rhsso-images/standalone-config-file.png[] +{% endif %} +{% if book.community %} +image:../../keycloak-images/standalone-config-file.png[] +{% endif %} + +==== Standalone {{book.project.name}} Configuration + +{{book.project.name}} has a json configuration file that is specific to {{book.project.name}} this is located within +_.../standalone/configuration/keycloak.json_. This file is used to configure non-infrastructure level things that are +only applicable to {{book.project.name}} + +.Standalone {{book.project.name}} Config File +{% if book.product %} +image:../../rhsso-images/standalone-json-config-file.png[] +{% endif %} +{% if book.community %} +image:../../keycloak-images/standalone-json-config-file.png[] +{% endif %} + + + + + + + diff --git a/topics/overview/recommended-reading.adoc b/topics/overview/recommended-reading.adoc new file mode 100755 index 0000000000..5e3779988d --- /dev/null +++ b/topics/overview/recommended-reading.adoc @@ -0,0 +1,10 @@ +=== Recommended Additional External Documentation + +{{book.project.name}} is built upon a derivative of the {{book.appserver.name}} Application Server and projects embedded +within {{book.appserver.name}} like {{book.cache.name}} (for caching) and Hibernate (for persistence). This guide only +goes over the basics for infrastructure-level configuration. It is highly recommended that you peruse the documentation +for {{book.appserver.name}} and its sub projects. Here are some links to that documentation: + +* link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] +* link:{{book.cache.admindoc.link}}[{{book.cache.admindoc.name}}] +* link:{{book.jpa.admindoc.link}}[{{book.jpa.admindoc.name}}] \ No newline at end of file From 3de712e9e8777fdd20b4bf59110f4b9932660c7f Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 12:38:09 -0400 Subject: [PATCH 053/149] more --- SUMMARY.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 64cd39a1f2..3b7b83ddb5 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -2,7 +2,7 @@ . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] - . link:topics/overview/recommended-reading.adoc[Recommended Reading] + .. link:topics/overview/recommended-reading.adoc[Recommended Reading] . link:topics/installation.adoc[Installation] .. link:topics/installation/system-requirements.adoc[System Requirements] {% if book.community %} @@ -13,7 +13,7 @@ {% endif %} .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] - . link:topics/deployment-mode.adoc[Choosing an Operation Mode] + . link:topics/operating-mode.adoc[Choosing an Operating Mode] .. link:topics/deployment-mode/standalone.adoc[Standalone Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] From 98a0e22933fcc7616d98d35b262838e84f819e9d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 12:39:15 -0400 Subject: [PATCH 054/149] more --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 3b7b83ddb5..d8f2f088a4 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -14,7 +14,7 @@ .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/operating-mode.adoc[Choosing an Operating Mode] - .. link:topics/deployment-mode/standalone.adoc[Standalone Mode] + .. link:topics/operating-mode/standalone.adoc[Standalone Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/proxy.adoc[Keycloak Security Proxy] From a5cb4146dfd682788915667d38f6584de06a2940 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 12:46:05 -0400 Subject: [PATCH 055/149] more --- topics/operating-mode/standalone.adoc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index 5e3720c3f7..9743caa743 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -40,12 +40,7 @@ aspects are configured in a configuration file that is specific to the applicati derivative of. In the standalone operation mode, this file lives in _.../standalone/configuration/standalone.xml_. .Standalone Config File -{% if book.product %} -image:../../rhsso-images/standalone-config-file.png[] -{% endif %} -{% if book.community %} -image:../../keycloak-images/standalone-config-file.png[] -{% endif %} +image:../../{{book.images}}/standalone-config-file.png[] ==== Standalone {{book.project.name}} Configuration From 4e866200f274a1e97e4bb4d803c2f72346f872b2 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 12:48:50 -0400 Subject: [PATCH 056/149] more --- book.json | 2 +- topics/installation/directory-structure.adoc | 7 +------ topics/operating-mode/standalone.adoc | 7 +------ 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/book.json b/book.json index bef1d07e2f..e0480933da 100755 --- a/book.json +++ b/book.json @@ -11,7 +11,7 @@ "variables": { "community": true, "product": false, - "images": "rhsso-images", + "images": "keycloak-images", "appserver": { "name": "JBoss EAP", "version": "6.4", diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 01cc684c63..1e640f5e51 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -3,12 +3,7 @@ This chapter walks you through the directory structure of the server distribution. .distribution directory structure -{% if book.product %} -. image:../../rhsso-images/files.png[alt="distribution"] -{% endif %} -{% if book.community %} -image:../../keycloak-images/files.png[alt="distribution"] -{% endif %} +image:../../{{book.images}}/files.png[alt="distribution"] Let's examine some of the purposes of each directory diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index 9743caa743..89b5ac0bb8 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -49,12 +49,7 @@ _.../standalone/configuration/keycloak.json_. This file is used to configure no only applicable to {{book.project.name}} .Standalone {{book.project.name}} Config File -{% if book.product %} -image:../../rhsso-images/standalone-json-config-file.png[] -{% endif %} -{% if book.community %} -image:../../keycloak-images/standalone-json-config-file.png[] -{% endif %} +image:../../{{book.images}}/standalone-json-config-file.png[] From fb20935491dfeb10a6eb28a9d498ec35a2f90b4b Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 16:18:15 -0400 Subject: [PATCH 057/149] more --- SUMMARY.adoc | 1 + topics/installation/system-requirements.adoc | 2 +- topics/operating-mode/standalone-ha.adoc | 52 ++++++++++++++++++++ topics/operating-mode/standalone.adoc | 16 +++--- 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100755 topics/operating-mode/standalone-ha.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index d8f2f088a4..0cff7918d0 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -15,6 +15,7 @@ .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/operating-mode.adoc[Choosing an Operating Mode] .. link:topics/operating-mode/standalone.adoc[Standalone Mode] + .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/proxy.adoc[Keycloak Security Proxy] diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 69054b7ee3..6f741396f7 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -10,4 +10,4 @@ These are the requirements to run the {{book.project.name}} authentication serve * At least 1G of diskspace {{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <> section of this guide for more information. \ No newline at end of file +the <> section of this guide for more information. \ No newline at end of file diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc new file mode 100755 index 0000000000..dad7f8e588 --- /dev/null +++ b/topics/operating-mode/standalone-ha.adoc @@ -0,0 +1,52 @@ +=== Standalone Clustered + +Standalone clustered operation mode is for when you want to run {{book.project.name}} within a cluster. This mode +requires that you have a copy of each distribution for each node you want to run in the cluster. While very easy to +deploy initially, this mode can become cumbersome if you end up having a large cluster because you will have to +modify the configuration in each node anytime you need to make a change. + +==== Standalone Clustered Configuration + +The distribution has a pre-configured app server configuration file for running within a cluster. It has all the specific +infrasture settings you need for the clustered caches and discovery that {{book.project.name}} needs. This file resides +in _.../standalone/configuration/standalone-ha.xml_ + +.Standalone HA Config +image:../../{{book.images}}/standalone-ha-config-file.png[] + +NOTE: Any changes you make to this file while the server is running will not take effect and may even be overwritten + by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See + the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. + +==== Standalone Boot Script + +You use the same boot scripts to start {{book.project.name}} as you do in standalone mode. The difference is that +you pass in an additional flag to point to the HA config file. + +.Standalone Clustered Boot Scripts +image:../../{{book.images}}/standalone-boot-files.png[] + +To boot the server: + +.Linux/Unix +[source] +---- +$ .../bin/standalone.sh --server-config=standalone-ha.xml +---- + +.Windows +[source] +---- +> ...\bin\standalone.bat --server-config=standalone-ha.xml +---- + +==== Standalone Clustered{{book.project.name}} Configuration + +The {{book.project.name}} specific json configure file resides in the same place as in standalone mode: _.../standalone/configuration/keycloak.json_. +Like _standalone-ha.xml_ you have to modify this file in each distribution in your cluster in order for changes to take effect. + +NOTE: Any changes you make to this file while the server is running will not take effect. You'll need to reboot the + server. + + + diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index 89b5ac0bb8..4444bcd68f 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -1,3 +1,4 @@ +[[_standalone-mode]] === Standalone Mode Standalone operating mode is only useful when you want to run one, and only one {{book.project.name}} server instance. Standalone @@ -12,12 +13,7 @@ When running the server in standalone mode, there is a specific script you need operating system. These scripts live in the _bin/_ directory of the server distribution. .Standalone Boot Scripts -{% if book.product %} -image:../../rhsso-images/standalone-boot-files.png[] -{% endif %} -{% if book.community %} -image:../../keycloak-images/standalone-boot-files.png[] -{% endif %} +image:../../{{book.images}}/standalone-boot-files.png[] To boot the server: @@ -42,6 +38,11 @@ derivative of. In the standalone operation mode, this file lives in _.../standa .Standalone Config File image:../../{{book.images}}/standalone-config-file.png[] +NOTE: Any changes you make to this file while the server is running will not take effect and may even be overwritten + by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See + the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. + + ==== Standalone {{book.project.name}} Configuration {{book.project.name}} has a json configuration file that is specific to {{book.project.name}} this is located within @@ -51,6 +52,9 @@ only applicable to {{book.project.name}} .Standalone {{book.project.name}} Config File image:../../{{book.images}}/standalone-json-config-file.png[] +NOTE: Any changes you make to this file while the server is running will not take effect. You'll need to reboot the + server. + From 1604b5ee62053ec539564f9d595b8b984bc94a1f Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 21 Apr 2016 16:18:30 -0400 Subject: [PATCH 058/149] more --- keycloak-images/standalone-ha-config-file.png | Bin 0 -> 9506 bytes rhsso-images/standalone-ha-config-file.png | Bin 0 -> 9596 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100755 keycloak-images/standalone-ha-config-file.png create mode 100755 rhsso-images/standalone-ha-config-file.png diff --git a/keycloak-images/standalone-ha-config-file.png b/keycloak-images/standalone-ha-config-file.png new file mode 100755 index 0000000000000000000000000000000000000000..e7694e379c2cbefd9953cff63e75e667a3cdfbba GIT binary patch literal 9506 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 AYXATM literal 0 HcmV?d00001 diff --git a/rhsso-images/standalone-ha-config-file.png b/rhsso-images/standalone-ha-config-file.png new file mode 100755 index 0000000000000000000000000000000000000000..fa6a0b0900903847c970fabc44d5a4e9516b1262 GIT binary patch literal 9596 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 literal 0 HcmV?d00001 From 1df5c08a3612b3aebfa90c782b573e3bd1079408 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Apr 2016 16:02:59 -0400 Subject: [PATCH 059/149] more --- SUMMARY.adoc | 2 + images/domain.png | Bin 0 -> 69245 bytes keycloak-images/domain-boot-files.png | Bin 0 -> 6233 bytes keycloak-images/domain-file.png | Bin 0 -> 8746 bytes keycloak-images/host-files.png | Bin 0 -> 9027 bytes rhsso-images/domain-boot-files.png | Bin 0 -> 5941 bytes rhsso-images/domain-file.png | Bin 0 -> 8964 bytes rhsso-images/host-files.png | Bin 0 -> 8933 bytes topics/installation/system-requirements.adoc | 8 +- topics/operating-mode/domain-example.adoc | 6 + topics/operating-mode/domain.adoc | 126 +++++++++++++++++++ topics/operating-mode/standalone-ha.adoc | 13 +- topics/operating-mode/standalone.adoc | 9 +- topics/overview.adoc | 4 + 14 files changed, 156 insertions(+), 12 deletions(-) create mode 100755 images/domain.png create mode 100755 keycloak-images/domain-boot-files.png create mode 100755 keycloak-images/domain-file.png create mode 100755 keycloak-images/host-files.png create mode 100755 rhsso-images/domain-boot-files.png create mode 100755 rhsso-images/domain-file.png create mode 100755 rhsso-images/host-files.png create mode 100755 topics/operating-mode/domain-example.adoc create mode 100755 topics/operating-mode/domain.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 0cff7918d0..6c3b58982a 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -16,6 +16,8 @@ . link:topics/operating-mode.adoc[Choosing an Operating Mode] .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] + .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] + .. link:topics/operating-mode/domain-example.adoc[Domain Clustered Mode] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/proxy.adoc[Keycloak Security Proxy] diff --git a/images/domain.png b/images/domain.png new file mode 100755 index 0000000000000000000000000000000000000000..6a751437d0b16352442c4410f4342fb343f12e7f GIT binary patch literal 69245 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

  • R+l0)1Zn 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%0AmN9hl8sCd<+86sWLJ$o|~D`eERh1 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 literal 0 HcmV?d00001 diff --git a/keycloak-images/domain-boot-files.png b/keycloak-images/domain-boot-files.png new file mode 100755 index 0000000000000000000000000000000000000000..0b6b33415c3d0474d0163519bb2c4cc8b1f38f81 GIT binary patch literal 6233 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 r2@q t%=0u-!C{~4B5XqLA6})g+~bHXB{BDD>VxNs!2dfy2G@-BP&&{@{}1`#8U+9V literal 0 HcmV?d00001 diff --git a/keycloak-images/host-files.png b/keycloak-images/host-files.png new file mode 100755 index 0000000000000000000000000000000000000000..dbab3fa68b894c3462dfbf02e2edd9f6e3387122 GIT binary patch literal 9027 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 G4*4HByS*_0 literal 0 HcmV?d00001 diff --git a/rhsso-images/domain-file.png b/rhsso-images/domain-file.png new file mode 100755 index 0000000000000000000000000000000000000000..f8e6f482217050602b81ef9aef31a013a657baa9 GIT binary patch literal 8964 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 literal 0 HcmV?d00001 diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 6f741396f7..49b2a3f1ef 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -5,9 +5,11 @@ These are the requirements to run the {{book.project.name}} authentication serve * Can run on any operating system that runs Java * Java 8 JDK * zip or gzip and tar -* Network multicast support if you are clustering {{book.project.name}}. * At least 512M of RAM * At least 1G of diskspace +* Network multicast support on your machine if you want to run in a cluster out of the box. {{book.project.name}} can + be clustered without multicast, but this requires a bunch of configuration changes. Please see + the <> section of this guide for more information. +* A shared external database like Postgres, MySql, Oracle, etc. {{book.project.name}} requires an external shared + database if you want to run in a cluster. Please see the <> section of this guide for more information. -{{book.project.name}} can be clustered without multicast, but this requires a bunch of configuration changes. Please see -the <> section of this guide for more information. \ No newline at end of file diff --git a/topics/operating-mode/domain-example.adoc b/topics/operating-mode/domain-example.adoc new file mode 100755 index 0000000000..50148ef67a --- /dev/null +++ b/topics/operating-mode/domain-example.adoc @@ -0,0 +1,6 @@ +== Domain Mode Example Walkthrough + +As noted in the <> chapter, {{book.project.name}} comes with a mostly pre-configured clustered domain +setup. This chapter walks you through this out of the box configuration highlighting each aspect of each configuration +file you need to touch and manage. At the end, the chapter discusses what changes you'll need to make to this out of the +box configuration to have it work in a real cluster. \ No newline at end of file diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc new file mode 100755 index 0000000000..93e0a612fa --- /dev/null +++ b/topics/operating-mode/domain.adoc @@ -0,0 +1,126 @@ +[[_domain-mode]] +=== Domain Clustered Mode + +Running a cluster in standard mode can quickly become aggravating as the cluster grows in size. Every time you need +to make a configuration change, you have perform it on each node in the cluster. Domain mode solves this problem by providing +a central place to store and publish configuration. It can be quite complex to set up, but it is worth it in the end. +This capability is built into the {{book.appserver.name}} Application Server which {{book.project.name}} derives from. + +NOTE: The guide will go over the very basics of domain mode. Detailed steps on how to set up domain mode in a cluster should be obtained from the + link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}]. + +Here are some of the basic concepts of running in domain mode. + +domain controller:: + The domain controller is a process that is responsible for storing, managing, and publishing the general configuration + for each node in the cluster. This process is the central point from which nodes in a cluster obtain their configuration. + +host controller:: + The host controller is responsible for managing server instances on a specific machine. You configure it to run + one or more server instances. The domain controller can also interact with the host controllers on each machine to + manage the cluster. To reduce the number of running process, a domain controller also acts as a host controller on + the machine it runs on. + +domain profile:: + A domain profile is a named set of configuration that can be used by a server to boot from. A domain controller + can define multiple domain profiles that are consumed by different servers. + +server group:: + A server group is a collection of servers. They are managed and configured as one. You can assign a domain profile to a server group and every service in that + group will use that domain profile as their configuration. + +In domain mode, a domain controller is started on a master node. The configuration for the cluster resides in the domain controller. +Next a host controller is started on each machine in the cluster. Each host controller deployment configuration specifies how +many {{book.project.name}} server instances will be started on that machine. When the host controller boots up, it starts +as many {{book.project.name}} server instances as it was configured to do. These server instances pull their configuration +from the domain controller. + +==== Domain Configuration + +Various other chapters in this guide walk you through configuring various aspects like databases, +HTTP network connections, caches, and other infrastructure related things. While standalone mode uses the _standalone.xml_ file to configure these things, +domain mode uses the _.../domain/domain.xml_ configuration file. This is +where the domain profile and server group for the {{book.project.name}} server are defined. + +{{book.project.name}} does come with a pre-configured _domain.xml_ file. While it will work almost out of the box, there is some tweaks you need +to make to it for it to be able to manage a real cluster. The <<_example_domain,example domain>> section of this chapter walks through each +aspect of this pre-configured _domain.xml_ file. + +.domain.xml +image:../../{{book.images}}/domain-file.png[] + +The default +profile+ XML block is where you are going to make the bulk of your configuration decisions. You can edit this file +directly prior to booting the domain controller, but you should use the {{book.appserver.name}} web console or command line interface +to modify it at runtime. + +.profile +[source,xml] +---- + + + ... + +---- + +The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile +that is used (+default+) and also so default boot arguments for the Java VM when the host controller boots an instance. + +.server group +[source,xml] +---- + + + + + + + + +---- + +NOTE: Any changes you make to this file while the domain controller is running will not take effect and may even be overwritten + by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See + the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. + +==== Host Controller Configuration + +{{book.project.name}} comes with two host controller configuration files that reside in the _.../domain/configuration/_ directory: +_host-master.xml_ and _host-slave.xml_. _host-master.xml_ is configured to boot up a domain controller, a load balancer, and +one {{book.project.name}} server instance. _host-slave.xml_ is configured to talk to the domain controller and boot up +one {{book.project.name}} server instance. + +.Host Controller Config +image:../../{{book.images}}/host-files.png[] + +==== Domain Boot Script + +When running the server in domain mode, there is a specific script you need to run to boot the server depending on your +operating system. These scripts live in the _bin/_ directory of the server distribution. + +.Standalone Boot Scripts +image:../../{{book.images}}/domain-boot-files.png[] + +To boot the server: + +.Linux/Unix +[source] +---- +$ .../bin/domain.sh --host-config=host-master.xml +---- + +.Windows +[source] +---- +> ...\bin\domain.bat --host-config=host-slave.xml +---- + +When running the boot script you will need pass in the host controlling configuration file you are going to use via the ++--host-config+ switch. + + + + + + + + diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc index dad7f8e588..d3f5607db6 100755 --- a/topics/operating-mode/standalone-ha.adoc +++ b/topics/operating-mode/standalone-ha.adoc @@ -1,4 +1,6 @@ -=== Standalone Clustered +[[_standalone-ha-mode]] + +=== Standalone Clustered Mode Standalone clustered operation mode is for when you want to run {{book.project.name}} within a cluster. This mode requires that you have a copy of each distribution for each node you want to run in the cluster. While very easy to @@ -7,9 +9,12 @@ modify the configuration in each node anytime you need to make a change. ==== Standalone Clustered Configuration -The distribution has a pre-configured app server configuration file for running within a cluster. It has all the specific -infrasture settings you need for the clustered caches and discovery that {{book.project.name}} needs. This file resides -in _.../standalone/configuration/standalone-ha.xml_ +The distribution has a mostly pre-configured app server configuration file for running within a cluster. It has all the specific +infrasture settings you need to configure networking, databases, caches, and discovery. This file resides +in _.../standalone/configuration/standalone-ha.xml_. There's a few things missing from this configuration. +You can't run {{book.project.name}} in a cluster without a configuring a shared database connection. You also need to +deploy some type of load balancer in front of the cluster. The <> and +<> sections of this guide walk you though these things. .Standalone HA Config image:../../{{book.images}}/standalone-ha-config-file.png[] diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index 4444bcd68f..986b879d5b 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -1,11 +1,10 @@ [[_standalone-mode]] === Standalone Mode -Standalone operating mode is only useful when you want to run one, and only one {{book.project.name}} server instance. Standalone -instances contain all the configuration files they need locally. What this basically means is that any configuration done -must be done on the config files contained in the installed distribution on the machine the {{book.project.name}} is going to run on -{{book.project.name}} standalone mode is available pre-configured out of the box. It turns off clustering entirely -and turns any distributed caches into local-only ones. +Standalone operating mode is only useful when you want to run one, and only one {{book.project.name}} server instance. +It cannot be made to run in a cluster and all caches are non-distributed and local-only. It is not recommended that +you use standalone mode in production as you will have a single point of failure. If your standalone mode server goes down, +users will not be able to log in. This mode is really only useful to test drive and play with the features of {{book.project.name}} ==== Standalone Boot Script diff --git a/topics/overview.adoc b/topics/overview.adoc index 82e921621c..d6ae0e5945 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -8,3 +8,7 @@ own embedded and local-only database. For and finally set up {{book.project.name}} to run in a cluster. This guide walks through each and every aspect of any pre-boot decisions and setup you must do prior to deploying the server. +One thing to particularly note is that {{book.project.name}} is derived from the {{book.appserver.name}} Application Server. +Many aspects of configuring a {{book.project.name}} revolve around {{book.appserver.name}} configuration elements. Often +this guide will direct you to documentation outside of the manual if you want to dive into more detail. + From 764c2833c414e49ec355f39e2765958ec04413ca Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Apr 2016 16:28:36 -0400 Subject: [PATCH 060/149] more --- SUMMARY.adoc | 7 +++++-- topics/installation/distribution-files-community.adoc | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 6c3b58982a..c826c0e572 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -17,9 +17,12 @@ .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] - .. link:topics/operating-mode/domain-example.adoc[Domain Clustered Mode] + .. link:topics/operating-mode/domain-example.adoc[Domain Mode Example Walkthrough] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] - . link:topics/proxy.adoc[Keycloak Security Proxy] + . link:topics/management.adoc[Managing The Install] +{% if book.community %} +. link:topics/proxy.adoc[Keycloak Security Proxy] +{% endif %} diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 34d2976175..94762043f2 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -7,10 +7,12 @@ The Keycloak Server has three downloadable distributions: * 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' The 'keycloak-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries -to run the Keycloak Server. +to run the Keycloak Server. To unpack this file just run your operating system's +unzip+ or +gunzip+ and +tar+ utilities. The 'keycloak-overlay-{{book.project.version}}.[zip|tar.gz]' file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing -Wildfly or JBoss EAP distribution. We suggest that you do not use this file unless you want to install on top of a JBoss EAP distribution. +Wildfly or JBoss EAP distribution. We suggest that you do not use this file unless you want to install on top of a JBoss EAP distribution. We do not support +users that want to run their applications and Keycloak on the same server instance. To install the Keycloak Service Pack, just unzip it in the root directory +of your JBoss EAP distribution. The 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' contains a the server binaries, all documentation and all examples. It is preconfigured with both the OIDC and SAML client application adapters and can deploy any of the distribution examples out of the box with no configuration. This distribution is only From d87ba6dd156d5cea3a9f657ea22e0a07e4345a10 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Apr 2016 16:30:44 -0400 Subject: [PATCH 061/149] more --- topics/operating-mode/standalone-ha.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc index d3f5607db6..4da47e5819 100755 --- a/topics/operating-mode/standalone-ha.adoc +++ b/topics/operating-mode/standalone-ha.adoc @@ -45,7 +45,7 @@ $ .../bin/standalone.sh --server-config=standalone-ha.xml > ...\bin\standalone.bat --server-config=standalone-ha.xml ---- -==== Standalone Clustered{{book.project.name}} Configuration +==== Standalone Clustered {{book.project.name}} Configuration The {{book.project.name}} specific json configure file resides in the same place as in standalone mode: _.../standalone/configuration/keycloak.json_. Like _standalone-ha.xml_ you have to modify this file in each distribution in your cluster in order for changes to take effect. From 73ebc1bd074cf22a181dd531c233233e85435456 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 22 Apr 2016 16:32:31 -0400 Subject: [PATCH 062/149] more --- topics/operating-mode/domain-example.adoc | 31 ++++++++++++++++++++++- topics/operating-mode/domain.adoc | 29 --------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/topics/operating-mode/domain-example.adoc b/topics/operating-mode/domain-example.adoc index 50148ef67a..a288df10aa 100755 --- a/topics/operating-mode/domain-example.adoc +++ b/topics/operating-mode/domain-example.adoc @@ -3,4 +3,33 @@ As noted in the <> chapter, {{book.project.name}} comes with a mostly pre-configured clustered domain setup. This chapter walks you through this out of the box configuration highlighting each aspect of each configuration file you need to touch and manage. At the end, the chapter discusses what changes you'll need to make to this out of the -box configuration to have it work in a real cluster. \ No newline at end of file +box configuration to have it work in a real cluster. + +The default +profile+ XML block is where you are going to make the bulk of your configuration decisions. You can edit this file +directly prior to booting the domain controller, but you should use the {{book.appserver.name}} web console or command line interface +to modify it at runtime. + +.profile +[source,xml] +---- + + + ... + +---- + +The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile +that is used (+default+) and also so default boot arguments for the Java VM when the host controller boots an instance. + +.server group +[source,xml] +---- + + + + + + + + +---- diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 93e0a612fa..67ebcf5c95 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -49,35 +49,6 @@ aspect of this pre-configured _domain.xml_ file. .domain.xml image:../../{{book.images}}/domain-file.png[] -The default +profile+ XML block is where you are going to make the bulk of your configuration decisions. You can edit this file -directly prior to booting the domain controller, but you should use the {{book.appserver.name}} web console or command line interface -to modify it at runtime. - -.profile -[source,xml] ----- - - - ... - ----- - -The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile -that is used (+default+) and also so default boot arguments for the Java VM when the host controller boots an instance. - -.server group -[source,xml] ----- - - - - - - - - ----- - NOTE: Any changes you make to this file while the domain controller is running will not take effect and may even be overwritten by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. From 3265ae272434ed9bbccf1f212f3fcbc1449fab39 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 23 Apr 2016 20:29:41 -0400 Subject: [PATCH 063/149] more --- SUMMARY.adoc | 3 +- keycloak-images/domain-json-config.png | Bin 0 -> 7353 bytes keycloak-images/domain-server-dir.png | Bin 0 -> 4581 bytes rhsso-images/domain-json-config.png | Bin 0 -> 7309 bytes rhsso-images/domain-server-dir.png | Bin 0 -> 4705 bytes topics/operating-mode/domain-example.adoc | 35 ----- topics/operating-mode/domain.adoc | 183 +++++++++++++++++++++- topics/operating-mode/standalone-ha.adoc | 2 +- topics/operating-mode/standalone.adoc | 2 +- 9 files changed, 183 insertions(+), 42 deletions(-) create mode 100755 keycloak-images/domain-json-config.png create mode 100755 keycloak-images/domain-server-dir.png create mode 100755 rhsso-images/domain-json-config.png create mode 100755 rhsso-images/domain-server-dir.png delete mode 100755 topics/operating-mode/domain-example.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index c826c0e572..7e4200ac59 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -17,10 +17,9 @@ .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] - .. link:topics/operating-mode/domain-example.adoc[Domain Mode Example Walkthrough] . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] - . link:topics/management.adoc[Managing The Install] + . link:topics/management.adoc[Runtime Management] {% if book.community %} . link:topics/proxy.adoc[Keycloak Security Proxy] {% endif %} diff --git a/keycloak-images/domain-json-config.png b/keycloak-images/domain-json-config.png new file mode 100755 index 0000000000000000000000000000000000000000..b14297b889a1ec6b5d211831aff16765c4f6ee57 GIT binary patch literal 7353 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 I)a@ew2f>fs2><{9 literal 0 HcmV?d00001 diff --git a/keycloak-images/domain-server-dir.png b/keycloak-images/domain-server-dir.png new file mode 100755 index 0000000000000000000000000000000000000000..6cf0a395f66f74fc1cb29da13f1fb116dd961dbd GIT binary patch literal 4581 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 literal 0 HcmV?d00001 diff --git a/rhsso-images/domain-json-config.png b/rhsso-images/domain-json-config.png new file mode 100755 index 0000000000000000000000000000000000000000..f174acd9356e2f65452b87e7f305ed6437e47fc6 GIT binary patch literal 7309 zcma)hcU%))w{?Jo-fKWWkgoJzq)L_Eg9r(TpmagHv>;gMy$L8FT@sPrV(1`6nsg9B zdPjQu0zTgRyw82#d%r(s@|!*9H#uj|K5MPL=9Qj~8VMl-Apig%(NI@5006L9Fo!KZ zHYTF<{c9fP2g}_+O$kui%eaiW0NN>PD*^x?qlr$fK$vR+S9LRY0D!dl^1y0$DX;+m z7;k7OD;jxQu4nW(FpdqsID<+}KNqw~HWsHUOKnZBZ|Jy@u7z#J9>z;)YsF_rgHNnO zi&b&E{07y#5poTgcM(C)GwCMoO!aTnS z$sjvrWS}dRd1*q`p!zX*C;7CGJuUWIHYd=;%*>4TM+mQtvTUph2`d$_kI_@%)+|S; zz3TSQUM7eBWEq*EB3pdRF`Y#US7OJQO1OokA!0==^I|sI2+K0Uz>*bbH{{T`@Gog);l$MS&ktx6J zq{N9IEH(a0V4Nt=k)q|Ty{djZF3i6czw+i)ssLaj4j>M!OhFJJjEx3#-~(}3*vN^4 zBK{@dPse+#DGJ(W0N_}A!}UK42~y+oK!k0So*$G=S9}!kE%DoX(7~xo64o^eGLN)% zAIJaJD=SDJ#+t%71VAge&^N%|(a7xdQnO*nw>>^T&=vjscDmw6)Kr~?HM&WtpU^qQ zi}@r9JbVpG2EGxrqRlI95LeA4DM1wE(@BV z9Xm~~>8A??c>7G)$UZGDGa3Y=v`HSM#Pdl}MnqcSf8(@)f2Z>r+8Y0bVA&HOkh7*q zk@;jc#l$Pr21S#)<22wIAS51z=nI*k0ZSl%I^rNjod1}+%VhqtKrSIVsYe9>#4l$F zRI%DW>v6M>HoqW)q5}BvipdLy$%R>o7AoKyDh+`0>=@XJVTM<9bo4~vRtaZW0jrG? ztuzWuhxm~ptpZ|O*gYD|*X5Xii|;51el@>KlxN0Eo1C0HFrsdUE+_{b=p@L<;4PeS z80>Yj&rVxr+nVd%w#sI$y*2tEL>RXQS5T^wEoEWslih%Yt{s}V@md?}L5`8I*_p-{ zD7(F@Va1TaH?bM%Kn_8nO19AuJTiWM{#-=t2D}h%YLuXdH~ZmLEc*$~)RQ&ALDwn) z5ZOU;Q3RghLn63r!0F-H$-%(Kh$y&}MuG7MkBN-CwKYkv1+^cXR%QVWa|>Y6%(A{G z`yX=0`}GCQM;+lGJPg-#qHP9xgp5MBISDJjxSVJRst^)XLU=73pYh-ozy0}`N>~x5 zk>aXGBCTiUcc8&Z&_#4Jm9p(k@T{U`@<>u>{d;sSH#@}cMmU2K=g#3T+`$uq7nOgK9%vbxG@$ael$G;S}%p=YwEx=@MwQ;sbR_IUsI$q|QaE$Ut0x z*=Q6j?Tw#XjFKwTK~Azjicd7H#I`eEO!zu}5@zgb9OF=XWKD2jAMTuzkJpl zGePrr1+bs{^Dw6fiEjekw5(0km8+8k}P0u4OX-?mDv!vFjkOUzZV(+7X2Ta z^zQ-n8Bq9nnpW@`_U9mQCXCvZm^f4kPBRnVjE4{hn&-s8j)#AN4(7LlVK4`3nh5R+ zt`}sOIpmbX(oX%{s-wM)(_O%5t+=gy0#~!d2vV%2UQgiQ{B-=C)pt+(;WfEkE4dB? zqJ-ALBp;d3Wt*Lf-y|P*v)w43AEJnEVsB2>lLFM1fzWr?IzL9i2p^gi;RG3T--OJ{ zN|iHDlXP;(BB~SXq560m4`AAa1SZdPNu8(+cQr|8m_&?L>6o#Qq@lo7EgSti9YDab z@(c(E_Vr&N>F=w(0xnp1;6qP1t{Sngf()X%b z*hkA@fbzWOFw73hHd0Twz)9+CzT8)YvNxESnO_^@cBwNRX54qL_Z`e-b|zD!q-FC%+8N#nYjt;iOH0nN4!}re00pI&E8M4&&NM| zV#+_wt}j!=OV$EZeEzJtm9Jt|+PHPKWc6TWy27H$4b3^o=Jf6RL0*1&oj4K{#`WKb z7X^Qk8b(8JTVOpL%=ZM9ad+Tpx&t#k`*5tD{KHTO9CH}#Z;)q2w4h_Zn4eeT>I5Sq zRz<2sGdK93m>8@tai;1IdI4eOO&quBo{`oHtHYj&AV!Xn^L&ZeRmVoE8 z1bLk`TzFry#q_gPs(Ae7%1E+oD7BJj2~4bYNf%#o5&Pw95YQfAeD z8;XsAn!hk1RV3WcZL5bnK)GD}Nzn~RHXXng0C%#|B{k8KUmt_IagRtQPO`G~69I(& zEF3FHTf`O(7?u80q5oFQbfo-&MFp!o4lsxjha>e3tTToH;F#7(REa_%pxW2}CL{r) zqW*MiJ39smgpWTtC|vVl0e5r(m?_A}$XajWJj8HfDLnNcbM#E?2M~4UAf7Y%;+IMr zIl8VXZq6>Sh@Vuo2LPb)_UojEYV~;Tgif zsCh|QS(*k!7|O{YsbgFE-uk)*%PKG z>uNHDd0*3zOp~vjr5jHV&`qoNOw2j`sz2B9eQq|++ASY~lxD{PM9|tR@{LMc9 zKWWAXYEqqXq+$D!1YtI?Xsm_wcQAwoKZ(AI;xsPNZ=j|DXKZ*4-zLpvf&a;_LLyEnB$9q%WhATkqYf}+K=Y`Xq1I8RUa2j^6rFLd{1t?mb2yA&gHNQJ z#??aX#OIT;M`26hEekD=ly_-`4eVcO@sn&V(A8E&!?dOA^IEqf+?VYaga$s^@C-j% zvZkEET`96{0zxS8lT^P9Ug}EYTwzr!hoRgnN$+j1e3;BL-zQo0EO2= zSJf>yEM@!O%m;|E?*3aNR33{54}Om!qV26My%J%)D;i7jL#h2FVUb3=0Q5Iyk762A z4l=zri3*uE+obEgl2e>3^gK=?yF7x0Bkm)Mi;It*@jI_?7^MHM^n&^j?8<43pyYmF zFbx}YWW3&NQ3g24QF~%gR*I_SJ5|$67o+$*#0X#wf|qQak>+uUMf1 zfP=x{^PBCFb2v@tFTn65P$(D$YZ)7(C-4ji;BV)Hs0lVn-r-# zw*^aGrrv3v@boa#d#Qo1%E-i|QOtBNQ=FAb^nNG99C31EuzMrm`ATH~g=X7}YP4}- zlV?3<{zgFa#E$GR41(nT>1D4Z<^Rx_zXR!9zx${ZUUJ7>WzXfH2ZKPkQ>OX{%oDCD zqKJ2Td+AQgnvatON;ST2MdJn z{lTvK>Hooml^QtcH15VMHAt*g*i93rQObjfLU!${nuS}J7gNr90Izr~m0(zWkc(nvS8~=G==pR)dYd&+hEKh;2 zoEHScS8fY}HH6Q6+se^BXN*+-CC>ucRC-qAx;Z%0{1FWTu39|GDC#5&I6v^qI>(A4 zxrMo(ts|&86uRWDfShhU2=q{*;P4pom^wdf-R`OD+c;zELNFAUek$B8rLWrbKdZ+} zjwQzbmUB3dxUk?^Yk5WVZ7~QYOZcHj0=0+be>Uq9phkkyhI(uYke+|o^}GRGby7ew zgQRk3vJo@qya1AZo~9C0 zyIRr%mF%xkV-aUXS>Qq^t`$PRjjxoxx# zQ$E8rL$hVY!i4V;U)dO4nmG;g!!PI(McRs;#4)o}I=Q18RBJVHoceXaApp0|=X@pO z?3`&hDJnW@T7P>P(J5s0-sJ8e`|t-{lHxZK^iNgGnxSY<6^`k1LZ`g65*a37x^Ilg ztFAh+6Lx*)_>d% zeM21~GHa~D!M}QF3Xz|dse3G%!JkP}A#z!39jjt1ui6mQ$3i@JNo5nbtc_-{;d}hb zIlkH3>mjHNQ)gi|{F60?pC{zxj+9oJ8#{8OiDbLL(U}W6;2joW+^ds#1J*xn8cizy zyEuROXZLW>16Sw*GsbZ06}kX&!Jl9!Cnqa|i4SPQLn8{fE`5b2+Rt2*Btb$%o<2T2 zcSH3oRfh&unelOxgm=_hnw#%@>{6g#cE~M;ZLrnc%)%tSLX(|Q0j~|-G>>?kFg$Lh`xJYKq&(F^u+1Tjpe02rv9tc;CwJB*Z zzkA6W zYz{a)(l3;iL57DpC?T67p#RiJUFj=QJ8aZp?ftrt%7x@eGW=R^j?GzD)#AI?5j6yJ$J?bd!YB7go?9`Ok z|D~R&|5thX+kC?iL*T2t&z3mxAPhBh@H4qOrYRtMs4h(+E4C#%PE1R6!WQ7?qf0Q#YeNBf@Ac-QVzoq4$9f0H8m4JFiK-V+ zrIGuqZ^|nskY2uQn~*Yr)jylq+`$4mL(qvK47DUo_pxp7lF(HRm984mAU>7O6#I>M zPIZCOwW7<-LT1u42R6nzNq`R7hXKr1Dq-|R5D%EN)s+^8W45xJ$&CCy4&s{H68ZBpzUl_HTVg(J6P6RX!LanJ z!dAkX)W)R-!L_j)L9?D^BrKyZpY*xz$5K(_V(jKCigxy&%fC=&Ay37Ivy#)}U^ZcZ zd2_Vfk-I2m{{@CJh_(xx8gv86+HvW~OT6BB6miNQ9?fj}ALB`imt0bcG@4hRF1rs4 z?MpXvF-)M6Fr+`?aWY5OF0m!)e{Ih7bJvk-H3&aD5=E-(3b`gDiu;&^SiXWL(BcK=L50?~NB^nf8y(T8O3 zxXF8Ps-;esoh@HIVGWC?Ud3HNAzn8N5x+ICtgP8(sI(iYOVPw&i3bt z_jt79jjH6tO5CPxzS4J+27)GN61`7um8aU5Z9FA+Tv6;Tq4vz?qb_3Q(eAC@{3#qk zxG|jm;Aa@a;5mi9kH^eKO$RAauQ}a#>Wc9g&AeWzUdbb7mx=xx)aMu;RIvxiJej+! zhSgIht$;3s9MngC;?V1w1w8Grt}fmAi$0$YSTlaHB7B$H%|NjCxhYLzb;%sm>dbp{ zEwBG+t+&ZgFEystSP>%yTns3KrS@EIsb6}TFZKP2@W0iOM`Dd3v{vgU7y|K+d`cN1U!;S~O7UgM`lLc|5^JuCh5_n<6wOpxyK7@2%cc48 zu;+nzhKw)J}6FLOKJL?g+?|_fSHSeJOHCyaI41VvoS7Q5o)PDDV@y?>Y18J8c`;-2Z{sxEz5i z76H(qOg0Kzip{)(0pvQ5wG}y0zEr$;%!h^6gJC50P}QDA*tRkZ`n2mju9?H7$2QY+ z*drms6Zw%+D^&^Zab?Y61N^f$;aGx?{`4|)3kw%mEWIVpqf+HS%qK*EhKi1IsS*tS F{{Tw%MFIc- literal 0 HcmV?d00001 diff --git a/rhsso-images/domain-server-dir.png b/rhsso-images/domain-server-dir.png new file mode 100755 index 0000000000000000000000000000000000000000..7869cfde4274beb08c9145876862a3438aeefc9e GIT binary patch literal 4705 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 literal 0 HcmV?d00001 diff --git a/topics/operating-mode/domain-example.adoc b/topics/operating-mode/domain-example.adoc deleted file mode 100755 index a288df10aa..0000000000 --- a/topics/operating-mode/domain-example.adoc +++ /dev/null @@ -1,35 +0,0 @@ -== Domain Mode Example Walkthrough - -As noted in the <> chapter, {{book.project.name}} comes with a mostly pre-configured clustered domain -setup. This chapter walks you through this out of the box configuration highlighting each aspect of each configuration -file you need to touch and manage. At the end, the chapter discusses what changes you'll need to make to this out of the -box configuration to have it work in a real cluster. - -The default +profile+ XML block is where you are going to make the bulk of your configuration decisions. You can edit this file -directly prior to booting the domain controller, but you should use the {{book.appserver.name}} web console or command line interface -to modify it at runtime. - -.profile -[source,xml] ----- - - - ... - ----- - -The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile -that is used (+default+) and also so default boot arguments for the Java VM when the host controller boots an instance. - -.server group -[source,xml] ----- - - - - - - - - ----- diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 67ebcf5c95..de3098cbe0 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -42,9 +42,6 @@ HTTP network connections, caches, and other infrastructure related things. Whil domain mode uses the _.../domain/domain.xml_ configuration file. This is where the domain profile and server group for the {{book.project.name}} server are defined. -{{book.project.name}} does come with a pre-configured _domain.xml_ file. While it will work almost out of the box, there is some tweaks you need -to make to it for it to be able to manage a real cluster. The <<_example_domain,example domain>> section of this chapter walks through each -aspect of this pre-configured _domain.xml_ file. .domain.xml image:../../{{book.images}}/domain-file.png[] @@ -53,6 +50,46 @@ NOTE: Any changes you make to this file while the domain controller is running w by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. +Let's look at some aspects of this _domain.xml_ file. The +auth-server+ +profile+ XML block is where you are going to make the bulk of your configuration decisions. +You'll be configuring things here like network connections, caches, and database connections. + + +.auth-server profile +[source,xml] +---- + + + ... + +---- + +The +ha-sockets+ +socket-binding-group+ defines the default port mappings for various connectors that are opened with each +{{book.project.name}} server instance. Any value that contains +${...}+ is a value that can be overriden on the command line +with the +-D+ switch, i.e. + +---- +$ domain.sh -Djboss.http.port=80 +---- + +The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile +that is used (+default+) and also some default boot arguments for the Java VM when the host controller boots an instance. It also +binds a +socket-binding-group+ to the server group. + +.server group +[source,xml] +---- + + + + + + + + +---- + + + ==== Host Controller Configuration {{book.project.name}} comes with two host controller configuration files that reside in the _.../domain/configuration/_ directory: @@ -60,9 +97,56 @@ _host-master.xml_ and _host-slave.xml_. _host-master.xml_ is configured to boot one {{book.project.name}} server instance. _host-slave.xml_ is configured to talk to the domain controller and boot up one {{book.project.name}} server instance. +NOTE: You should remove the load balancer server from _host-master.xml_. The load balancer included is really not that + production ready and doesn't work as smoothly as something like Apache HTTPD + mod-cluster or a hardward based one. + .Host Controller Config image:../../{{book.images}}/host-files.png[] +To disable the load balancer server instance, edit _host-master.xml_ and comment out or remove the +"load-balancer"+ entry. + +[source,xml] +---- + + + + ... + +---- + +Another interesting thing to note about this file is the declaration of the authentication server instance. It has +a +port-offset+ setting. Any network port defined in the _domain.xml_ +socket-binding-group+ or the server group +will have the value of +port-offset+ added to it. For this example domain setup we do this so that ports opened by +the load balancer server don't conflict with the authentication server instance that is started. + +[source,xml] +---- + + ... + + + + +---- + +==== Server Instance Working Directories + +Each {{book.project.name}} server instance defined in your host files creates a working directory under _.../domain/servers/{SERVER NAME}_. +Additional configuration can be put there, and any temporary, log, or data files the server instance needs or creates go there too. +The structure of these per server directories ends up looking like any other {{book.appserver.name}} booted server. + +.Working Directories +image:../../{{book.images}}/domain-server-dir.png[] + +==== {{book.project.name}} JSon Configuration + +Unfortunately, there is no centralized way to manage the _keycloak.json_ file. You'll have to manage a copy of this file +in every server instance you deploy. This file must exist in the _.../domain/servers/{SERVER NAME}/configuration directory. + +.JSON Configuration +image:../../{{book.images}}/domain-json-config.png[] + + ==== Domain Boot Script When running the server in domain mode, there is a specific script you need to run to boot the server depending on your @@ -89,6 +173,99 @@ When running the boot script you will need pass in the host controlling configur +--host-config+ switch. +==== Running the Clustered Domain Example + +The example domain that comes with {{book.project.name}} was meant to run on one machine. It starts a: +* domain controller +* HTTP load balancer +* 2 {{book.project.name}} server instances + +To simulate running a cluster on two machines, you'll run the +domain.sh+ script twice to start two separate +host controllers. The first will be the master host controller. It start a domain controller, an HTTP load balancer, and one +{{book.project.name}} authentication server instance. The second will be a slave host controller that only starts +up an authentication server instance. + +===== Setup Secure Master Slave Connection + +Before you can boot things up though, you have to configure the slave host controller so that it can talk securely to the domain +controller to obtain the centralized configuration. To set up a secure connection, you have to create a server admin user and a secret that +will be shared between the master and the slave. You do this by running the +.../bin/add-user.sh+ script. + +When you run the script select +Management User+ and answer +yes+ when it asks you if the new user is going to be used +for one AS process to connect to another. This will generate a secret that you'll need to cut and paste into the +_.../domain/configuration/host-slave.xml_ file. + +.Add App Server Admin +[source,shell] +---- +$ add-user.sh + What type of user do you wish to add? + a) Management User (mgmt-users.properties) + b) Application User (application-users.properties) + (a): a + Enter the details of the new user to add. + Using realm 'ManagementRealm' as discovered from the existing property files. + Username : admin + Password recommendations are listed below. To modify these restrictions edit the add-user.properties configuration file. + - The password should not be one of the following restricted values {root, admin, administrator} + - The password should contain at least 8 characters, 1 alphabetic character(s), 1 digit(s), 1 non-alphanumeric symbol(s) + - The password should be different from the username + Password : + Re-enter Password : + What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[ ]: + About to add user 'admin' for realm 'ManagementRealm' + Is this correct yes/no? yes + Added user 'admin' to file '/.../standalone/configuration/mgmt-users.properties' + Added user 'admin' to file '/.../domain/configuration/mgmt-users.properties' + Added user 'admin' with groups to file '/.../standalone/configuration/mgmt-groups.properties' + Added user 'admin' with groups to file '/.../domain/configuration/mgmt-groups.properties' + Is this new user going to be used for one AS process to connect to another AS process? + e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls. + yes/no? *yes* + To represent the user add the following to the server-identities definition ** + ---- + + Now cut and paste the secret value into the .../domain/configuration/host-slave.xml_ file: + + [source,xml] + ---- + + + + + + +---- + +===== Run the Boot Scripts + +Since we're simulating running on two separate machines, you'll run the boot script twice: + +.Boot up master +[source,shell] +---- +$ domain.sh --host-config=host-master.xml +---- + +.Boot up slave +[source,shell] +---- +$ domain.sh --host-config=host-slave.xml +---- + +To try it out, open your browser and go to http://localhost:8080/auth + + + + + + + + + + + + diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc index 4da47e5819..07fde37123 100755 --- a/topics/operating-mode/standalone-ha.adoc +++ b/topics/operating-mode/standalone-ha.adoc @@ -45,7 +45,7 @@ $ .../bin/standalone.sh --server-config=standalone-ha.xml > ...\bin\standalone.bat --server-config=standalone-ha.xml ---- -==== Standalone Clustered {{book.project.name}} Configuration +==== Standalone Clustered {{book.project.name}} JSON Configuration The {{book.project.name}} specific json configure file resides in the same place as in standalone mode: _.../standalone/configuration/keycloak.json_. Like _standalone-ha.xml_ you have to modify this file in each distribution in your cluster in order for changes to take effect. diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index 986b879d5b..6052433ab8 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -42,7 +42,7 @@ NOTE: Any changes you make to this file while the server is running will not tak the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. -==== Standalone {{book.project.name}} Configuration +==== Standalone {{book.project.name}} JSON Configuration {{book.project.name}} has a json configuration file that is specific to {{book.project.name}} this is located within _.../standalone/configuration/keycloak.json_. This file is used to configure non-infrastructure level things that are From 5a41e85cdd3c34d9f26384340fa9de39af88a441 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 23 Apr 2016 20:34:52 -0400 Subject: [PATCH 064/149] more --- topics/operating-mode/domain.adoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index de3098cbe0..6f26566c18 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -221,14 +221,14 @@ $ add-user.sh Added user 'admin' with groups to file '/.../domain/configuration/mgmt-groups.properties' Is this new user going to be used for one AS process to connect to another AS process? e.g. for a slave host controller connecting to the master or for a Remoting connection for server to server EJB calls. - yes/no? *yes* - To represent the user add the following to the server-identities definition ** - ---- + yes/no? yes + To represent the user add the following to the server-identities definition +---- - Now cut and paste the secret value into the .../domain/configuration/host-slave.xml_ file: +Now cut and paste the secret value into the .../domain/configuration/host-slave.xml_ file: - [source,xml] - ---- +[source,xml] +---- From d69a6e4c5c5ccdb889fa0280179873066e38cafb Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 23 Apr 2016 20:36:51 -0400 Subject: [PATCH 065/149] more --- topics/operating-mode/domain.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 6f26566c18..61186d08cf 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -196,7 +196,7 @@ for one AS process to connect to another. This will generate a secret that you' _.../domain/configuration/host-slave.xml_ file. .Add App Server Admin -[source,shell] +[source] ---- $ add-user.sh What type of user do you wish to add? From 6355629639604d8698c20f86f58417af9a645d5f Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 26 Apr 2016 23:02:53 -0400 Subject: [PATCH 066/149] more --- SUMMARY.adoc | 5 ++ book.json | 4 ++ keycloak-images/db-module.png | Bin 0 -> 8482 bytes rhsso-images/db-module.png | Bin 0 -> 8762 bytes topics/database.adoc | 62 +++++++++++++++++++ topics/manage.adoc | 53 +++++++++++++++++ topics/mongo.adoc | 95 ++++++++++++++++++++++++++++++ topics/operating-mode/domain.adoc | 2 +- 8 files changed, 220 insertions(+), 1 deletion(-) create mode 100755 keycloak-images/db-module.png create mode 100755 rhsso-images/db-module.png create mode 100755 topics/database.adoc create mode 100755 topics/manage.adoc create mode 100755 topics/mongo.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 7e4200ac59..99e8c66513 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -17,6 +17,11 @@ .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] + . link:topics/management.adoc[Managing Config at Runtime] + . link:topics/database.adoc[Relational Database Setup] + {% if book.community %} + . link:topics/mongo.adoc[Mongo DB Setup] + {% endif %} . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] . link:topics/management.adoc[Runtime Management] diff --git a/book.json b/book.json index e0480933da..5dd8eddcf8 100755 --- a/book.json +++ b/book.json @@ -18,6 +18,10 @@ "admindoc": { "name": "JBoss EAP Administration and Configuration Guide", "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/" + }, + "datasource": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/chap-Datasource_Management.html" } }, "caching": { diff --git a/keycloak-images/db-module.png b/keycloak-images/db-module.png new file mode 100755 index 0000000000000000000000000000000000000000..1e39af22a8e5fae3072d1406a0b91acfc20d25ae GIT binary patch literal 8482 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

    W7wH$Qj zHO;m)(VdXY*KI*ffLzvd{q0A${FxqBVMO z!r_KN{-@c`=?DK;Vf{=H;cvcvursv;11bF6ojoE78O-F?YtwxL{I3CoQqoe)zh?31 F{{RIFMpOU* literal 0 HcmV?d00001 diff --git a/rhsso-images/db-module.png b/rhsso-images/db-module.png new file mode 100755 index 0000000000000000000000000000000000000000..a55355c1f044460f7e89c16ebcc5291f7e820d0f GIT binary patch literal 8762 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 p{Da!-a27P#-%D*`(6M5 literal 0 HcmV?d00001 diff --git a/topics/database.adoc b/topics/database.adoc new file mode 100755 index 0000000000..0a22c68337 --- /dev/null +++ b/topics/database.adoc @@ -0,0 +1,62 @@ +[[_database]] + +== Relational Database Setup + +Out of the box, {{book.project.name}} persists its data using the Hibernate JPA set of APIs on top of an embedded Java based relational database. +The built-in database is not viable in high load and high concurrency situations. It cannot be used in a cluster either. It is +highly recommended that you replace the default embedded database with a more scalable and reliable solution like PostgreSQL or MySql. This +chapter will show you how to configure {{book.project.name}} to use an external relational database. It will also discuss +how you can configure the Hibernate JPA persistence abstraction that sits on top of your RDBMS. + +NOTE: Datasource configuration is covered much more thoroughly within the link:{{book.appserver.database.link}}[the datasource configuration chapter] + of the {{book.appserver.admindoc.name}}. + +=== RDBMS Checklist + +These are the steps you will need to perform to get an RDBMS configured for {{book.project.name}}. + +. Locate and download a JDBC driver for your database +. Package the driver JAR into a module and install this module into the server +. Declare the JDBC driver in the configuration profile of the server +. Modify the datasource configuration to use your database's JDBC driver +. Modify the datasource configuration to define the connection parameters to your database + +This chapter will use PostgresSQL for all its examples. Other databases follow the same steps for installation. + +=== Package the JDBC Driver + +Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module. +Modules define JARs that are loaded into the {{book.project.name}} classpath and the dependencies those JARs have on +other modules. They are pretty simple to set up. + +Within the _.../modules/system/layers/keycloak/_ directory of your +{{book.project.name}} distribution, you need to create a directory structure to hold your module definition. The convention is use the Java package name +of the JDBC driver for the name of the directory structure. For PostgreSQL, create the directory _org/postgresql/main_. Copy your database +driver JAR into this directory and also create an empty _module.xml_ file. + +.Module Directory +image:../../{{book.images}}/db-module.png[] + +After you have done this, open up the _module.xml_ file and create the following XML + +.Module XML +[source,xml] +---- + + + + + + + + + + + + +---- + +The module name should match the directory structure of your module. _org/postgresql_ maps to +org.postgresql+. The ++resource-root path+ attribute should specify the JAR filename. The rest are just the normal dependencies that +any JDBC driver JAR would have. + diff --git a/topics/manage.adoc b/topics/manage.adoc new file mode 100755 index 0000000000..8f8de1f966 --- /dev/null +++ b/topics/manage.adoc @@ -0,0 +1,53 @@ +[[_app_server_cli]] + +== Manage Configuration at Runtime + +In the upcoming chapters, you'll often be provided two options for applying application server configuration changes to your deployment. You'll be +shown how to edit the _standalone.xml_ or _domain.xml_ directly. This must be done when the server (or servers) are offline. +Additionally, you may be shown how to apply config changes on a running server using the app server's command line interface ({{books.appserver.name}} CLI). This chapter discusses +how you will do this. + +=== Start the {{books.appserver.name}} CLI + +To start the {{books.appserver.name}} CLI, you need to run the +jboss-cli+ script. + +.Linux/Unix +[source] +---- +$ .../bin/jboss-cli.sh +---- + +.Windows +[source] +---- +> ...\bin\jboss-cli.bat +---- + +This will bring you to a prompt like this: + +.Prompt +[source] +---- +[disconnected /] +---- + +There's a few commands you can execute without a running standalone server or domain controller, but usually you will +have to have those services booted up before you can execute CLI commands. To connect to a running server simply +execute the +connect+ command. + +.connect +[source] +---- +[disconnected /] connect +connect +[domain@localhost:9990 /] +---- + +You may be thinking to yourself, "I didn't enter in any username or password!". If you run +jboss-cli+ on the same machine +as your running standalone server or domain controller and your account has appropriate file permissions, you do not have +to setup or enter in a admin username and password. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] +for more details on how to make things more secure if you are uncomfortable with that setup. + + + + diff --git a/topics/mongo.adoc b/topics/mongo.adoc new file mode 100755 index 0000000000..400b529102 --- /dev/null +++ b/topics/mongo.adoc @@ -0,0 +1,95 @@ +[[_mongo]] + +== Mongo DB Setup + +You are not stuck with using a RDBMS for persisting data. {{book.project.name}} +provides http://www.mongodb.com[MongoDB] based model implementation. +To configure {{book.project.name}} to use Mongo, you need to edit the _keycloak-server.json_ file. If you are running +in standalone mode, this file is in the _.../standalone/configuration_ directory. If you are running in domain mode +this file will live in the _.../domain/servers/{server name}/configuration_ directory. + +[source,json] +---- + +"eventsStore": { + "provider": "jpa", + "jpa": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "jpa" +}, + +"user": { + "provider": "${keycloak.user.provider:jpa}" +}, +---- +to: + +[source,json] +---- + +"eventsStore": { + "provider": "mongo", + "mongo": { + "exclude-events": [ "REFRESH_TOKEN" ] + } +}, + +"realm": { + "provider": "mongo" +}, + +"user": { + "provider": "mongo" +}, +---- +And at the end of the file add the snippet like this where you can configure details about your Mongo database: + +[source,json] +---- + +"connectionsMongo": { + "default": { + "host": "127.0.0.1", + "port": "27017", + "db": "keycloak", + "connectionsPerHost": 100, + "databaseSchema": "update" + } +} +---- +All configuration options are optional. +Default values for host and port are localhost and 27017. +Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. +If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. + +Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. +Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. +Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. +Supported long option is `maxAutoConnectRetryTime`. +See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. + +Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. +In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. +Please note that the database specified within the URI is only used for authentication. +To change the database used by keycloak you have to set `db` property as before. +Therefore, a configuration like the following + +[source] +---- + +"connectionsMongo": { + "default": { + "uri": "mongodb://user:password@127.0.0.1/authentication", + "db": "keycloak" + } +} +---- +will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. + +==== MongoDB Replica Sets + +In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 61186d08cf..768078f916 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -225,7 +225,7 @@ $ add-user.sh To represent the user add the following to the server-identities definition ---- -Now cut and paste the secret value into the .../domain/configuration/host-slave.xml_ file: +Now cut and paste the secret value into the _.../domain/configuration/host-slave.xml_ file: [source,xml] ---- From a551e86a4083ba722c1deab61f311e9d86c7a861 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 26 Apr 2016 23:05:25 -0400 Subject: [PATCH 067/149] more --- SUMMARY.adoc | 2 +- topics/database.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 99e8c66513..65131fdd78 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -17,7 +17,7 @@ .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] - . link:topics/management.adoc[Managing Config at Runtime] + . link:topics/manage.adoc[Managing Config at Runtime] . link:topics/database.adoc[Relational Database Setup] {% if book.community %} . link:topics/mongo.adoc[Mongo DB Setup] diff --git a/topics/database.adoc b/topics/database.adoc index 0a22c68337..9a11231e7f 100755 --- a/topics/database.adoc +++ b/topics/database.adoc @@ -35,7 +35,7 @@ of the JDBC driver for the name of the directory structure. For PostgreSQL, cre driver JAR into this directory and also create an empty _module.xml_ file. .Module Directory -image:../../{{book.images}}/db-module.png[] +image:../{{book.images}}/db-module.png[] After you have done this, open up the _module.xml_ file and create the following XML From d1f2f961ffc515d82f3cc10ab11befe42e49e58e Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 26 Apr 2016 23:09:46 -0400 Subject: [PATCH 068/149] more --- topics/database.adoc | 2 +- topics/mongo.adoc | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/topics/database.adoc b/topics/database.adoc index 9a11231e7f..cf67ab7a6f 100755 --- a/topics/database.adoc +++ b/topics/database.adoc @@ -8,7 +8,7 @@ highly recommended that you replace the default embedded database with a more sc chapter will show you how to configure {{book.project.name}} to use an external relational database. It will also discuss how you can configure the Hibernate JPA persistence abstraction that sits on top of your RDBMS. -NOTE: Datasource configuration is covered much more thoroughly within the link:{{book.appserver.database.link}}[the datasource configuration chapter] +NOTE: Datasource configuration is covered much more thoroughly within the link:{{book.appserver.dataource.link}}[the datasource configuration chapter] of the {{book.appserver.admindoc.name}}. === RDBMS Checklist diff --git a/topics/mongo.adoc b/topics/mongo.adoc index 400b529102..332b545cf6 100755 --- a/topics/mongo.adoc +++ b/topics/mongo.adoc @@ -8,6 +8,9 @@ To configure {{book.project.name}} to use Mongo, you need to edit the _keycloak- in standalone mode, this file is in the _.../standalone/configuration_ directory. If you are running in domain mode this file will live in the _.../domain/servers/{server name}/configuration_ directory. +Open the _keycloak-server.json_ file. Look for the following JSON snippet This is the area you will be modifying +to use Mongo. + [source,json] ---- @@ -26,7 +29,8 @@ this file will live in the _.../domain/servers/{server name}/configuration_ dire "provider": "${keycloak.user.provider:jpa}" }, ---- -to: + +Change that JSON snippet to use Mongo: [source,json] ---- From 6f12c15d521575face41b90ff3ffae7cc221050e Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 26 Apr 2016 23:11:09 -0400 Subject: [PATCH 069/149] more --- SUMMARY.adoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 65131fdd78..e127aeb488 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -12,7 +12,6 @@ .. link:topics/installation/distribution-files-product.adoc[Installing Distribution Files] {% endif %} .. link:topics/installation/directory-structure.adoc[Distribution Directory Structure] - .. link:topics/openshift.adoc[Installing on OpenShift] . link:topics/operating-mode.adoc[Choosing an Operating Mode] .. link:topics/operating-mode/standalone.adoc[Standalone Mode] .. link:topics/operating-mode/standalone-ha.adoc[Standalone Clustered Mode] @@ -24,7 +23,6 @@ {% endif %} . link:topics/cache.adoc[Server Cache] . link:topics/clustering.adoc[Clustering] - . link:topics/management.adoc[Runtime Management] {% if book.community %} . link:topics/proxy.adoc[Keycloak Security Proxy] {% endif %} From 15dee9a19650d88850f59f46b9986cb36bec3593 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 27 Apr 2016 17:01:22 -0400 Subject: [PATCH 070/149] more --- SUMMARY.adoc | 4 ++ book.json | 2 +- topics/database.adoc | 65 +++++----------------- topics/database/checklist.adoc | 12 +++++ topics/database/datasource.adoc | 46 ++++++++++++++++ topics/database/hibernate.adoc | 52 ++++++++++++++++++ topics/database/jdbc.adoc | 96 +++++++++++++++++++++++++++++++++ topics/operating-mode.adoc | 2 + 8 files changed, 226 insertions(+), 53 deletions(-) create mode 100755 topics/database/checklist.adoc create mode 100755 topics/database/datasource.adoc create mode 100755 topics/database/hibernate.adoc create mode 100755 topics/database/jdbc.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index e127aeb488..d99a958539 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -18,6 +18,10 @@ .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] . link:topics/manage.adoc[Managing Config at Runtime] . link:topics/database.adoc[Relational Database Setup] + .. link:topics/checklist.adoc[Setup Checklist] + .. link:topics/jdbc.adoc[JDBC Setup] + .. link:topics/datasource.adoc[Datasource Setup] + .. link:topics/hibernate.adoc[Hibernate Configuration] {% if book.community %} . link:topics/mongo.adoc[Mongo DB Setup] {% endif %} diff --git a/book.json b/book.json index 5dd8eddcf8..a277afeeb1 100755 --- a/book.json +++ b/book.json @@ -36,7 +36,7 @@ "name": "Hibernate", "version": "???", "admindoc": { - "name": "Hibernate Config", + "name": "JBoss Development Guide", "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Development_Guide/sect-Java_Persistence_API_JPA.html#sect-Configuration2" } diff --git a/topics/database.adoc b/topics/database.adoc index cf67ab7a6f..f10fc31efb 100755 --- a/topics/database.adoc +++ b/topics/database.adoc @@ -1,62 +1,23 @@ [[_database]] == Relational Database Setup +{{book.project.name}} comes with its own embedded Java-based relational database called H2. +This is the default database that {{book.project.name}} will use to persist data and really only exists so that you can run the authentication +server out of the box. We highly recommend that you replace it with a more production ready external database. The H2 database +is not very viable in high concurrency situations and cannot be used in a cluster either. The purpose of this chapter is to +show you how to connect {{book.project.name}} to a more mature database. -Out of the box, {{book.project.name}} persists its data using the Hibernate JPA set of APIs on top of an embedded Java based relational database. -The built-in database is not viable in high load and high concurrency situations. It cannot be used in a cluster either. It is -highly recommended that you replace the default embedded database with a more scalable and reliable solution like PostgreSQL or MySql. This -chapter will show you how to configure {{book.project.name}} to use an external relational database. It will also discuss -how you can configure the Hibernate JPA persistence abstraction that sits on top of your RDBMS. +{{book.project.name}} uses two layered technologies to persist its relational data. The bottom layered technology is JDBC. JDBC +is a Java API that is used to connect to a RDBMS. There are different JDBC drivers per database type that are provided +by your database vendor. This chapter discusses how to configure {{book.project.name}} to use one of these vendor-specific drivers. -NOTE: Datasource configuration is covered much more thoroughly within the link:{{book.appserver.dataource.link}}[the datasource configuration chapter] +The top layered technology for persistence is Hibernate JPA. This is a object to relational mapping API that maps Java +Objects to relational data. Most deployments of {{book.project.name}} will never have to touch the configuration aspects +of Hibernate, but we will discuss how that is done if you run into that rare circumstance. + +NOTE: Datasource configuration is covered much more thoroughly within the link:{{book.appserver.datasource.link}}[the datasource configuration chapter] of the {{book.appserver.admindoc.name}}. -=== RDBMS Checklist -These are the steps you will need to perform to get an RDBMS configured for {{book.project.name}}. -. Locate and download a JDBC driver for your database -. Package the driver JAR into a module and install this module into the server -. Declare the JDBC driver in the configuration profile of the server -. Modify the datasource configuration to use your database's JDBC driver -. Modify the datasource configuration to define the connection parameters to your database - -This chapter will use PostgresSQL for all its examples. Other databases follow the same steps for installation. - -=== Package the JDBC Driver - -Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module. -Modules define JARs that are loaded into the {{book.project.name}} classpath and the dependencies those JARs have on -other modules. They are pretty simple to set up. - -Within the _.../modules/system/layers/keycloak/_ directory of your -{{book.project.name}} distribution, you need to create a directory structure to hold your module definition. The convention is use the Java package name -of the JDBC driver for the name of the directory structure. For PostgreSQL, create the directory _org/postgresql/main_. Copy your database -driver JAR into this directory and also create an empty _module.xml_ file. - -.Module Directory -image:../{{book.images}}/db-module.png[] - -After you have done this, open up the _module.xml_ file and create the following XML - -.Module XML -[source,xml] ----- - - - - - - - - - - - - ----- - -The module name should match the directory structure of your module. _org/postgresql_ maps to +org.postgresql+. The -+resource-root path+ attribute should specify the JAR filename. The rest are just the normal dependencies that -any JDBC driver JAR would have. diff --git a/topics/database/checklist.adoc b/topics/database/checklist.adoc new file mode 100755 index 0000000000..d578f89478 --- /dev/null +++ b/topics/database/checklist.adoc @@ -0,0 +1,12 @@ +=== RDBMS Setup Checklist + +These are the steps you will need to perform to get an RDBMS configured for {{book.project.name}}. + +. Locate and download a JDBC driver for your database +. Package the driver JAR into a module and install this module into the server +. Declare the JDBC driver in the configuration profile of the server +. Modify the datasource configuration to use your database's JDBC driver +. Modify the datasource configuration to define the connection parameters to your database + +This chapter will use PostgresSQL for all its examples. Other databases follow the same steps for installation. + diff --git a/topics/database/datasource.adoc b/topics/database/datasource.adoc new file mode 100755 index 0000000000..4f7963b5eb --- /dev/null +++ b/topics/database/datasource.adoc @@ -0,0 +1,46 @@ +=== Modify the {{book.project.name}} Datasource + +After declaring your JDBC driver, you have to modify the existing datasource configuration that {{book.project.name}} uses +to connect to the built-in embedded database. You'l need to change it to connect to your new external database. You'll do +this within the same configuration file and XML block that you registered your JDBC driver. Here's an example +that set's up the connection to your new database: + +.Declare Your JDBC Drivers +[source,xml] +---- + + + ... + + jdbc:postgresql://localhost/keycloak + postgresql + + 20 + + + William + password + + + ... + + +---- + +Search for the +datasource+ definition for +KeycloakDS+. You'll first need to specify the +connection-url+. The +documentation for your vendor's JDBC implementation will tell you the connection URL you should provide there. + +Next define the +driver+ you will use. This is the logical name of the JDBC driver you declared in the previous section of this +chapter. + +It is expensive to open a new connection to a database ever time you want to perform a transaction. To compensate, the datasource +implementation maintains a pool of open connections. The +max-pool-size+ specifies the maximum number of connections it will pool. +You may want to change the value of this depending on the load of your system. + +Finally, or PostgreSQL at least, you need to define the database username and password that is needed to connect to the database. You +may be worried that this is in clear text in the example. There are methods to obfuscate this, but this is beyond the +scope of this guide. + +NOTE: For more information and details features of datasources, please see the link:{{book.appserver.datasource.link}}[the datasource configuration chapter] +of the {{book.appserver.admindoc.name}}. + diff --git a/topics/database/hibernate.adoc b/topics/database/hibernate.adoc new file mode 100755 index 0000000000..fe43659b5a --- /dev/null +++ b/topics/database/hibernate.adoc @@ -0,0 +1,52 @@ +=== Hibernate Configuration + +The Hibernate persistence API is already pre-configured out of the box. It is rare to have to modify the configuration for it. +To configure Hibernate, you need to edit the _keycloak-server.json_ file. If you are running +in standalone mode, this file is in the _.../standalone/configuration_ directory. If you are running in domain mode +this file will live in the _.../domain/servers/{server name}/configuration_ directory. + +.Hibernate JPA Config +[source,json] +---- +"connectionsJpa": { + "default": { + "dataSource": "java:jboss/datasources/KeycloakDS", + "databaseSchema": "update" + } +}, +---- + +Possible configuration options are: + +dataSource:: + JNDI name of the dataSource + +jta:: + boolean property to specify if datasource is JTA capable + +driverDialect:: + Value of database dialect. + In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. + +databaseSchema:: + Specify if schema should be updated or validated. + Valid values are +update+ (default) and +validate+. The +update+ value will set up or update + the table definitions that {{book.project.name}} needs. +validate+ just makes sure that the database has + the appropriate table definitions set up. + +showSql:: + Specify whether Hibernate should show all SQL commands in the console (false by default). This is very verbose! + +formatSql:: + Specify whether Hibernate should format SQL commands (true by default) + +globalStatsInterval:: + Will log global statistics from Hibernate about executed DB queries and other things. + Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. + +schema:: + Specify the database schema to use + +NOTE: All these configuration switches and more are described in the link:{{book.jpa.link}}[the Hibernate chapter] + of {{book.jpa.name}}. + diff --git a/topics/database/jdbc.adoc b/topics/database/jdbc.adoc new file mode 100755 index 0000000000..4f28499d34 --- /dev/null +++ b/topics/database/jdbc.adoc @@ -0,0 +1,96 @@ +=== Package the JDBC Driver + +Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module. +Modules define JARs that are loaded into the {{book.project.name}} classpath and the dependencies those JARs have on +other modules. They are pretty simple to set up. + +Within the _.../modules/system/layers/keycloak/_ directory of your +{{book.project.name}} distribution, you need to create a directory structure to hold your module definition. The convention is use the Java package name +of the JDBC driver for the name of the directory structure. For PostgreSQL, create the directory _org/postgresql/main_. Copy your database +driver JAR into this directory and also create an empty _module.xml_ file. + +.Module Directory +image:../../{{book.images}}/db-module.png[] + +After you have done this, open up the _module.xml_ file and create the following XML + +.Module XML +[source,xml] +---- + + + + + + + + + + + + +---- + +The module name should match the directory structure of your module. So, _org/postgresql_ maps to +org.postgresql+. The ++resource-root path+ attribute should specify the JAR filename. The rest are just the normal dependencies that +any JDBC driver JAR would have. + +=== Declare and Load JDBC Driver + +The next thing you have to do is declare your newly packaged JDBC driver into your deployment profile so that it loads and becomes +available. Where you perform this action depends on your <>. If you're +deploying in standard mode, edit _.../standalone/configuration/standalone.xml_. If you're deploying in standard clustering +mode, edit _.../standalone/configuration/standalone-ha.xml_. If you're deploying in domain mode, edit +_.../domain/configuration/domain.xml_. In domain mode, you'll need to make sure you edit the profile you are using: ++auth-server-standalone+ or +auth-server-clustered+ + +.Domain Profile +[source,xml] +---- + + ... + +---- + +Within the profile, search for the +drivers+ XML block within the +datasources+ subsystem. You should see +a pre-defined driver declared for the H2 JDBC driver. There is where you'll declare the JDBC driver for your external +database. + +.JDBC Drivers +[source,xml] +---- + + + ... + + + org.h2.jdbcx.JdbcDataSource + + + + +---- + +Within the +drivers+ XML block you'll need to declare an additional JDBC driver. It needs to have a +name+ which +you can choose to be anything you want. You have to define the module the new JDBC driver classes are defined in. Finally +you have to specify the driver's Java class. Here's an example of installing PostgreSQL driver that lives in the module +example defined earlier in this chapter. + + +.Declare Your JDBC Drivers +[source,xml] +---- + + + ... + + + org.postgresql.Driver + + + org.h2.jdbcx.JdbcDataSource + + + + +---- diff --git a/topics/operating-mode.adoc b/topics/operating-mode.adoc index 9d27b3947b..bdd87b7f10 100755 --- a/topics/operating-mode.adoc +++ b/topics/operating-mode.adoc @@ -1,3 +1,5 @@ +[[_operating_mode]] + == Choosing an Operating Mode Before deploying {{book.project.name}} in a production environment you need to decide which type of operating mode From aa87a8534f819b293361a460327a8226d598f638 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 27 Apr 2016 17:05:07 -0400 Subject: [PATCH 071/149] more --- SUMMARY.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index d99a958539..7ab048cfe4 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -18,10 +18,10 @@ .. link:topics/operating-mode/domain.adoc[Domain Clustered Mode] . link:topics/manage.adoc[Managing Config at Runtime] . link:topics/database.adoc[Relational Database Setup] - .. link:topics/checklist.adoc[Setup Checklist] - .. link:topics/jdbc.adoc[JDBC Setup] - .. link:topics/datasource.adoc[Datasource Setup] - .. link:topics/hibernate.adoc[Hibernate Configuration] + .. link:topics/database/checklist.adoc[Setup Checklist] + .. link:topics/database/jdbc.adoc[JDBC Setup] + .. link:topics/database/datasource.adoc[Datasource Setup] + .. link:topics/database/hibernate.adoc[Hibernate Configuration] {% if book.community %} . link:topics/mongo.adoc[Mongo DB Setup] {% endif %} From 587e04738a92fb7a855eb55142f291e211562398 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 27 Apr 2016 17:07:25 -0400 Subject: [PATCH 072/149] more --- topics/database/jdbc.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/database/jdbc.adoc b/topics/database/jdbc.adoc index 4f28499d34..b264ad18f6 100755 --- a/topics/database/jdbc.adoc +++ b/topics/database/jdbc.adoc @@ -38,7 +38,7 @@ any JDBC driver JAR would have. === Declare and Load JDBC Driver The next thing you have to do is declare your newly packaged JDBC driver into your deployment profile so that it loads and becomes -available. Where you perform this action depends on your <>. If you're +available. Where you perform this action depends on your <>. If you're deploying in standard mode, edit _.../standalone/configuration/standalone.xml_. If you're deploying in standard clustering mode, edit _.../standalone/configuration/standalone-ha.xml_. If you're deploying in domain mode, edit _.../domain/configuration/domain.xml_. In domain mode, you'll need to make sure you edit the profile you are using: From 54981bcd9fa7b76408736c6a3d7bf3c8ad3aca90 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 27 Apr 2016 17:09:21 -0400 Subject: [PATCH 073/149] more --- topics/database/hibernate.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topics/database/hibernate.adoc b/topics/database/hibernate.adoc index fe43659b5a..d5e0615454 100755 --- a/topics/database/hibernate.adoc +++ b/topics/database/hibernate.adoc @@ -47,6 +47,6 @@ globalStatsInterval:: schema:: Specify the database schema to use -NOTE: All these configuration switches and more are described in the link:{{book.jpa.link}}[the Hibernate chapter] - of {{book.jpa.name}}. +NOTE: All these configuration switches and more are described in the link:{{book.jpa.admindoc.link}}[the Hibernate chapter] + of {{book.jpa.admindoc.name}}. From 394592068dac600013a0cb15645bb7ae2f6ddd36 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 16:34:44 -0400 Subject: [PATCH 074/149] network --- SUMMARY.adoc | 10 +- book.json | 8 ++ document-attributes.adoc | 3 - topics/network.adoc | 20 ++++ topics/network/bind-address.adoc | 51 +++++++++ topics/network/https.adoc | 189 +++++++++++++++++++++++++++++++ topics/network/outgoing.adoc | 115 +++++++++++++++++++ topics/network/ports.adoc | 57 ++++++++++ 8 files changed, 448 insertions(+), 5 deletions(-) delete mode 100755 document-attributes.adoc create mode 100755 topics/network.adoc create mode 100755 topics/network/bind-address.adoc create mode 100755 topics/network/https.adoc create mode 100755 topics/network/outgoing.adoc create mode 100755 topics/network/ports.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 7ab048cfe4..78ba824229 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -25,10 +25,16 @@ {% if book.community %} . link:topics/mongo.adoc[Mongo DB Setup] {% endif %} - . link:topics/cache.adoc[Server Cache] + . link:topics/network.adoc[Network Setup] + .. link:topics/network/bind-address.adoc[Bind Addresses] + .. link:topics/network/ports.adoc[Socket Port Bindings] + .. link:topics/network/https.adoc[HTTPS/SSL Setup] + .. link:topics/network/outgoing.adoc[Outgoing HTTP Requests] . link:topics/clustering.adoc[Clustering] + . link:topics/cache.adoc[Server Cache Configuration] {% if book.community %} -. link:topics/proxy.adoc[Keycloak Security Proxy] + . link:topics/proxy.adoc[Keycloak Security Proxy] {% endif %} + . link:topics/migration.adoc[Upgrading and Migrating] diff --git a/book.json b/book.json index a277afeeb1..17294e0256 100755 --- a/book.json +++ b/book.json @@ -22,6 +22,14 @@ "datasource": { "name": "JBoss EAP Administration and Configuration Guide", "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/chap-Datasource_Management.html" + }, + "network": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/chap-Network_and_Port_Configuration.html#Configure_interfaces" + }, + "socket": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/sect-Socket_Binding_Groups.html" } }, "caching": { diff --git a/document-attributes.adoc b/document-attributes.adoc deleted file mode 100755 index 2b5779488a..0000000000 --- a/document-attributes.adoc +++ /dev/null @@ -1,3 +0,0 @@ -:attributes: yes - -Include worked! diff --git a/topics/network.adoc b/topics/network.adoc new file mode 100755 index 0000000000..9f08ab53ac --- /dev/null +++ b/topics/network.adoc @@ -0,0 +1,20 @@ +[[_network]] + +== Network Setup + +{{book.project.name}} can run out of the box, with some limitations. For one, all network endpoints bind to +localhost+ +so the auth server is really only usable on one local machine. For HTTP based connections, it does not use default ports +like 80 and 443. The SSO protocols that {{book.project.name}} uses all require +SSL/HTTPS or otherwise these protocols have some serious vulnerabilities. HTTPS/SSL is not configured out of the box. +Finally, {{book.project.name}} +may often need to make secure SSL connections to external servers and thus need a trust store set up so that endpoints can +be validated correctly. This chapter discusses all of these things. + + + + + + + + + diff --git a/topics/network/bind-address.adoc b/topics/network/bind-address.adoc new file mode 100755 index 0000000000..dc6bdfdda6 --- /dev/null +++ b/topics/network/bind-address.adoc @@ -0,0 +1,51 @@ +=== Bind Addresses + +By default {{book.project.name}} binds to the localhost loopback address 127.0.0.1. That's not a very useful default if +you want the authentication server available on your network. Generally, what we recommend is that you deploy a reverse proxy +or load balancer on a public network and route traffic to individual {{book.project.name}} server instances on a private network. +In either case though, you still need to set up your network interfaces to bind to something other than +localhost+. + +Setting the bind address is actually quite easy and can be done on the command line with either the _standalone.sh_ or +_domain.sh_ boot scripts discussed in the <> chapter. + +[source] +---- +$ standalone.sh -b 192.168.0.5 +---- + +The +-b+ switch tells the boot script the IP bind address for any public interfaces. + +Alternatively, you can edit the profile configuration of your deployment if you do not want to specify this IP address +every time you boot the server. Open up the profile configuration file (_standalone.xml or _domain.xml_ depending on your +<> and look for the interfaces XML block. + +[source,xml] +---- + + + + + + + + +---- + +The +public+ interface corresponds to subsystems creating sockets that are available publically. An example of one +of these subsystems is the web layer which serves up the authentication endpoints of {{book.project.name}}. The +management+ +interface corresponds to sockets opened up by the management layer of the {{book.appserver.name}}. Specifically the sockets +which allow you to use the +jboss-cli.sh+ command line interface and the {{book.appserver.name}} web console. + +In looking at the +public+ interface you see that it has a special string +${jboss.bind.address:127.0.0.1}+. This string +denotes a value +127.0.0.1+ that can be overriden on the command line by setting a Java system property, i.e.: + +[source] +---- +$ domain.sh -Djboss.bind.address=192.168.0.5 +---- + ++-b+ is actually just a convenience function for this. So, you can either change the bind address value directly in the profile config, or change it on the command line when +you boot up. + +NOTE: There's a lot more nifty options when setting up +interface+ definitions. See the link:{{book.appserver.network.link}}[the network interface] + chapter of the {{book.appserver.network.name}}. diff --git a/topics/network/https.adoc b/topics/network/https.adoc new file mode 100755 index 0000000000..854f7df037 --- /dev/null +++ b/topics/network/https.adoc @@ -0,0 +1,189 @@ +=== Setting up HTTPS/SSL + +WARNING: {{book.project.name}} is not set up by default to handle SSL/HTTPS. + It is highly recommended that you either enable SSL on the {{book.project.name}} server itself or on a reverse proxy in front of the {{book.project.name}} server. + +{{book.project.name}} can run out of the box without SSL/HTTPS so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. +If you try to access {{book.project.name}} out of the box via a non-private IP address you will get an error. + +This default behavior is defined by the SSL/HTTPS mode of each {{book.project.name}} realm. This is discussed in more detail in the +link:{{book.adminguide.link}}[{{book.adminguide.name}}], but let's give some context and a brief overview of these modes. + +external:: + {{book.project.name}} can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. + If you try to access {{book.project.name}} from a non-private IP adress you will get an error. + +none:: + {{book.project.name}} does not require SSL. This should really only be used in development when you are playing around with things. + +all:: + {{book.project.name}} requires SSL for all IP addresses. + +==== Enable HTTPS/SSL with a Reverse Proxy + +It is believed that most deployments of {{book.project.name}} will be clustered and will use a reverse proxy or load balancer +in front of {{book.project.name}} server instances. + +To enable SSL/HTTPS in this deployment scenario, follow the documentation for your reverse proxy first, before doing any {{book.project.name}} setup. +It is important that you make sure the proxy sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to {{book.project.name}}. +Next you need to enable `proxy-address-forwarding` on the {{book.project.name}} http connector in {{book.project.name}} configuration +Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. + +. Open _standalone.xml_, _standalone-ha.xml_, or _domain.xml_ file (depends on your <>). + +. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: + +[source] +---- + + ... + + ... + +---- + +Then add a new `socket-binding` element to the `socket-binding-group` element: + +[source] +---- + + + ... + + ... + +---- + +Also remember that when running in <> what +socket-binding-group+ +you modify depends on how you have your server groups configured. + +==== Enabling SSL/HTTPS for the {{book.project.name}} Server + +If you are not using a reverse proxy or load blancer to handle HTTPS traffic for you, you'll need to enable HTTPS +for the {{book.project.name}} server. This involves + +. Obtaining or generating a keystore that contains the private key and certificate for SSL/HTTP traffic +. Configuring the {{book.project.name}} server to use this keypair and certificate. + +===== Creating the Certificate and Java Keystore + +In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. + +====== Self Signed Certificate + +In development, you will probably not have a third party signed certificate available to test a {{book.project.name}} deployment so you'll need to generate a self-signed on. +Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. + + +[source] +---- + +$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 + Enter keystore password: secret + Re-enter new password: secret + What is your first and last name? + [Unknown]: localhost + What is the name of your organizational unit? + [Unknown]: Keycloak + What is the name of your organization? + [Unknown]: Red Hat + What is the name of your City or Locality? + [Unknown]: Westford + What is the name of your State or Province? + [Unknown]: MA + What is the two-letter country code for this unit? + [Unknown]: US + Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? + [no]: yes +---- + +You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. +For testing purposes, `localhost` should be used. +After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. + +If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. +You'll have to do a little set up first before doing this though. + +The first thing to do is generate a Certificate Request: + +[source] +---- + +$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq +---- + +Where `yourdomain` is a DNS name for which this certificate is generated for. +Keytool generates the request: + +[source] +---- + +-----BEGIN NEW CERTIFICATE REQUEST----- +MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y +ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY +Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 +29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as +H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw +Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 +2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i +n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf +PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ +9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X +MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S +vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= +-----END NEW CERTIFICATE REQUEST----- +---- + +Send this ca request to your CA. +The CA will issue you a signed certificate and send it to you. +Before you import your new cert, you must obtain and import the root certificate of the CA. +You can download the cert from CA (ie.: root.crt) and import as follows: + +[source] +---- + +$ keytool -import -keystore keycloak.jks -file root.crt -alias root +---- + +Last step is import your new CA generated certificate to your keystore: + +[source] +---- + +$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer +---- + +===== Configure {{book.project.name}} to Use the Keystore + +Now that you have a Java keystore with the appropriate certificates, you need to configure your {{book.project.name}} installation to use it. +First step is to move the keystore file to the _configuration_ directory of your deployment and to edit the _standalone.xml_, _standalone-ha.xml_ or _domain.xml_ file to use +the keystore and enable HTTPS. (See <>). + +In the standalone or domain configuration file, search for the `security-realms` element and add: + +[source] +---- + + + + + + + + +---- + +Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:`) and add: + +[source] +---- + + + + + ... + +---- diff --git a/topics/network/outgoing.adoc b/topics/network/outgoing.adoc new file mode 100755 index 0000000000..35bd16b67a --- /dev/null +++ b/topics/network/outgoing.adoc @@ -0,0 +1,115 @@ +=== Outgoing HTTP Requests + +The {{book.project.name}} server often needs to invoke non-browser HTTP requests on the applications and services it secures. +The auth server manages these outgoing connections by maintaining an HTTP client connection pool. There are a few settings +of which you should be aware of. These settings live in the file _keycloak-server.json_ _keycloak-server.json_ file that corresponds to your <> + +By default the setting is like this: + +[source,json] +---- +"connectionsHttpClient": { + "default": {} +}, +---- +Possible configuration options are: + +establish-connection-timeout-millis:: + Timeout for establishing a socket connection. + +socket-timeout-millis:: + If an outgoing request does not receive data for this amount of time, timeout the connection. + +connection-pool-size:: + How many connections can be in the pool (128 by default). + +max-pooled-per-route:: + How many connections can be pooled per host (64 by default). + +connection-ttl-millis:: + Maximum connection time to live in milliseconds. + Not set by default. + +max-connection-idle-time-millis:: + Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. + Set to -1 to disable this checking and the background thread. + +disable-cookies:: + `true` by default. + When set to true, this will disable any cookie caching. + +client-keystore:: + This is the file path to a Java keystore file. + This keystore contains client certificate for two-way SSL. + +client-keystore-password:: + Password for the client keystore. + This is _REQUIRED_ if `client-keystore` is set. + +client-key-password:: + _Not supported yet, but we will support in future versions. Password for the client's key. + This is _REQUIRED_ if `client-keystore` is set. + +[[_truststore]] +==== Outgoing HTTPS Request Truststore + +When {{book.project.name}} connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. +This is necessary in order to prevent man-in-the-middle attacks. + +How certificates are validated is also configured in the _keycloak-server.json_ file that corresponds to your <>. + +`standalone/configuration/keycloak-server.json`. +By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ + Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. + +Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. +Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. +The default JavaMail API implementation used to send out emails behaves in this way, for example. + +You can add your truststore configuration by using the following template: + +[source] +---- + +"truststore": { + "file": { + "file": "path to your .jks file containing public certificates", + "password": "password", + "hostname-verification-policy": "WILDCARD", + "disabled": false + } +} +---- + +Possible configuration options are: + +file:: + The value is the file path to a Java keystore file. + HTTPS requests need a way to verify the host of the server they are talking to. + This is what the trustore does. + The keystore contains one or more trusted host certificates or certificate authorities. + Truststore file should only contain public certificates of your secured hosts. + This is _REQUIRED_ if `disabled` is not true. + +password:: + Password for the truststore. + This is _REQUIRED_ if `disabled` is not true. + +hostname-verification-policy:: + `WILDCARD` by default. + For HTTPS requests, this verifies the hostname of the server's certificate. + `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. + *.foo.com. `STRICT` CN must match hostname exactly. + +disabled:: + If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. + If set to false, you must configure `file`, and `password` for the truststore. + +You can use _keytool_ to create a new truststore file and add trusted host certificates to it: + +[source] +---- + +$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer +---- + diff --git a/topics/network/ports.adoc b/topics/network/ports.adoc new file mode 100755 index 0000000000..41ae8c324d --- /dev/null +++ b/topics/network/ports.adoc @@ -0,0 +1,57 @@ +=== Socket Port Bindings + +The ports for each socket also have a pre-defined default that can be overriden at the command line or within configuration. +To illustrate this configuration, let's pretend you are running in <> and +open up the _.../standalone/configuration/standalone.xml_. Search for +socket-binding-group+. + +[source,xml] +---- + + + + + + + + + + + + +---- + ++socket-bindings+ define actual socket connections that will be open by the server that covers both the +interface+ (bind address) +that will be used as wel as the port. The ones you will be most interested in are + +http:: + Defines the port used by {{book.project.name}} HTTP connections +https:: + Defines the port used by {{book.project.name}} HTTPS connections +ajp:: + The Apache HTTPD server is often used with _mod-cluster_ as a load balancer. AJP is the protocol that is used. + This socket binding defines the port used for the AJP protocol. +management-http:: + Defines the HTTP connection used by {{book.appserer.name}} CLI and web console. + +When running in <> locking the socket configurations +is a bit trickier as the example _domain.xml_ file has multiple +socket-binding-groups+ defined. If you scroll down +to the +server-group+ definitions you can see what +socket-binding-group+ is used for each +server-group+. + +.domain socket bindings +[source,xml] +---- + + + ... + + + + ... + + + +---- + +NOTE: There's a lot more nifty options when setting up +socket-binding-group+ definitions. See the link:{{book.appserver.socket.link}}[the socket binding group] + chapter of the {{book.appserver.socket.name}}. + From fcc7ad78221fe70b2dfa5da6cefc91c031640f60 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 18:25:54 -0400 Subject: [PATCH 075/149] clustering --- SUMMARY.adoc | 7 ++ book.json | 12 ++ topics/clustering.adoc | 158 ++----------------------- topics/clustering/booting.adoc | 17 +++ topics/clustering/example.adoc | 5 + topics/clustering/load-balancer.adoc | 6 + topics/clustering/multicast.adoc | 35 ++++++ topics/clustering/recommended.adoc | 9 ++ topics/clustering/serialized.adoc | 23 ++++ topics/clustering/troubleshooting.adoc | 17 +++ topics/network/bind-address.adoc | 2 + topics/network/ports.adoc | 2 + topics/operating-mode/domain.adoc | 2 +- 13 files changed, 147 insertions(+), 148 deletions(-) create mode 100755 topics/clustering/booting.adoc create mode 100755 topics/clustering/example.adoc create mode 100755 topics/clustering/load-balancer.adoc create mode 100755 topics/clustering/multicast.adoc create mode 100755 topics/clustering/recommended.adoc create mode 100755 topics/clustering/serialized.adoc create mode 100755 topics/clustering/troubleshooting.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 78ba824229..c1b51f5bed 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -31,6 +31,13 @@ .. link:topics/network/https.adoc[HTTPS/SSL Setup] .. link:topics/network/outgoing.adoc[Outgoing HTTP Requests] . link:topics/clustering.adoc[Clustering] + .. link:topics/clustering/recommended.adoc[Recommended Network Architecture] + .. link:topics/clustering/load-balancer.adoc[Setting Up a Load Balancer] + .. link:topics/clustering/multicast.adoc[Multicast Network Setup] + .. link:topics/clustering/serialized.adoc[Serialized Cluster Startup] + .. link:topics/clustering/booting.adoc[Booting the Cluster] + .. link:topics/clustering/example.adoc[Cluster Example] + .. link:topics/clustering/troubleshooting.adoc[Trouble Shooting] . link:topics/cache.adoc[Server Cache Configuration] {% if book.community %} . link:topics/proxy.adoc[Keycloak Security Proxy] diff --git a/book.json b/book.json index 17294e0256..ff4653fb7c 100755 --- a/book.json +++ b/book.json @@ -30,6 +30,14 @@ "socket": { "name": "JBoss EAP Administration and Configuration Guide", "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/sect-Socket_Binding_Groups.html" + }, + "loadbalancer": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/sect-Web_HTTP_Connectors_and_HTTP_Clustering.html" + }, + "jgroups": { + "name": "JBoss EAP Administration and Configuration Guide", + "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/sect-JGroups.html" } }, "caching": { @@ -49,6 +57,10 @@ } }, + "adminguide": { + "name": "Keycloak Adminstration Guide", + "link": "https://keycloak.gitbooks.io/server-adminstration-guide/content/" + } "project": { "name": "Keycloak", "version": "1.9.3.Final-SNAPSHOT" diff --git a/topics/clustering.adoc b/topics/clustering.adoc index c430f17040..b57b67ce1c 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -1,154 +1,18 @@ [[_clustering]] == Clustering -Keycloak doesn't replicate realms and users, but instead relies on all nodes using the same database. -This can be a relational database or Mongo. -To make sure your database doesn't become a single point of failure you may also want to deploy your database to a cluster. +This section covers some of the aspects of configuring {{book.project.name}} to run in a cluster. There's a number +of things you have to do to provide and prepare for to run in a cluster, specifically: -[[_clustering_db_lock]] -=== DB lock +* <> +* <> +* Setting up a load balancer +* Supplying a private network that supports IP multicast -Note that Keycloak supports concurrent startup by more cluster nodes at the same. -This is ensured by DB lock, which prevents that some startup actions (migrating database from previous version, importing realms at startup, initial bootstrap of admin user) are always executed just by one cluster node at a time and other cluster nodes need to wait until the current node finishes startup actions and release the DB lock. +Picking an operation mode and configuring a shared database have been discussed earlier in this guide. In this chapter +we'll discuss setting up a load balancer and supplying a private network. We'll also discuss some issues around +when bringing up a cluster. -By default, the maximum timeout for lock is 900 seconds, so in case that second node is not able to acquire the lock within 900 seconds, it fails to start. -The lock checking is done every 2 seconds by default. -Typically you won't need to increase/decrease the default value, but just in case it's possible to configure it in `standalone/configuration/keycloak-server.json`: +Note: It is possible to cluster {{book.project.name}} without IP Multicast, but this topic is beyond the + scope of this guide. Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. -[source,json] ----- -"dblock": { - "jpa": { - "lockWaitTimeout": 900, - "lockRecheckTime": 2 - } -} ----- -or similarly if you're using Mongo (just by replace `jpa` with `mongo`) - -=== Configure Infinispan - -Keycloak uses http://www.infinispan.org/[Infinispan] caches to share information between nodes. - -For realm and users Keycloak uses a invalidation cache. -An invalidation cache doesn't share any data, but simply removes stale data from remote caches and makes sure all nodes re-load data from the database when it is changed. -This reduces network traffic, as well as preventing sensitive data (such as realm keys and password hashes) from being sent between the nodes. - -User sessions and login failures supports either distributed caches or fully replicated caches. -We recommend using a distributed cache. -A distributed cache splits user sessions into segments where each node holds one or more segment. -It is possible to replicate each segment to multiple nodes, but this is not strictly necessary since the failure of a node will only result in users having to log in again. -If you need to prevent node failures from requiring users to log in again, set the `owners` attribute to 2 or more for the `sessions` cache of `infinispan/Keycloak` container as described below. - -The infinispan container is set by default in `standalone/configuration/keycloak-server.json`: - -[source,json] ----- - -"connectionsInfinispan": { - "default" : { - "cacheContainer" : "java:jboss/infinispan/Keycloak" - } -} ----- - -As you can see in this file, the realmCache, userCache and userSession providers are configured to use infinispan by default, which applies for both cluster and non-cluster environment. - -For non-cluster configuration (server executed with `standalone.xml` ) is the infinispan container `infinispan/Keycloak` just uses local infinispan caches for realms, users and userSessions. - -For cluster configuration, you can edit the configuration of `infinispan/Keycloak` container in `standalone/configuration/standalone-ha.xml` (or `standalone-keycloak-ha.xml` if you are using overlay or demo distribution) . - -=== Start in HA mode - -To start the server in HA mode, start it with: - -[source] ----- -# bin/standalone --server-config=standalone-ha.xml ----- -or if you are using overlay or demo distribution with: - -[source] ----- -# bin/standalone --server-config=standalone-keycloak-ha.xml ----- - -Alternatively you can copy `standalone/config/standalone-ha.xml` to `standalone/config/standalone.xml` to make it the default server config. - -=== Enabling cluster security - -By default there's nothing to prevent unauthorized nodes from joining the cluster and sending potentially malicious messages to the cluster. -However, as there's no sensitive data sent there's not much that can be achieved. -For realms and users all that can be done is to send invalidation messages to make nodes load data from the database more frequently. -For user sessions it would be possible to modify existing user sessions, but creating new sessions would have no affect as they would not be linked to any access tokens. -There's not too much that can be achieved by modifying user sessions. -For example it would be possible to prevent sessions from expiring, by changing the creation time. -However, it would for example have no effect adding additional permissions to the sessions as these are rechecked against the user and application when the token is created or refreshed. - -In either case your cluster nodes should be in a private network, with a firewall protecting them from outside attacks. -Ideally isolated from workstations and laptops. -You can also enable encryption of cluster messages, this could for example be useful if you can't isolate cluster nodes from workstations and laptops on your private network. -However, encryption will obviously come at a cost of reduced performance. - -To enable encryption of cluster messages you first have to create a shared keystore (change the key and store passwords!): - -[source] ----- - -# keytool -genseckey -alias keycloak -keypass -storepass \ - -keyalg Blowfish -keysize 56 -keystore defaultStore.keystore -storetype JCEKS ----- - -Copy this keystore to all nodes (for example to standalone/configuration). Then configure JGroups to encrypt all messages by adding the `ENCRYPT` protocol to the JGroups sub-system (this should be added after the `pbcast.GMS` protocol): - -[source] ----- - - - ... - - - - ${jboss.server.config.dir}/defaultStore.keystore - - PASSWORD - PASSWORD - keycloak - - ... - - - ... - - - - ${jboss.server.config.dir}/defaultStore.keystore - - PASSWORD - PASSWORD - keycloak - - ... - - ... - ----- -See the http://www.jgroups.org/manual/index.html#ENCRYPT[JGroups manual] for more details. - -=== Troubleshooting - -Note that when you run cluster, you should see message similar to this in the log of both cluster nodes: - -[source] ----- -INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-10,shared=udp) -ISPN000094: Received new cluster view: [node1/keycloak|1] (2) [node1/keycloak, node2/keycloak] ----- -If you see just one node mentioned, it's possible that your cluster hosts are not joined together. - -Usually it's best practice to have your cluster nodes on private network without firewall for communication among them. -Firewall could be enabled just on public access point to your network instead. -If for some reason you still need to have firewall enabled on cluster nodes, you will need to open some ports. -Default values are UDP port 55200 and multicast port 45688 with multicast address 230.0.0.4. -Note that you may need more ports opened if you want to enable additional features like diagnostics for your JGroups stack. -Keycloak delegates most of the clustering work to Infinispan/JGroups, so consult EAP or JGroups documentation for more info. diff --git a/topics/clustering/booting.adoc b/topics/clustering/booting.adoc new file mode 100755 index 0000000000..31ff5ab75a --- /dev/null +++ b/topics/clustering/booting.adoc @@ -0,0 +1,17 @@ +=== Booting the Cluster + +Booting {{book.project.name}} in a cluster depends on your <> + +.Standalone Mode +[source] +---- +$ bin/standalone.sh --server-config=standalone-ha.xml +---- + +.Domain Mode +[source] +---- +$ bin/domain.sh --host-config=host-master.xml +$ bin/domain.sh --host-config=host-slave.xml +---- + diff --git a/topics/clustering/example.adoc b/topics/clustering/example.adoc new file mode 100755 index 0000000000..cb3b18a5ee --- /dev/null +++ b/topics/clustering/example.adoc @@ -0,0 +1,5 @@ +=== Clustering Example + +{{book.project.name}} does come with an out of the box clustering demo that leverages domain mode. Review the +<> chapter for more details. + diff --git a/topics/clustering/load-balancer.adoc b/topics/clustering/load-balancer.adoc new file mode 100755 index 0000000000..fbd8ef0f47 --- /dev/null +++ b/topics/clustering/load-balancer.adoc @@ -0,0 +1,6 @@ +=== Setting Up a Load Balancer + +This guide does not go over how to set up a load balancer as it is already documented in detail within the +link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}}. It will +involve configuring the <> and <> discussed in previous chapters in this guide. + diff --git a/topics/clustering/multicast.adoc b/topics/clustering/multicast.adoc new file mode 100755 index 0000000000..0a882f0c31 --- /dev/null +++ b/topics/clustering/multicast.adoc @@ -0,0 +1,35 @@ +=== Multicast Network Setup + +Out of the box clustering support has a need to for IP Multicast. Multicast is a network broadcast protocol. This protocol +is used at boot time to discover and join the cluster. It is also used to broadcast message for the replication and invalidation +distributed caches used by {{book.project.name}}. + +The clustering subsystem for {{book.project.name}} runs on the JGroups stack. Out of the box, the bind addresses for clustering are bound to a private network interface with a default IP address of 127.0.0.1. +You'll have to edit your the _standalone-ha.xml_ or _domain.xml_ sections discussed in <> + +.private network config +[source,xml] +---- + + ... + + + + + + ... + + + + + + + ... + +---- + +Things you'll want to configure are the +jboss.bind.address.private+ and +jboss.default.multicast.address+ as well as the ports of the services on the clustering stack. +Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. + +Note: It is possible to cluster {{book.project.name}} without IP Multicast, but this topic is beyond the + scope of this guide. Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. diff --git a/topics/clustering/recommended.adoc b/topics/clustering/recommended.adoc new file mode 100755 index 0000000000..86c6ea2716 --- /dev/null +++ b/topics/clustering/recommended.adoc @@ -0,0 +1,9 @@ +=== Recommended Network Architecture + +The recommended network architecture for deploying {{book.project.name}} is to set up an HTTP/HTTPS load balancer on +a public IP address and network routing requests to {{book.project.name}} servers sitting on a private network. This +isolates all clustering connections and provides a nice means of protecting the servers. + +By default, there is nothing to prevent unauthorized nodes from joining the cluster and broadcasting multicast messages. +This is why cluster nodes should be in a private network, with a firewall protecting them from outside attacks. + diff --git a/topics/clustering/serialized.adoc b/topics/clustering/serialized.adoc new file mode 100755 index 0000000000..b7ae718da0 --- /dev/null +++ b/topics/clustering/serialized.adoc @@ -0,0 +1,23 @@ +[[_clustering_db_lock]] +=== Serialized Cluster Startup + +Note that {{book.project.name}} supports concurrent startup by more cluster nodes at the same. +When {{book.project.name}} boots up it may do some database migration, importing, or first time initializations. The server +makes use of a DB lock which prevents these startup actions from running and conflicting with eachother when nodes are +booted concurrently. + +By default, the maximum timeout for lock is 900 seconds, so in case that second node is not able to acquire the lock within 900 seconds, it fails to start. +The lock checking is done every 2 seconds by default. +Typically you won't need to increase/decrease the default value, but just in case it's possible to configure it in `keycloak-server.json`: + +[source,json] +---- +"dblock": { + "jpa": { + "lockWaitTimeout": 900, + "lockRecheckTime": 2 + } +} +---- +or similarly if you're using Mongo (just by replace `jpa` with `mongo`) + diff --git a/topics/clustering/troubleshooting.adoc b/topics/clustering/troubleshooting.adoc new file mode 100755 index 0000000000..b8dc7bb0b3 --- /dev/null +++ b/topics/clustering/troubleshooting.adoc @@ -0,0 +1,17 @@ +=== Troubleshooting + +Note that when you run cluster, you should see message similar to this in the log of both cluster nodes: + +[source] +---- +INFO [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (Incoming-10,shared=udp) +ISPN000094: Received new cluster view: [node1/keycloak|1] (2) [node1/keycloak, node2/keycloak] +---- +If you see just one node mentioned, it's possible that your cluster hosts are not joined together. + +Usually it's best practice to have your cluster nodes on private network without firewall for communication among them. +Firewall could be enabled just on public access point to your network instead. +If for some reason you still need to have firewall enabled on cluster nodes, you will need to open some ports. +Default values are UDP port 55200 and multicast port 45688 with multicast address 230.0.0.4. +Note that you may need more ports opened if you want to enable additional features like diagnostics for your JGroups stack. +{{book.project.name}} delegates most of the clustering work to Infinispan/JGroups. Please consult the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}. diff --git a/topics/network/bind-address.adoc b/topics/network/bind-address.adoc index dc6bdfdda6..9a76aaa45a 100755 --- a/topics/network/bind-address.adoc +++ b/topics/network/bind-address.adoc @@ -1,3 +1,5 @@ +[[_bind-address]] + === Bind Addresses By default {{book.project.name}} binds to the localhost loopback address 127.0.0.1. That's not a very useful default if diff --git a/topics/network/ports.adoc b/topics/network/ports.adoc index 41ae8c324d..794afb649d 100755 --- a/topics/network/ports.adoc +++ b/topics/network/ports.adoc @@ -1,3 +1,5 @@ +[[_ports]] + === Socket Port Bindings The ports for each socket also have a pre-defined default that can be overriden at the command line or within configuration. diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 768078f916..899ea07227 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -172,7 +172,7 @@ $ .../bin/domain.sh --host-config=host-master.xml When running the boot script you will need pass in the host controlling configuration file you are going to use via the +--host-config+ switch. - +[[_clustered-domain-example]] ==== Running the Clustered Domain Example The example domain that comes with {{book.project.name}} was meant to run on one machine. It starts a: From 6ebde6a65877e50e09fd34eb69e6b5a059d3e645 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 18:28:37 -0400 Subject: [PATCH 076/149] more --- SUMMARY.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index c1b51f5bed..177d98a9e6 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -42,6 +42,6 @@ {% if book.community %} . link:topics/proxy.adoc[Keycloak Security Proxy] {% endif %} - . link:topics/migration.adoc[Upgrading and Migrating] + . link:topics/migration.adoc[Importing and Exporting the Database] From 0ec8d42af46c09fd06509e2970005a49c9715385 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 18:29:40 -0400 Subject: [PATCH 077/149] more --- topics/clustering/troubleshooting.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/topics/clustering/troubleshooting.adoc b/topics/clustering/troubleshooting.adoc index b8dc7bb0b3..48136012e8 100755 --- a/topics/clustering/troubleshooting.adoc +++ b/topics/clustering/troubleshooting.adoc @@ -14,4 +14,5 @@ Firewall could be enabled just on public access point to your network instead. If for some reason you still need to have firewall enabled on cluster nodes, you will need to open some ports. Default values are UDP port 55200 and multicast port 45688 with multicast address 230.0.0.4. Note that you may need more ports opened if you want to enable additional features like diagnostics for your JGroups stack. -{{book.project.name}} delegates most of the clustering work to Infinispan/JGroups. Please consult the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}. +{{book.project.name}} delegates most of the clustering work to Infinispan/JGroups. +Please consult the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. From 7bcdba8259d38668734f691402727c4a34b3649c Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 18:38:20 -0400 Subject: [PATCH 078/149] more --- topics/clustering/multicast.adoc | 2 +- topics/clustering/serialized.adoc | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/topics/clustering/multicast.adoc b/topics/clustering/multicast.adoc index 0a882f0c31..614a416be7 100755 --- a/topics/clustering/multicast.adoc +++ b/topics/clustering/multicast.adoc @@ -5,7 +5,7 @@ is used at boot time to discover and join the cluster. It is also used to broad distributed caches used by {{book.project.name}}. The clustering subsystem for {{book.project.name}} runs on the JGroups stack. Out of the box, the bind addresses for clustering are bound to a private network interface with a default IP address of 127.0.0.1. -You'll have to edit your the _standalone-ha.xml_ or _domain.xml_ sections discussed in <> +You'll have to edit your the _standalone-ha.xml_ or _domain.xml_ sections discussed in the <> chapter. .private network config [source,xml] diff --git a/topics/clustering/serialized.adoc b/topics/clustering/serialized.adoc index b7ae718da0..f88a1c3f0b 100755 --- a/topics/clustering/serialized.adoc +++ b/topics/clustering/serialized.adoc @@ -19,5 +19,8 @@ Typically you won't need to increase/decrease the default value, but just in cas } } ---- -or similarly if you're using Mongo (just by replace `jpa` with `mongo`) + +{% if book.community %} +If you are using Mongo DB replace `jpa` with `mongo`. +{% endif %} From fc396031e99ff34860646a8ccced1e8ca1f359e4 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 18:39:37 -0400 Subject: [PATCH 079/149] more --- book.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book.json b/book.json index ff4653fb7c..aaf7386316 100755 --- a/book.json +++ b/book.json @@ -60,7 +60,7 @@ "adminguide": { "name": "Keycloak Adminstration Guide", "link": "https://keycloak.gitbooks.io/server-adminstration-guide/content/" - } + }, "project": { "name": "Keycloak", "version": "1.9.3.Final-SNAPSHOT" From 6ace795d4ed6ebb23db65d3c73f5534d057880c7 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 19:31:06 -0400 Subject: [PATCH 080/149] cache --- SUMMARY.adoc | 5 ++- book.json | 3 +- topics/cache.adoc | 64 +++++++---------------------------- topics/cache/clear.adoc | 5 +++ topics/cache/disable.adoc | 25 ++++++++++++++ topics/cache/eviction.adoc | 52 ++++++++++++++++++++++++++++ topics/cache/replication.adoc | 21 ++++++++++++ 7 files changed, 121 insertions(+), 54 deletions(-) create mode 100755 topics/cache/clear.adoc create mode 100755 topics/cache/disable.adoc create mode 100755 topics/cache/eviction.adoc create mode 100755 topics/cache/replication.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 177d98a9e6..caa976b65b 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -39,9 +39,12 @@ .. link:topics/clustering/example.adoc[Cluster Example] .. link:topics/clustering/troubleshooting.adoc[Trouble Shooting] . link:topics/cache.adoc[Server Cache Configuration] + .. link:topics/cache/eviction.adoc[Eviction Policy and Max Entries] + .. link:topics/cache/replication.adoc[Replication and Failover] + .. link:topics/cache/disable.adoc[Disabling Caching] + .. link:topics/cache/clear.adoc[Clearing Caches at Runtime] {% if book.community %} . link:topics/proxy.adoc[Keycloak Security Proxy] {% endif %} - . link:topics/migration.adoc[Importing and Exporting the Database] diff --git a/book.json b/book.json index aaf7386316..3be9cf7d4a 100755 --- a/book.json +++ b/book.json @@ -45,7 +45,8 @@ "version": "???", "admindoc": { "name": "JBoss Data Grid Administration and Configuration Guide", - "link": "https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Data_Grid/6.6/html/Administration_and_Configuration_Guide/index.html" + "link": "https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Data_Grid/6.6/html/Administration_and_Configuration_Guide/index.html", + "eviction": "https://access.redhat.com/documentation/en-US/Red_Hat_JBoss_Data_Grid/7.0/html/Administration_and_Configuration_Guide/sect-Eviction_Strategies.html" } }, "jpa": { diff --git a/topics/cache.adoc b/topics/cache.adoc index c4e0293594..14417d77f2 100755 --- a/topics/cache.adoc +++ b/topics/cache.adoc @@ -1,58 +1,18 @@ -== Server Cache +== Server Cache Configuration -By default, Keycloak caches realm metadata and users. -There are two separate caches, one for realm metadata (realm, application, client, roles, etc...) and one for users. -These caches greatly improves the performance of the server. +{{book.project.name}} has two types of caches. One type of cache sits in front of the database to decrease load on the DB +and to increase overall response times by keeping data in memory. Realm, client, role, and user metadata is kept in this cache. +The caching for this data is stored in something called an invalidation cache. Invalidation caches do not use replication. +Instead, they only keep copies locally and if the entry is updated an invalidation message is sent to the rest of the cluster +and the entry is evicted. This greatly reduces network traffic, makes things efficient, and avoids transmitting sensitive +metadata over the ire. -=== Eviction and Expiration +The second type of cache handles managing user sessions, offline tokens, and keeping track of login failures so that the +server can detect password phishing and other attacks. The data held in these caches is temporary, in memory only, +but is possibly replicated across the cluster. -By default the user cache contains a maximum of 10000 entries. -This is not 10000 users, but 10000 entries in the cache. -You can change the maximum number of entries by editing the server configuration `standalone.xml` or `standalone-ha.xml`. -Locate the element `cache-container name="keycloak"` and change the eviction policy for the `users` cache. -For more information see https://docs.jboss.org/author/display/WFLY10/Infinispan+Subsystem[Infinispan Subsystem documentation]. +This chapter discusses some configuration options for these caches for both clustered a non-clustered deployments. -=== Disabling Caches - -To disable the realm or user cache, you must edit the `keycloak-server.json` file in your distribution. -Here's what the config looks like initially. +Note: More advanced configuration of these caches can be found in link:{{book.caching.admindoc.link}}[{{book.caching.admindoc.name}}] -[source] ----- - - "userCache": { - "infinispan" : { - "enabled": true - } - }, - - "realmCache": { - "infinispan" : { - "enabled": true - } - }, ----- - -To disable the cache set the enabled field to false for the cache you want to disable: -[source] ----- - - "userCache": { - "infinispan" : { - "enabled": false - } - }, - - "realmCache": { - "infinispan" : { - "enabled": false - } - }, ----- - -=== Clear Caches - -To clear the realm or user cache, go to the Keycloak admin console Realm Settings->Cache Config page. -On this page you can clear the realm cache or the user cache. -This will clear the caches for all realms and not only the selected realm. diff --git a/topics/cache/clear.adoc b/topics/cache/clear.adoc new file mode 100755 index 0000000000..a69d971abb --- /dev/null +++ b/topics/cache/clear.adoc @@ -0,0 +1,5 @@ +=== Clearing Caches at Runtime + +To clear the realm or user cache, go to the {{book.project.name}} admin console Realm Settings->Cache Config page. +On this page you can clear the realm cache or the user cache. +This will clear the caches for all realms and not only the selected realm. diff --git a/topics/cache/disable.adoc b/topics/cache/disable.adoc new file mode 100755 index 0000000000..06ca4efcef --- /dev/null +++ b/topics/cache/disable.adoc @@ -0,0 +1,25 @@ +=== Disabling Caching + +To disable the realm or user cache, you must edit the `keycloak-server.json` file in your distribution. Where +this file lives depends on your <> +Here's what the config looks like initially. + + +[source,json] +---- + + "userCache": { + "infinispan" : { + "enabled": true + } + }, + + "realmCache": { + "infinispan" : { + "enabled": true + } + }, +---- + +To disable the cache set the +enabled+ field to false for the cache you want to disable. You must reboot your +server for this change to take effect. diff --git a/topics/cache/eviction.adoc b/topics/cache/eviction.adoc new file mode 100755 index 0000000000..76ce029ba8 --- /dev/null +++ b/topics/cache/eviction.adoc @@ -0,0 +1,52 @@ +=== Eviction and Expiration + +There is a realm cache that holds information about secured applications, general security data, and configuration options. +This cache is unbounded and does not have a limit on entries. This might scare you a little bit, but the number of entries +in this cache is pretty low compared to the user cache. There is a user cache that contains user metadata. It defaults to a maximum of 10000 entries and uses a least recently used eviction strategy. +There are also separate caches for user sessions, offline tokens, and login failures. These caches are unbounded as well. + +The eviction policy and max entries for these caches can be configured in the _standalone.xml_, _standalone-ha.xml_, or +_domain.xml_ depending on your <>. + +.non-clustered +[source,xml] +---- + + + + + + + + + + + + + + +---- + + +.non-clustered +[source,xml] +---- + + + + + + + + + + + + + + + +---- + +To limit to expand the number of entries simply add, edit, or remove the +eviction+ element from the +invalidation-cache+ or ++distributed-cache+ eviction policy you want to change. diff --git a/topics/cache/replication.adoc b/topics/cache/replication.adoc new file mode 100755 index 0000000000..a1e4f46452 --- /dev/null +++ b/topics/cache/replication.adoc @@ -0,0 +1,21 @@ +=== Replication and Failover + +The +sessions+, +offlineSessions+ and +loginFailures+ caches are distributed caches which means that one more nodes +is designated as the owner of a specific cache entry. If a node is not the owner of a specific cache entry it queries +the cluster to obtain it. What this means for failover is that if the nodes that own a piece of data go down, that data +is lost forever. By default, {{book.project.name}} only specifies one owner for data. So if that one node goes down +that data is lost. This usually means that users will be logged out and will have to login again. + +You can change the number of nodes that replicate a piece of data by change the +owners+ attribute in the +distributed-cache+ declaration + +.owners +[source,xml] +---- + + + +... +---- + +Here's we've changed it so at least two nodes will replicate one specific user login session. + From f45ef1efec2cfb8214e011aa428e2addc8ca7731 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 28 Apr 2016 19:34:34 -0400 Subject: [PATCH 081/149] cache --- topics/cache/eviction.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topics/cache/eviction.adoc b/topics/cache/eviction.adoc index 76ce029ba8..8514fdf221 100755 --- a/topics/cache/eviction.adoc +++ b/topics/cache/eviction.adoc @@ -28,7 +28,7 @@ _domain.xml_ depending on your < From eca440d1e77bd13856edbf133dae975bf113eea4 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 29 Apr 2016 12:09:09 -0400 Subject: [PATCH 082/149] 2nd draft --- SUMMARY.adoc | 1 - book.json | 9 ++- topics/database/datasource.adoc | 12 ++-- topics/database/hibernate.adoc | 4 +- topics/database/jdbc.adoc | 24 +++---- topics/installation.adoc | 5 +- topics/installation/directory-structure.adoc | 8 +-- .../distribution-files-community.adoc | 6 +- .../distribution-files-product.adoc | 4 +- topics/installation/system-requirements.adoc | 6 +- topics/operating-mode.adoc | 3 +- topics/operating-mode/domain.adoc | 71 ++++++++++++++----- topics/operating-mode/standalone-ha.adoc | 16 ++--- topics/operating-mode/standalone.adoc | 10 +-- topics/overview/recommended-reading.adoc | 4 +- topics/preface.adoc | 22 ------ 16 files changed, 108 insertions(+), 97 deletions(-) delete mode 100755 topics/preface.adoc diff --git a/SUMMARY.adoc b/SUMMARY.adoc index caa976b65b..261b65eb07 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,6 +1,5 @@ = Summary - . link:topics/preface.adoc[Preface] . link:topics/overview.adoc[Overview] .. link:topics/overview/recommended-reading.adoc[Recommended Reading] . link:topics/installation.adoc[Installation] diff --git a/book.json b/book.json index 3be9cf7d4a..fe5534d5bf 100755 --- a/book.json +++ b/book.json @@ -13,8 +13,8 @@ "product": false, "images": "keycloak-images", "appserver": { - "name": "JBoss EAP", - "version": "6.4", + "name": "Wildfly", + "version": "10", "admindoc": { "name": "JBoss EAP Administration and Configuration Guide", "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Administration_and_Configuration_Guide/" @@ -57,6 +57,11 @@ "link": "https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.4/html/Development_Guide/sect-Java_Persistence_API_JPA.html#sect-Configuration2" } + }, + "developerguide": { + "name": "Keycloak Server Developer Guide", + "link": "https://keycloak.gitbooks.io/server-developer-guide/content/" + }, "adminguide": { "name": "Keycloak Adminstration Guide", diff --git a/topics/database/datasource.adoc b/topics/database/datasource.adoc index 4f7963b5eb..cae5634492 100755 --- a/topics/database/datasource.adoc +++ b/topics/database/datasource.adoc @@ -1,8 +1,8 @@ === Modify the {{book.project.name}} Datasource After declaring your JDBC driver, you have to modify the existing datasource configuration that {{book.project.name}} uses -to connect to the built-in embedded database. You'l need to change it to connect to your new external database. You'll do -this within the same configuration file and XML block that you registered your JDBC driver. Here's an example +to connect it to your new external database. You'll do +this within the same configuration file and XML block that you registered your JDBC driver in. Here's an example that set's up the connection to your new database: .Declare Your JDBC Drivers @@ -27,8 +27,8 @@ that set's up the connection to your new database: ---- -Search for the +datasource+ definition for +KeycloakDS+. You'll first need to specify the +connection-url+. The -documentation for your vendor's JDBC implementation will tell you the connection URL you should provide there. +Search for the +datasource+ definition for +KeycloakDS+. You'll first need to modify the +connection-url+. The +documentation for your vendor's JDBC implementation should specify the format for this connection URL value. Next define the +driver+ you will use. This is the logical name of the JDBC driver you declared in the previous section of this chapter. @@ -37,10 +37,10 @@ It is expensive to open a new connection to a database ever time you want to per implementation maintains a pool of open connections. The +max-pool-size+ specifies the maximum number of connections it will pool. You may want to change the value of this depending on the load of your system. -Finally, or PostgreSQL at least, you need to define the database username and password that is needed to connect to the database. You +Finally, with PostgreSQL at least, you need to define the database username and password that is needed to connect to the database. You may be worried that this is in clear text in the example. There are methods to obfuscate this, but this is beyond the scope of this guide. NOTE: For more information and details features of datasources, please see the link:{{book.appserver.datasource.link}}[the datasource configuration chapter] -of the {{book.appserver.admindoc.name}}. + of the {{book.appserver.admindoc.name}}. diff --git a/topics/database/hibernate.adoc b/topics/database/hibernate.adoc index d5e0615454..22dfb5fdc1 100755 --- a/topics/database/hibernate.adoc +++ b/topics/database/hibernate.adoc @@ -1,7 +1,7 @@ === Hibernate Configuration -The Hibernate persistence API is already pre-configured out of the box. It is rare to have to modify the configuration for it. -To configure Hibernate, you need to edit the _keycloak-server.json_ file. If you are running +The Hibernate persistence API is already pre-configured out of the box and rarely needs to be changed. +The configuration for this component lies in the _keycloak-server.json_ file. If you are running in standalone mode, this file is in the _.../standalone/configuration_ directory. If you are running in domain mode this file will live in the _.../domain/servers/{server name}/configuration_ directory. diff --git a/topics/database/jdbc.adoc b/topics/database/jdbc.adoc index b264ad18f6..09c37cf2c5 100755 --- a/topics/database/jdbc.adoc +++ b/topics/database/jdbc.adoc @@ -1,13 +1,14 @@ === Package the JDBC Driver -Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module. +Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module +and install it into the server. Modules define JARs that are loaded into the {{book.project.name}} classpath and the dependencies those JARs have on other modules. They are pretty simple to set up. Within the _.../modules/system/layers/keycloak/_ directory of your {{book.project.name}} distribution, you need to create a directory structure to hold your module definition. The convention is use the Java package name of the JDBC driver for the name of the directory structure. For PostgreSQL, create the directory _org/postgresql/main_. Copy your database -driver JAR into this directory and also create an empty _module.xml_ file. +driver JAR into this directory and create an empty _module.xml_ file within it too. .Module Directory image:../../{{book.images}}/db-module.png[] @@ -32,28 +33,20 @@ After you have done this, open up the _module.xml_ file and create the following ---- The module name should match the directory structure of your module. So, _org/postgresql_ maps to +org.postgresql+. The -+resource-root path+ attribute should specify the JAR filename. The rest are just the normal dependencies that ++resource-root path+ attribute should specify the JAR filename of the driver. The rest are just the normal dependencies that any JDBC driver JAR would have. === Declare and Load JDBC Driver The next thing you have to do is declare your newly packaged JDBC driver into your deployment profile so that it loads and becomes -available. Where you perform this action depends on your <>. If you're +available when the server boots up. Where you perform this action depends on your <>. If you're deploying in standard mode, edit _.../standalone/configuration/standalone.xml_. If you're deploying in standard clustering mode, edit _.../standalone/configuration/standalone-ha.xml_. If you're deploying in domain mode, edit -_.../domain/configuration/domain.xml_. In domain mode, you'll need to make sure you edit the profile you are using: +_.../domain/configuration/domain.xml_. In domain mode, you'll need to make sure you edit the profile you are using: either +auth-server-standalone+ or +auth-server-clustered+ -.Domain Profile -[source,xml] ----- - - ... - ----- - Within the profile, search for the +drivers+ XML block within the +datasources+ subsystem. You should see -a pre-defined driver declared for the H2 JDBC driver. There is where you'll declare the JDBC driver for your external +a pre-defined driver declared for the H2 JDBC driver. This is where you'll declare the JDBC driver for your external database. .JDBC Drivers @@ -72,7 +65,8 @@ database. ---- Within the +drivers+ XML block you'll need to declare an additional JDBC driver. It needs to have a +name+ which -you can choose to be anything you want. You have to define the module the new JDBC driver classes are defined in. Finally +you can choose to be anything you want. You specify the +module+ attribute which points to the +module+ package you +created earlier for the driver JAR. Finally you have to specify the driver's Java class. Here's an example of installing PostgreSQL driver that lives in the module example defined earlier in this chapter. diff --git a/topics/installation.adoc b/topics/installation.adoc index a2f982f931..289e0ec6ed 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -1,5 +1,4 @@ == Installation -This chapter reviews what binaries you need to install to run the {{book.project.name}} Server on a specific machine. -It describes the directory structure and files of the distribution. Finally, it describes how to install {{book.project.name}} -on the cloud if you prefer that type of deployment. \ No newline at end of file +Installing {{book.project.name}} is as simple as downloading it and unzipping it. This chapter reviews system requirements +as well as the directory structure of the distribution. \ No newline at end of file diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 1e640f5e51..15f902467b 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -11,20 +11,20 @@ _bin/_:: This contains various scripts to either boot the server or perform some other management action on the server. _domain/_:: - This contains configuration files and working directory when running {{book.project.name}} in <>. + This contains configuration files and working directory when running {{book.project.name}} in <>. _modules/_:: These are all the Java libraries used by the server. _providers/_:: - If you are writing extensions to keycloak, you can put your extensions here. See the link:http://not-implemented-yet[Server Developer Guide] for more information on this. + If you are writing extensions to keycloak, you can put your extensions here. See the link:{{book.developerguide.link}}[{{book.developerguide.name] for more information on this. _standalone/_:: - This contains configuration files and working directory when running {{book.project.name}} in <>. + This contains configuration files and working directory when running {{book.project.name}} in <>. _themes/_:: This directory contains all the html, style sheets, javascript files, and images used to display any UI screen displayed by the server. - Here you can modify an existing theme or create your own. See the link:http://not-implemented-yet[Server Developer Guide] for more information on this. + Here you can modify an existing theme or create your own. See the link:{{book.developerguide.link}}[{{book.developerguide.name] for more information on this. diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 94762043f2..881b5d96e2 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -10,13 +10,13 @@ The 'keycloak-{{book.project.version}}.[zip|tar.gz]' file is the server only dis to run the Keycloak Server. To unpack this file just run your operating system's +unzip+ or +gunzip+ and +tar+ utilities. The 'keycloak-overlay-{{book.project.version}}.[zip|tar.gz]' file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing -Wildfly or JBoss EAP distribution. We suggest that you do not use this file unless you want to install on top of a JBoss EAP distribution. We do not support +Wildfly or JBoss EAP distribution. We suggest that you do not use this distribution unless you want to install on top of the latest JBoss EAP distribution. We do not support users that want to run their applications and Keycloak on the same server instance. To install the Keycloak Service Pack, just unzip it in the root directory of your JBoss EAP distribution. -The 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' contains a the server binaries, all documentation and all examples. It is preconfigured with both the +The 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' contains the server binaries, all documentation and all examples. It is preconfigured with both the OIDC and SAML client application adapters and can deploy any of the distribution examples out of the box with no configuration. This distribution is only -recommended for those that want to test drive Keycloak. +recommended for those that want to test drive Keycloak. We do not support users that run the demo distribution in production. To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc index c81e06ccff..d1b1aa9da6 100755 --- a/topics/installation/distribution-files-product.adoc +++ b/topics/installation/distribution-files-product.adoc @@ -1,11 +1,11 @@ === Installing Distribution Files -The Keycloak Server is contained in one distribution file: +The {{book.project.name}} Server is contained in one distribution file: * 'RH-SSO-{{book.project.version}}.[zip|tar.gz]' The 'RH-SSO-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries -to run the Keycloak Server. +to run the {{book.project.name}} Server. To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index 49b2a3f1ef..a19a7b7306 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -7,9 +7,9 @@ These are the requirements to run the {{book.project.name}} authentication serve * zip or gzip and tar * At least 512M of RAM * At least 1G of diskspace -* Network multicast support on your machine if you want to run in a cluster out of the box. {{book.project.name}} can - be clustered without multicast, but this requires a bunch of configuration changes. Please see - the <> section of this guide for more information. * A shared external database like Postgres, MySql, Oracle, etc. {{book.project.name}} requires an external shared database if you want to run in a cluster. Please see the <> section of this guide for more information. +* Network multicast support on your machine if you want to run in a cluster. {{book.project.name}} can + be clustered without multicast, but this requires a bunch of configuration changes. Please see + the <> section of this guide for more information. diff --git a/topics/operating-mode.adoc b/topics/operating-mode.adoc index bdd87b7f10..2f0acd744f 100755 --- a/topics/operating-mode.adoc +++ b/topics/operating-mode.adoc @@ -4,8 +4,7 @@ Before deploying {{book.project.name}} in a production environment you need to decide which type of operating mode you are going to use. Will you run {{book.project.name}} within a cluster? Do you want a centralized way to manage -your server configurations? This is where deciding the operating mode comes in. This decision - effects how you configure databases, configure caching and even how you boot the server. +your server configurations? Your choice of operating mode effects how you configure databases, configure caching and even how you boot the server. TIP: The {{book.project.name}} is built on top of the {{book.appserver.name}} Application Server. This guide will only go over the basics for deployment within a specific mode. If you want specific information on this, a better place diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 899ea07227..645986f652 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -1,6 +1,8 @@ [[_domain-mode]] === Domain Clustered Mode +Domain mode is a way to centrally manage and publish the configuration for your servers. + Running a cluster in standard mode can quickly become aggravating as the cluster grows in size. Every time you need to make a configuration change, you have perform it on each node in the cluster. Domain mode solves this problem by providing a central place to store and publish configuration. It can be quite complex to set up, but it is worth it in the end. @@ -46,11 +48,11 @@ where the domain profile and server group for the {{book.project.name}} server a .domain.xml image:../../{{book.images}}/domain-file.png[] -NOTE: Any changes you make to this file while the domain controller is running will not take effect and may even be overwritten +WARNING: Any changes you make to this file while the domain controller is running will not take effect and may even be overwritten by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. -Let's look at some aspects of this _domain.xml_ file. The +auth-server+ +profile+ XML block is where you are going to make the bulk of your configuration decisions. +Let's look at some aspects of this _domain.xml_ file. The +auth-serve-standalone+ and +auth-server-clustered+ +profile+ XML block is where you are going to make the bulk of your configuration decisions. You'll be configuring things here like network connections, caches, and database connections. @@ -58,12 +60,36 @@ You'll be configuring things here like network connections, caches, and database [source,xml] ---- - + + ... + + ... ---- -The +ha-sockets+ +socket-binding-group+ defines the default port mappings for various connectors that are opened with each +The +auth-server-standalone+ profile is a non-clustered setup. The +auth-server-clustered+ profile is the clustered setup. + +If you scroll down further, you'll see various +socket-binding-groups+ defined. + +.socket-binding-grous +[source,xml] +---- + + + ... + + + ... + + + + ... + + ---- + + +This config defines the default port mappings for various connectors that are opened with each {{book.project.name}} server instance. Any value that contains +${...}+ is a value that can be overriden on the command line with the +-D+ switch, i.e. @@ -79,7 +105,14 @@ binds a +socket-binding-group+ to the server group. [source,xml] ---- - + + + + + + + + @@ -97,8 +130,9 @@ _host-master.xml_ and _host-slave.xml_. _host-master.xml_ is configured to boot one {{book.project.name}} server instance. _host-slave.xml_ is configured to talk to the domain controller and boot up one {{book.project.name}} server instance. -NOTE: You should remove the load balancer server from _host-master.xml_. The load balancer included is really not that - production ready and doesn't work as smoothly as something like Apache HTTPD + mod-cluster or a hardward based one. +NOTE: The load balancer is not a required service. It exists so that you can easily test drive clustering on your development + machine. While usable in production, you have the option of replacing it if you have a different hardware or software + based load balancer you want to use. .Host Controller Config image:../../{{book.images}}/host-files.png[] @@ -152,7 +186,7 @@ image:../../{{book.images}}/domain-json-config.png[] When running the server in domain mode, there is a specific script you need to run to boot the server depending on your operating system. These scripts live in the _bin/_ directory of the server distribution. -.Standalone Boot Scripts +.Domain Boot Script image:../../{{book.images}}/domain-boot-files.png[] To boot the server: @@ -173,22 +207,25 @@ When running the boot script you will need pass in the host controlling configur +--host-config+ switch. [[_clustered-domain-example]] -==== Running the Clustered Domain Example +==== Clustered Domain Example -The example domain that comes with {{book.project.name}} was meant to run on one machine. It starts a: -* domain controller -* HTTP load balancer +You can test drive clustering using the out-of-the-box _domain.xml_ configuration. This example +domain is meant to run on one machine and boots up: + +* a domain controller +* an HTTP load balancer * 2 {{book.project.name}} server instances To simulate running a cluster on two machines, you'll run the +domain.sh+ script twice to start two separate -host controllers. The first will be the master host controller. It start a domain controller, an HTTP load balancer, and one +host controllers. The first will be the master host controller which will start a domain controller, an HTTP load balancer, and one {{book.project.name}} authentication server instance. The second will be a slave host controller that only starts up an authentication server instance. -===== Setup Secure Master Slave Connection +===== Setup Slave Connection to Domain Controller Before you can boot things up though, you have to configure the slave host controller so that it can talk securely to the domain -controller to obtain the centralized configuration. To set up a secure connection, you have to create a server admin user and a secret that +controller. If you do not do this, then the slave host will not be able to obtain the centralized configuration from the domain controller. +To set up a secure connection, you have to create a server admin user and a secret that will be shared between the master and the slave. You do this by running the +.../bin/add-user.sh+ script. When you run the script select +Management User+ and answer +yes+ when it asks you if the new user is going to be used @@ -225,7 +262,7 @@ $ add-user.sh To represent the user add the following to the server-identities definition ---- -Now cut and paste the secret value into the _.../domain/configuration/host-slave.xml_ file: +Now cut and paste the secret value into the _.../domain/configuration/host-slave.xml_ file as follows: [source,xml] ---- @@ -239,7 +276,7 @@ Now cut and paste the secret value into the _.../domain/configuration/host-slave ===== Run the Boot Scripts -Since we're simulating running on two separate machines, you'll run the boot script twice: +Since we're simulating a two node cluster on one development machine, you'll run the boot script twice: .Boot up master [source,shell] diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc index 07fde37123..a57988c492 100755 --- a/topics/operating-mode/standalone-ha.adoc +++ b/topics/operating-mode/standalone-ha.adoc @@ -3,14 +3,14 @@ === Standalone Clustered Mode Standalone clustered operation mode is for when you want to run {{book.project.name}} within a cluster. This mode -requires that you have a copy of each distribution for each node you want to run in the cluster. While very easy to -deploy initially, this mode can become cumbersome if you end up having a large cluster because you will have to -modify the configuration in each node anytime you need to make a change. +requires that you have a copy of the {{book.project.name}} distribution on each machine you want to run a server instance. +This mode can be very easy to deploy initially, but can become quite cumbersome. To make a configuration change +you'll have to modify each distribution on each machine. For a large cluster this can become time consuming and error prone. ==== Standalone Clustered Configuration The distribution has a mostly pre-configured app server configuration file for running within a cluster. It has all the specific -infrasture settings you need to configure networking, databases, caches, and discovery. This file resides +infrastructure settings for networking, databases, caches, and discovery. This file resides in _.../standalone/configuration/standalone-ha.xml_. There's a few things missing from this configuration. You can't run {{book.project.name}} in a cluster without a configuring a shared database connection. You also need to deploy some type of load balancer in front of the cluster. The <> and @@ -19,11 +19,11 @@ deploy some type of load balancer in front of the cluster. The < Date: Fri, 29 Apr 2016 16:12:12 -0400 Subject: [PATCH 083/149] 2nd draft --- SUMMARY.adoc | 2 +- topics/cache.adoc | 4 +- topics/cache/disable.adoc | 2 +- topics/cache/eviction.adoc | 11 ++- topics/cache/replication.adoc | 11 ++- topics/clustering.adoc | 14 +-- topics/clustering/load-balancer.adoc | 91 ++++++++++++++++++- topics/clustering/multicast.adoc | 6 +- topics/clustering/recommended.adoc | 6 +- topics/clustering/serialized.adoc | 11 +-- topics/database/datasource.adoc | 6 +- topics/database/hibernate.adoc | 4 +- topics/database/jdbc.adoc | 12 +-- .../distribution-files-community.adoc | 4 +- .../distribution-files-product.adoc | 2 +- topics/manage.adoc | 6 +- topics/mongo.adoc | 2 +- topics/network.adoc | 8 +- topics/network/bind-address.adoc | 28 +++--- topics/network/https.adoc | 31 ++++--- topics/network/outgoing.adoc | 50 +++++----- topics/network/ports.adoc | 24 ++--- topics/operating-mode/domain.adoc | 30 +++--- 23 files changed, 226 insertions(+), 139 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 261b65eb07..88d775e501 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -31,11 +31,11 @@ .. link:topics/network/outgoing.adoc[Outgoing HTTP Requests] . link:topics/clustering.adoc[Clustering] .. link:topics/clustering/recommended.adoc[Recommended Network Architecture] + .. link:topics/clustering/example.adoc[Cluster Example] .. link:topics/clustering/load-balancer.adoc[Setting Up a Load Balancer] .. link:topics/clustering/multicast.adoc[Multicast Network Setup] .. link:topics/clustering/serialized.adoc[Serialized Cluster Startup] .. link:topics/clustering/booting.adoc[Booting the Cluster] - .. link:topics/clustering/example.adoc[Cluster Example] .. link:topics/clustering/troubleshooting.adoc[Trouble Shooting] . link:topics/cache.adoc[Server Cache Configuration] .. link:topics/cache/eviction.adoc[Eviction Policy and Max Entries] diff --git a/topics/cache.adoc b/topics/cache.adoc index 14417d77f2..3ab0ebcad9 100755 --- a/topics/cache.adoc +++ b/topics/cache.adoc @@ -1,8 +1,8 @@ == Server Cache Configuration {{book.project.name}} has two types of caches. One type of cache sits in front of the database to decrease load on the DB -and to increase overall response times by keeping data in memory. Realm, client, role, and user metadata is kept in this cache. -The caching for this data is stored in something called an invalidation cache. Invalidation caches do not use replication. +and to increase overall response times by keeping data in memory. Realm, client, role, and user metadata is kept in this type of cache. +This cache is an invalidation cache. Invalidation caches do not use replication. Instead, they only keep copies locally and if the entry is updated an invalidation message is sent to the rest of the cluster and the entry is evicted. This greatly reduces network traffic, makes things efficient, and avoids transmitting sensitive metadata over the ire. diff --git a/topics/cache/disable.adoc b/topics/cache/disable.adoc index 06ca4efcef..72d856edb3 100755 --- a/topics/cache/disable.adoc +++ b/topics/cache/disable.adoc @@ -21,5 +21,5 @@ Here's what the config looks like initially. }, ---- -To disable the cache set the +enabled+ field to false for the cache you want to disable. You must reboot your +To disable the cache set the `enabled` field to false for the cache you want to disable. You must reboot your server for this change to take effect. diff --git a/topics/cache/eviction.adoc b/topics/cache/eviction.adoc index 8514fdf221..152165dabb 100755 --- a/topics/cache/eviction.adoc +++ b/topics/cache/eviction.adoc @@ -1,9 +1,10 @@ === Eviction and Expiration +There are multiple different caches configured for {{book.project.name}}. There is a realm cache that holds information about secured applications, general security data, and configuration options. -This cache is unbounded and does not have a limit on entries. This might scare you a little bit, but the number of entries -in this cache is pretty low compared to the user cache. There is a user cache that contains user metadata. It defaults to a maximum of 10000 entries and uses a least recently used eviction strategy. -There are also separate caches for user sessions, offline tokens, and login failures. These caches are unbounded as well. +This size of this cache is unbounded and does not have a limit on entries. This might scare you a little bit, but the number of entries +in this cache is pretty low compared to the user cache. There is also a user cache that contains user metadata. It defaults to a maximum of 10000 entries and uses a least recently used eviction strategy. +There are also separate caches for user sessions, offline tokens, and login failures. These caches are unbounded in size as well. The eviction policy and max entries for these caches can be configured in the _standalone.xml_, _standalone-ha.xml_, or _domain.xml_ depending on your <>. @@ -48,5 +49,5 @@ _domain.xml_ depending on your < ---- -To limit to expand the number of entries simply add, edit, or remove the +eviction+ element from the +invalidation-cache+ or -+distributed-cache+ eviction policy you want to change. +To limit or expand the number of allowed entries simply add, edit, or remove the `eviction` element from the `invalidation-cache` or +`distributed-cache` declaration you want to change. diff --git a/topics/cache/replication.adoc b/topics/cache/replication.adoc index a1e4f46452..b07fc812ec 100755 --- a/topics/cache/replication.adoc +++ b/topics/cache/replication.adoc @@ -1,12 +1,12 @@ === Replication and Failover -The +sessions+, +offlineSessions+ and +loginFailures+ caches are distributed caches which means that one more nodes -is designated as the owner of a specific cache entry. If a node is not the owner of a specific cache entry it queries -the cluster to obtain it. What this means for failover is that if the nodes that own a piece of data go down, that data +The `sessions`, `offlineSessions` and `loginFailures` caches are the only caches that may perform replication. Entries are +not replicated to every single node, but instead one or more nodes is chosen as an owner of that data. If a node is not the owner of a specific cache entry it queries +the cluster to obtain it. What this means for failover is that if all the nodes that own a piece of data go down, that data is lost forever. By default, {{book.project.name}} only specifies one owner for data. So if that one node goes down that data is lost. This usually means that users will be logged out and will have to login again. -You can change the number of nodes that replicate a piece of data by change the +owners+ attribute in the +distributed-cache+ declaration +You can change the number of nodes that replicate a piece of data by change the `owners` attribute in the `distributed-cache` declaration. .owners [source,xml] @@ -19,3 +19,6 @@ You can change the number of nodes that replicate a piece of data by change the Here's we've changed it so at least two nodes will replicate one specific user login session. +TIP: The number of owners recommended is really dependent on your deployment. If you do not care if users are logged + out when a node goes down, then one owner is good enough and you will avoid replication. + diff --git a/topics/clustering.adoc b/topics/clustering.adoc index b57b67ce1c..323b2c20c4 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -1,17 +1,17 @@ [[_clustering]] == Clustering -This section covers some of the aspects of configuring {{book.project.name}} to run in a cluster. There's a number -of things you have to do to provide and prepare for to run in a cluster, specifically: +This section covers configuring {{book.project.name}} to run in a cluster. There's a number +of things you have to do when setting up a cluster, specifically: -* <> -* <> -* Setting up a load balancer +* <> +* <> +* Set up a load balancer * Supplying a private network that supports IP multicast Picking an operation mode and configuring a shared database have been discussed earlier in this guide. In this chapter -we'll discuss setting up a load balancer and supplying a private network. We'll also discuss some issues around -when bringing up a cluster. +we'll discuss setting up a load balancer and supplying a private network. We'll also discuss some issues that you need +to be aware of when booting up a host in the cluster. Note: It is possible to cluster {{book.project.name}} without IP Multicast, but this topic is beyond the scope of this guide. Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. diff --git a/topics/clustering/load-balancer.adoc b/topics/clustering/load-balancer.adoc index fbd8ef0f47..119c797e69 100755 --- a/topics/clustering/load-balancer.adoc +++ b/topics/clustering/load-balancer.adoc @@ -1,6 +1,91 @@ === Setting Up a Load Balancer -This guide does not go over how to set up a load balancer as it is already documented in detail within the -link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}}. It will -involve configuring the <> and <> discussed in previous chapters in this guide. +This section only covers configuring the built in load balancer that is discussed in the +<>. +The link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}} +has some information on using some other software based load balancers that may help you. + +The <> is only designed to run +on one machine. To bring up a slave on another host, you'll need to + +. Edit the _domain.xml_ file to point to your new host slave +. Copy the server distribution. You don't need the _domain.xml_, _host.xml_, or _host-master.xml_ files. Nor do you need + the _standalone/_ directory. +. Edit the _host-slave.xml_ file to change the bind addresses used or override them on the command line + +==== Register a New Host With Load Balancer + +Let's look first at registering the new host slave with the load balancer configuration in _domain.xml_. Open this +file and go to the undertow configuration in the `load-balancer` profile. Add a new `host` definition called +`remote-host3` within the `reverse-proxy` XML block. + +.domain.xml reverse-proxy config +[source,xml] +---- + + ... + + + + + + + + ... + +---- + +The `output-socket-binding` is a logical name pointing to a `socket-binding` configured later in the _domain.xml_ file. +the `instance-id` attribute must also be unique to the new host as this value is used by a cookie to enable sticky +sessions when load balancing. + +Next go down to the `load-balancer-sockets` `socket-binding-group` and add the `outbound-socket-binding` for `remote-host3`. This new +binding needs to point to the host and port of the new host. + +.domain.xml outbound-socket-binding +[source,xml] +---- + + ... + + + + + + + + + + +---- + +=== Master Bind Addresses + +Next thing you'll have to do is to change the `public` and `management` bind addresses for the master host. Either +edit the _domain.xml_ file as discussed in the <> chapter +or specify these bind addresses on the command line as follows: + +[source] +---- +$ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2 +---- + +=== Host Slave Bind Addresses + +Next you'll have to change the `public`, `management`, and domain controller bind addresses (`jboss.domain.master-address`). Either edit the +_host-slave.xml_ file or specify them on the command line as follows: + +[source] +---- +$ domain.sh --host-config=host-slave.xml + -Djboss.bind.address=192.168.0.5 + -Djboss.bind.address.management=192.168.0.5 + -Djboss.domain.master.address=192.168.0.2 +---- + +The values of `jboss.bind.address` and `jboss.bind.addres.management` pertain to the host slave's IP address. +The value of `jboss.domain.master.address` need to be the IP address of the domain controller which is the management address +of the master host. + + diff --git a/topics/clustering/multicast.adoc b/topics/clustering/multicast.adoc index 614a416be7..6702eeef16 100755 --- a/topics/clustering/multicast.adoc +++ b/topics/clustering/multicast.adoc @@ -1,7 +1,7 @@ === Multicast Network Setup Out of the box clustering support has a need to for IP Multicast. Multicast is a network broadcast protocol. This protocol -is used at boot time to discover and join the cluster. It is also used to broadcast message for the replication and invalidation +is used at boot time to discover and join the cluster. It is also used to broadcast messages for the replication and invalidation distributed caches used by {{book.project.name}}. The clustering subsystem for {{book.project.name}} runs on the JGroups stack. Out of the box, the bind addresses for clustering are bound to a private network interface with a default IP address of 127.0.0.1. @@ -28,8 +28,8 @@ You'll have to edit your the _standalone-ha.xml_ or _domain.xml_ sections discus ---- -Things you'll want to configure are the +jboss.bind.address.private+ and +jboss.default.multicast.address+ as well as the ports of the services on the clustering stack. -Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. +Things you'll want to configure are the `jboss.bind.address.private` and `jboss.default.multicast.address` as well as the ports of the services on the clustering stack. +Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}} for more details. Note: It is possible to cluster {{book.project.name}} without IP Multicast, but this topic is beyond the scope of this guide. Please see the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. diff --git a/topics/clustering/recommended.adoc b/topics/clustering/recommended.adoc index 86c6ea2716..1b5ae0d05f 100755 --- a/topics/clustering/recommended.adoc +++ b/topics/clustering/recommended.adoc @@ -1,9 +1,9 @@ === Recommended Network Architecture The recommended network architecture for deploying {{book.project.name}} is to set up an HTTP/HTTPS load balancer on -a public IP address and network routing requests to {{book.project.name}} servers sitting on a private network. This +a public IP address that routes requests to {{book.project.name}} servers sitting on a private network. This isolates all clustering connections and provides a nice means of protecting the servers. -By default, there is nothing to prevent unauthorized nodes from joining the cluster and broadcasting multicast messages. -This is why cluster nodes should be in a private network, with a firewall protecting them from outside attacks. +NOTE: By default, there is nothing to prevent unauthorized nodes from joining the cluster and broadcasting multicast messages. + This is why cluster nodes should be in a private network, with a firewall protecting them from outside attacks. diff --git a/topics/clustering/serialized.adoc b/topics/clustering/serialized.adoc index f88a1c3f0b..5afd9e09e7 100755 --- a/topics/clustering/serialized.adoc +++ b/topics/clustering/serialized.adoc @@ -1,13 +1,12 @@ [[_clustering_db_lock]] === Serialized Cluster Startup -Note that {{book.project.name}} supports concurrent startup by more cluster nodes at the same. -When {{book.project.name}} boots up it may do some database migration, importing, or first time initializations. The server -makes use of a DB lock which prevents these startup actions from running and conflicting with eachother when nodes are -booted concurrently. +{{book.project.name}} cluster nodes are allowed to boot concurrenty. +When {{book.project.name}} server instance boots up it may do some database migration, importing, or first time initializations. +A DB lock is used to prevent start actions from conflicting ith one another when cluster nodes boot up concurrently. -By default, the maximum timeout for lock is 900 seconds, so in case that second node is not able to acquire the lock within 900 seconds, it fails to start. -The lock checking is done every 2 seconds by default. +By default, the maximum timeout for this lock is 900 seconds. If a node is waiting on this lock for more than the timeout +it will fail to boot. This lock is checked every 2 seconds by default. Typically you won't need to increase/decrease the default value, but just in case it's possible to configure it in `keycloak-server.json`: [source,json] diff --git a/topics/database/datasource.adoc b/topics/database/datasource.adoc index cae5634492..3699c2b355 100755 --- a/topics/database/datasource.adoc +++ b/topics/database/datasource.adoc @@ -27,14 +27,14 @@ that set's up the connection to your new database: ---- -Search for the +datasource+ definition for +KeycloakDS+. You'll first need to modify the +connection-url+. The +Search for the `datasource` definition for `KeycloakDS`. You'll first need to modify the `connection-url`. The documentation for your vendor's JDBC implementation should specify the format for this connection URL value. -Next define the +driver+ you will use. This is the logical name of the JDBC driver you declared in the previous section of this +Next define the `driver` you will use. This is the logical name of the JDBC driver you declared in the previous section of this chapter. It is expensive to open a new connection to a database ever time you want to perform a transaction. To compensate, the datasource -implementation maintains a pool of open connections. The +max-pool-size+ specifies the maximum number of connections it will pool. +implementation maintains a pool of open connections. The `max-pool-size` specifies the maximum number of connections it will pool. You may want to change the value of this depending on the load of your system. Finally, with PostgreSQL at least, you need to define the database username and password that is needed to connect to the database. You diff --git a/topics/database/hibernate.adoc b/topics/database/hibernate.adoc index 22dfb5fdc1..d251ccf480 100755 --- a/topics/database/hibernate.adoc +++ b/topics/database/hibernate.adoc @@ -30,8 +30,8 @@ driverDialect:: databaseSchema:: Specify if schema should be updated or validated. - Valid values are +update+ (default) and +validate+. The +update+ value will set up or update - the table definitions that {{book.project.name}} needs. +validate+ just makes sure that the database has + Valid values are `update` (default) and `validate`. The `update` value will set up or update + the table definitions that {{book.project.name}} needs. `validate` just makes sure that the database has the appropriate table definitions set up. showSql:: diff --git a/topics/database/jdbc.adoc b/topics/database/jdbc.adoc index 09c37cf2c5..f5ef1d2114 100755 --- a/topics/database/jdbc.adoc +++ b/topics/database/jdbc.adoc @@ -32,8 +32,8 @@ After you have done this, open up the _module.xml_ file and create the following ---- -The module name should match the directory structure of your module. So, _org/postgresql_ maps to +org.postgresql+. The -+resource-root path+ attribute should specify the JAR filename of the driver. The rest are just the normal dependencies that +The module name should match the directory structure of your module. So, _org/postgresql_ maps to `org.postgresql`. The +`resource-root path` attribute should specify the JAR filename of the driver. The rest are just the normal dependencies that any JDBC driver JAR would have. === Declare and Load JDBC Driver @@ -43,9 +43,9 @@ available when the server boots up. Where you perform this action depends on yo deploying in standard mode, edit _.../standalone/configuration/standalone.xml_. If you're deploying in standard clustering mode, edit _.../standalone/configuration/standalone-ha.xml_. If you're deploying in domain mode, edit _.../domain/configuration/domain.xml_. In domain mode, you'll need to make sure you edit the profile you are using: either -+auth-server-standalone+ or +auth-server-clustered+ +`auth-server-standalone` or `auth-server-clustered` -Within the profile, search for the +drivers+ XML block within the +datasources+ subsystem. You should see +Within the profile, search for the `drivers` XML block within the `datasources` subsystem. You should see a pre-defined driver declared for the H2 JDBC driver. This is where you'll declare the JDBC driver for your external database. @@ -64,8 +64,8 @@ database. ---- -Within the +drivers+ XML block you'll need to declare an additional JDBC driver. It needs to have a +name+ which -you can choose to be anything you want. You specify the +module+ attribute which points to the +module+ package you +Within the `drivers` XML block you'll need to declare an additional JDBC driver. It needs to have a `name` which +you can choose to be anything you want. You specify the `module` attribute which points to the `module` package you created earlier for the driver JAR. Finally you have to specify the driver's Java class. Here's an example of installing PostgreSQL driver that lives in the module example defined earlier in this chapter. diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 881b5d96e2..761fbae07b 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -7,7 +7,7 @@ The Keycloak Server has three downloadable distributions: * 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' The 'keycloak-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries -to run the Keycloak Server. To unpack this file just run your operating system's +unzip+ or +gunzip+ and +tar+ utilities. +to run the Keycloak Server. To unpack this file just run your operating system's `unzip` or `gunzip` and `tar` utilities. The 'keycloak-overlay-{{book.project.version}}.[zip|tar.gz]' file is a Wildfly Service Pack that allows you to install Keycloak Server on top of an existing Wildfly or JBoss EAP distribution. We suggest that you do not use this distribution unless you want to install on top of the latest JBoss EAP distribution. We do not support @@ -18,7 +18,7 @@ The 'keycloak-demo-{{book.project.version}}.[zip|tar.gz]' contains the server bi OIDC and SAML client application adapters and can deploy any of the distribution examples out of the box with no configuration. This distribution is only recommended for those that want to test drive Keycloak. We do not support users that run the demo distribution in production. -To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. +To unpack of these files run the `unzip` or `gunzip` and `tar` utilities. diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc index d1b1aa9da6..0db0d44c2e 100755 --- a/topics/installation/distribution-files-product.adoc +++ b/topics/installation/distribution-files-product.adoc @@ -7,7 +7,7 @@ The {{book.project.name}} Server is contained in one distribution file: The 'RH-SSO-{{book.project.version}}.[zip|tar.gz]' file is the server only distribution. It contains nothing other than the scripts and binaries to run the {{book.project.name}} Server. -To unpack of these files run the +unzip+ or +gunzip+ and +tar+ utilities. +To unpack of these files run the `unzip` or `gunzip` and `tar` utilities. diff --git a/topics/manage.adoc b/topics/manage.adoc index 8f8de1f966..0325b6372d 100755 --- a/topics/manage.adoc +++ b/topics/manage.adoc @@ -9,7 +9,7 @@ how you will do this. === Start the {{books.appserver.name}} CLI -To start the {{books.appserver.name}} CLI, you need to run the +jboss-cli+ script. +To start the {{books.appserver.name}} CLI, you need to run the `jboss-cli` script. .Linux/Unix [source] @@ -33,7 +33,7 @@ This will bring you to a prompt like this: There's a few commands you can execute without a running standalone server or domain controller, but usually you will have to have those services booted up before you can execute CLI commands. To connect to a running server simply -execute the +connect+ command. +execute the `connect` command. .connect [source] @@ -43,7 +43,7 @@ connect [domain@localhost:9990 /] ---- -You may be thinking to yourself, "I didn't enter in any username or password!". If you run +jboss-cli+ on the same machine +You may be thinking to yourself, "I didn't enter in any username or password!". If you run `jboss-cli` on the same machine as your running standalone server or domain controller and your account has appropriate file permissions, you do not have to setup or enter in a admin username and password. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more details on how to make things more secure if you are uncomfortable with that setup. diff --git a/topics/mongo.adoc b/topics/mongo.adoc index 332b545cf6..b572d23b69 100755 --- a/topics/mongo.adoc +++ b/topics/mongo.adoc @@ -3,7 +3,7 @@ == Mongo DB Setup You are not stuck with using a RDBMS for persisting data. {{book.project.name}} -provides http://www.mongodb.com[MongoDB] based model implementation. +provides a http://www.mongodb.com[MongoDB] based model implementation. To configure {{book.project.name}} to use Mongo, you need to edit the _keycloak-server.json_ file. If you are running in standalone mode, this file is in the _.../standalone/configuration_ directory. If you are running in domain mode this file will live in the _.../domain/servers/{server name}/configuration_ directory. diff --git a/topics/network.adoc b/topics/network.adoc index 9f08ab53ac..5b73d20178 100755 --- a/topics/network.adoc +++ b/topics/network.adoc @@ -2,12 +2,12 @@ == Network Setup -{{book.project.name}} can run out of the box, with some limitations. For one, all network endpoints bind to +localhost+ +{{book.project.name}} can run out of the box with some networking limitations. For one, all network endpoints bind to `localhost` so the auth server is really only usable on one local machine. For HTTP based connections, it does not use default ports -like 80 and 443. The SSO protocols that {{book.project.name}} uses all require -SSL/HTTPS or otherwise these protocols have some serious vulnerabilities. HTTPS/SSL is not configured out of the box. +like 80 and 443. HTTPS/SSL is not configured out of the box and without it, {{book.project.name}} has many security +vulnerabilities. Finally, {{book.project.name}} -may often need to make secure SSL connections to external servers and thus need a trust store set up so that endpoints can +may often need to make secure SSL and HTTPS connections to external servers and thus need a trust store set up so that endpoints can be validated correctly. This chapter discusses all of these things. diff --git a/topics/network/bind-address.adoc b/topics/network/bind-address.adoc index 9a76aaa45a..b542be25f0 100755 --- a/topics/network/bind-address.adoc +++ b/topics/network/bind-address.adoc @@ -2,12 +2,12 @@ === Bind Addresses -By default {{book.project.name}} binds to the localhost loopback address 127.0.0.1. That's not a very useful default if +By default {{book.project.name}} binds to the localhost loopback address `127.0.0.1`. That's not a very useful default if you want the authentication server available on your network. Generally, what we recommend is that you deploy a reverse proxy or load balancer on a public network and route traffic to individual {{book.project.name}} server instances on a private network. -In either case though, you still need to set up your network interfaces to bind to something other than +localhost+. +In either case though, you still need to set up your network interfaces to bind to something other than `localhost`. -Setting the bind address is actually quite easy and can be done on the command line with either the _standalone.sh_ or +Setting the bind address is quite easy and can be done on the command line with either the _standalone.sh_ or _domain.sh_ boot scripts discussed in the <> chapter. [source] @@ -15,11 +15,11 @@ _domain.sh_ boot scripts discussed in the <> and look for the interfaces XML block. +Alternatively, if you don't want to set the bind address at the command line, you can edit the profile configuration of your deployment. +Open up the profile configuration file (_standalone.xml or _domain.xml_ depending on your +<> and look for the `interfaces` XML block. [source,xml] ---- @@ -33,21 +33,21 @@ every time you boot the server. Open up the profile configuration file (_standa ---- -The +public+ interface corresponds to subsystems creating sockets that are available publically. An example of one -of these subsystems is the web layer which serves up the authentication endpoints of {{book.project.name}}. The +management+ +The `public` interface corresponds to subsystems creating sockets that are available publicly. An example of one +of these subsystems is the web layer which serves up the authentication endpoints of {{book.project.name}}. The `management` interface corresponds to sockets opened up by the management layer of the {{book.appserver.name}}. Specifically the sockets -which allow you to use the +jboss-cli.sh+ command line interface and the {{book.appserver.name}} web console. +which allow you to use the `jboss-cli.sh` command line interface and the {{book.appserver.name}} web console. -In looking at the +public+ interface you see that it has a special string +${jboss.bind.address:127.0.0.1}+. This string -denotes a value +127.0.0.1+ that can be overriden on the command line by setting a Java system property, i.e.: +In looking at the `public` interface you see that it has a special string `${jboss.bind.address:127.0.0.1}`. This string +denotes a value `127.0.0.1` that can be overriden on the command line by setting a Java system property, i.e.: [source] ---- $ domain.sh -Djboss.bind.address=192.168.0.5 ---- -+-b+ is actually just a convenience function for this. So, you can either change the bind address value directly in the profile config, or change it on the command line when +The `-b` is just a shorthand notation for this command. So, you can either change the bind address value directly in the profile config, or change it on the command line when you boot up. -NOTE: There's a lot more nifty options when setting up +interface+ definitions. See the link:{{book.appserver.network.link}}[the network interface] +NOTE: There's a lot more nifty options when setting up `interface` definitions. See the link:{{book.appserver.network.link}}[the network interface] chapter of the {{book.appserver.network.name}}. diff --git a/topics/network/https.adoc b/topics/network/https.adoc index 854f7df037..30cdd83083 100755 --- a/topics/network/https.adoc +++ b/topics/network/https.adoc @@ -10,7 +10,7 @@ This default behavior is defined by the SSL/HTTPS mode of each {{book.project.na link:{{book.adminguide.link}}[{{book.adminguide.name}}], but let's give some context and a brief overview of these modes. external:: - {{book.project.name}} can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. + {{book.project.name}} can run out of the box without SSL so long as you stick to private IP addresses like `localhost`, `127.0.0.1`, `10.0.x.x`, `192.168.x.x`, and `172..16.x.x`. If you try to access {{book.project.name}} from a non-private IP adress you will get an error. none:: @@ -19,23 +19,24 @@ none:: all:: {{book.project.name}} requires SSL for all IP addresses. +The SSL mode for each realm can be configured in the {{book.project.name}} admin console. + ==== Enable HTTPS/SSL with a Reverse Proxy -It is believed that most deployments of {{book.project.name}} will be clustered and will use a reverse proxy or load balancer -in front of {{book.project.name}} server instances. +It is general best practice that {{book.project.name}} will be run in a cluster with a reverse proxy or hardware load balancer +setting in front of {{book.project.name}} server instances. -To enable SSL/HTTPS in this deployment scenario, follow the documentation for your reverse proxy first, before doing any {{book.project.name}} setup. -It is important that you make sure the proxy sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to {{book.project.name}}. -Next you need to enable `proxy-address-forwarding` on the {{book.project.name}} http connector in {{book.project.name}} configuration +To enable SSL/HTTPS in this deployment scenario, it is important that you make sure your reverse proxy sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to {{book.project.name}}. +To make sure that {{book.project.name}} honors these headers, you need to enable the `proxy-address-forwarding` setting of the {{book.project.name}} http connector in {{book.project.name}} configuration. Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. . Open _standalone.xml_, _standalone-ha.xml_, or _domain.xml_ file (depends on your <>). -. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: +. Add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: [source] ---- - + ... @@ -56,12 +57,12 @@ Then add a new `socket-binding` element to the `socket-binding-group` element: ---- -Also remember that when running in <> what +socket-binding-group+ +Also remember that when running in <> what `socket-binding-group` you modify depends on how you have your server groups configured. ==== Enabling SSL/HTTPS for the {{book.project.name}} Server -If you are not using a reverse proxy or load blancer to handle HTTPS traffic for you, you'll need to enable HTTPS +If you are not using a reverse proxy or load balancer to handle HTTPS traffic for you, you'll need to enable HTTPS for the {{book.project.name}} server. This involves . Obtaining or generating a keystore that contains the private key and certificate for SSL/HTTP traffic @@ -73,8 +74,8 @@ In order to allow HTTPS connections, you need to obtain a self signed or third-p ====== Self Signed Certificate -In development, you will probably not have a third party signed certificate available to test a {{book.project.name}} deployment so you'll need to generate a self-signed on. -Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. +In development, you will probably not have a third party signed certificate available to test a {{book.project.name}} deployment so you'll need to generate a self-signed one +using the `keytool` utility that comes with the Java JDK. [source] @@ -125,7 +126,7 @@ MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 -29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as +29RvyeUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i @@ -148,7 +149,7 @@ You can download the cert from CA (ie.: root.crt) and import as follows: $ keytool -import -keystore keycloak.jks -file root.crt -alias root ---- -Last step is import your new CA generated certificate to your keystore: +Last step is to import your new CA generated certificate to your keystore: [source] ---- @@ -159,7 +160,7 @@ $ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificat ===== Configure {{book.project.name}} to Use the Keystore Now that you have a Java keystore with the appropriate certificates, you need to configure your {{book.project.name}} installation to use it. -First step is to move the keystore file to the _configuration_ directory of your deployment and to edit the _standalone.xml_, _standalone-ha.xml_ or _domain.xml_ file to use +First step is to move the keystore file to the _configuration/_ directory of your deployment and to edit the _standalone.xml_, _standalone-ha.xml_ or _domain.xml_ file to use the keystore and enable HTTPS. (See <>). In the standalone or domain configuration file, search for the `security-realms` element and add: diff --git a/topics/network/outgoing.adoc b/topics/network/outgoing.adoc index 35bd16b67a..97c3bbd169 100755 --- a/topics/network/outgoing.adoc +++ b/topics/network/outgoing.adoc @@ -1,11 +1,11 @@ === Outgoing HTTP Requests -The {{book.project.name}} server often needs to invoke non-browser HTTP requests on the applications and services it secures. -The auth server manages these outgoing connections by maintaining an HTTP client connection pool. There are a few settings -of which you should be aware of. These settings live in the file _keycloak-server.json_ _keycloak-server.json_ file that corresponds to your <> +The {{book.project.name}} server often needs to make non-browser HTTP requests to the applications and services it secures. +The auth server manages these outgoing connections by maintaining an HTTP client connection pool. There are some thing +you'll need to configure in the _keycloak-server.json_. Where this file lives depends on your <> -By default the setting is like this: +.keycloak-server.json HTTP client Config [source,json] ---- "connectionsHttpClient": { @@ -32,7 +32,7 @@ connection-ttl-millis:: max-connection-idle-time-millis:: Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. - Set to -1 to disable this checking and the background thread. + Set to -`1` to disable this checking and the background thread. disable-cookies:: `true` by default. @@ -47,25 +47,31 @@ client-keystore-password:: This is _REQUIRED_ if `client-keystore` is set. client-key-password:: - _Not supported yet, but we will support in future versions. Password for the client's key. + Password for the client's key. This is _REQUIRED_ if `client-keystore` is set. [[_truststore]] ==== Outgoing HTTPS Request Truststore -When {{book.project.name}} connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. -This is necessary in order to prevent man-in-the-middle attacks. +When {{book.project.name}} invokes on remote HTTPS endpoints, it has to validate the remote server's certificate in order to ensure it is connecting to a trusted server. +This is necessary in order to prevent man-in-the-middle attacks. The certificates of these remote server's or the CA that signed these +certificates must be put in a truststore. This truststore is managed by the {{book.project.name}} server. -How certificates are validated is also configured in the _keycloak-server.json_ file that corresponds to your <>. +The truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. -`standalone/configuration/keycloak-server.json`. -By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ - Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. +WARNING: By default, a truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in + https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[Java's JSSE Reference Guide]. If there is no trust + establised, then these outgoing HTTPS requests will fail. -Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. -Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. -The default JavaMail API implementation used to send out emails behaves in this way, for example. +You can use _keytool_ to create a new truststore file or add trusted host certificates to an existing one: +[source] +---- + +$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer +---- + +The truststore is configured within the_keycloak-server.json_ file. The location of this file depends on your <>. You can add your truststore configuration by using the following template: [source] @@ -81,14 +87,14 @@ You can add your truststore configuration by using the following template: } ---- -Possible configuration options are: +Possible configuration options for this setting are: file:: - The value is the file path to a Java keystore file. + The path to a Java keystore file. HTTPS requests need a way to verify the host of the server they are talking to. This is what the trustore does. The keystore contains one or more trusted host certificates or certificate authorities. - Truststore file should only contain public certificates of your secured hosts. + This truststore file should only contain public certificates of your secured hosts. This is _REQUIRED_ if `disabled` is not true. password:: @@ -105,11 +111,3 @@ disabled:: If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. If set to false, you must configure `file`, and `password` for the truststore. -You can use _keytool_ to create a new truststore file and add trusted host certificates to it: - -[source] ----- - -$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer ----- - diff --git a/topics/network/ports.adoc b/topics/network/ports.adoc index 794afb649d..8d9aea288d 100755 --- a/topics/network/ports.adoc +++ b/topics/network/ports.adoc @@ -2,9 +2,9 @@ === Socket Port Bindings -The ports for each socket also have a pre-defined default that can be overriden at the command line or within configuration. +The ports opened for each socket have a pre-defined default that can be overriden at the command line or within configuration. To illustrate this configuration, let's pretend you are running in <> and -open up the _.../standalone/configuration/standalone.xml_. Search for +socket-binding-group+. +open up the _.../standalone/configuration/standalone.xml_. Search for `socket-binding-group`. [source,xml] ---- @@ -22,22 +22,22 @@ open up the _.../standalone/configuration/standalone.xml_. Search for +socket-b ---- -+socket-bindings+ define actual socket connections that will be open by the server that covers both the +interface+ (bind address) -that will be used as wel as the port. The ones you will be most interested in are +`socket-bindings` define socket connections that will be opened by the server. These bindings specify the +`interface` (bind address) they use as well as what port number they will open. The ones you will be most interested in are: http:: - Defines the port used by {{book.project.name}} HTTP connections + Defines the port used for {{book.project.name}} HTTP connections https:: - Defines the port used by {{book.project.name}} HTTPS connections + Defines the port used for {{book.project.name}} HTTPS connections ajp:: - The Apache HTTPD server is often used with _mod-cluster_ as a load balancer. AJP is the protocol that is used. - This socket binding defines the port used for the AJP protocol. + This socket binding defines the port used for the AJP protocol. This protocol is used by Apache HTTPD server + in conjunction `mod-cluster` when you are using Apache HTTPD as a load balancer. management-http:: Defines the HTTP connection used by {{book.appserer.name}} CLI and web console. -When running in <> locking the socket configurations -is a bit trickier as the example _domain.xml_ file has multiple +socket-binding-groups+ defined. If you scroll down -to the +server-group+ definitions you can see what +socket-binding-group+ is used for each +server-group+. +When running in <> setting the socket configurations +is a bit trickier as the example _domain.xml_ file has multiple `socket-binding-groups` defined. If you scroll down +to the `server-group` definitions you can see what `socket-binding-group` is used for each `server-group`. .domain socket bindings [source,xml] @@ -54,6 +54,6 @@ to the +server-group+ definitions you can see what +socket-binding-group+ is use ---- -NOTE: There's a lot more nifty options when setting up +socket-binding-group+ definitions. See the link:{{book.appserver.socket.link}}[the socket binding group] +NOTE: There's a lot more nifty options when setting up `socket-binding-group` definitions. See the link:{{book.appserver.socket.link}}[the socket binding group] chapter of the {{book.appserver.socket.name}}. diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 645986f652..6b3050805c 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -52,7 +52,7 @@ WARNING: Any changes you make to this file while the domain controller is runnin by the server. Instead use the the command line scripting or the web console of {{book.appserver.name}}. See the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] for more information. -Let's look at some aspects of this _domain.xml_ file. The +auth-serve-standalone+ and +auth-server-clustered+ +profile+ XML block is where you are going to make the bulk of your configuration decisions. +Let's look at some aspects of this _domain.xml_ file. The `auth-serve-standalone` and `auth-server-clustered` `profile` XML block is where you are going to make the bulk of your configuration decisions. You'll be configuring things here like network connections, caches, and database connections. @@ -68,9 +68,9 @@ You'll be configuring things here like network connections, caches, and database ---- -The +auth-server-standalone+ profile is a non-clustered setup. The +auth-server-clustered+ profile is the clustered setup. +The `auth-server-standalone` profile is a non-clustered setup. The `auth-server-clustered` profile is the clustered setup. -If you scroll down further, you'll see various +socket-binding-groups+ defined. +If you scroll down further, you'll see various `socket-binding-groups` defined. .socket-binding-grous [source,xml] @@ -90,16 +90,16 @@ If you scroll down further, you'll see various +socket-binding-groups+ defined. This config defines the default port mappings for various connectors that are opened with each -{{book.project.name}} server instance. Any value that contains +${...}+ is a value that can be overriden on the command line -with the +-D+ switch, i.e. +{{book.project.name}} server instance. Any value that contains `${...}` is a value that can be overriden on the command line +with the `-D` switch, i.e. ---- $ domain.sh -Djboss.http.port=80 ---- -The definition of the server group for {{book.project.name}} resides in the +server-groups+ XML block. It specifies the domain profile -that is used (+default+) and also some default boot arguments for the Java VM when the host controller boots an instance. It also -binds a +socket-binding-group+ to the server group. +The definition of the server group for {{book.project.name}} resides in the `server-groups` XML block. It specifies the domain profile +that is used (`default`) and also some default boot arguments for the Java VM when the host controller boots an instance. It also +binds a `socket-binding-group` to the server group. .server group [source,xml] @@ -137,7 +137,7 @@ NOTE: The load balancer is not a required service. It exists so that you can e .Host Controller Config image:../../{{book.images}}/host-files.png[] -To disable the load balancer server instance, edit _host-master.xml_ and comment out or remove the +"load-balancer"+ entry. +To disable the load balancer server instance, edit _host-master.xml_ and comment out or remove the `"load-balancer"` entry. [source,xml] ---- @@ -149,8 +149,8 @@ To disable the load balancer server instance, edit _host-master.xml_ and comment ---- Another interesting thing to note about this file is the declaration of the authentication server instance. It has -a +port-offset+ setting. Any network port defined in the _domain.xml_ +socket-binding-group+ or the server group -will have the value of +port-offset+ added to it. For this example domain setup we do this so that ports opened by +a `port-offset` setting. Any network port defined in the _domain.xml_ `socket-binding-group` or the server group +will have the value of `port-offset` added to it. For this example domain setup we do this so that ports opened by the load balancer server don't conflict with the authentication server instance that is started. [source,xml] @@ -204,7 +204,7 @@ $ .../bin/domain.sh --host-config=host-master.xml ---- When running the boot script you will need pass in the host controlling configuration file you are going to use via the -+--host-config+ switch. +`--host-config` switch. [[_clustered-domain-example]] ==== Clustered Domain Example @@ -216,7 +216,7 @@ domain is meant to run on one machine and boots up: * an HTTP load balancer * 2 {{book.project.name}} server instances -To simulate running a cluster on two machines, you'll run the +domain.sh+ script twice to start two separate +To simulate running a cluster on two machines, you'll run the `domain.sh` script twice to start two separate host controllers. The first will be the master host controller which will start a domain controller, an HTTP load balancer, and one {{book.project.name}} authentication server instance. The second will be a slave host controller that only starts up an authentication server instance. @@ -226,9 +226,9 @@ up an authentication server instance. Before you can boot things up though, you have to configure the slave host controller so that it can talk securely to the domain controller. If you do not do this, then the slave host will not be able to obtain the centralized configuration from the domain controller. To set up a secure connection, you have to create a server admin user and a secret that -will be shared between the master and the slave. You do this by running the +.../bin/add-user.sh+ script. +will be shared between the master and the slave. You do this by running the `.../bin/add-user.sh` script. -When you run the script select +Management User+ and answer +yes+ when it asks you if the new user is going to be used +When you run the script select `Management User` and answer `yes` when it asks you if the new user is going to be used for one AS process to connect to another. This will generate a secret that you'll need to cut and paste into the _.../domain/configuration/host-slave.xml_ file. From 85b8088a4954f9ab247c4498b8ea83b37f0fa30d Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 29 Apr 2016 16:18:59 -0400 Subject: [PATCH 084/149] 2nd draft --- topics/installation/directory-structure.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index 15f902467b..a85bbdbf14 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -17,14 +17,14 @@ _modules/_:: These are all the Java libraries used by the server. _providers/_:: - If you are writing extensions to keycloak, you can put your extensions here. See the link:{{book.developerguide.link}}[{{book.developerguide.name] for more information on this. + If you are writing extensions to keycloak, you can put your extensions here. See the link:{{book.developerguide.link}}[{{book.developerguide.name}}] for more information on this. _standalone/_:: This contains configuration files and working directory when running {{book.project.name}} in <>. _themes/_:: This directory contains all the html, style sheets, javascript files, and images used to display any UI screen displayed by the server. - Here you can modify an existing theme or create your own. See the link:{{book.developerguide.link}}[{{book.developerguide.name] for more information on this. + Here you can modify an existing theme or create your own. See the link:{{book.developerguide.link}}[{{book.developerguide.name}}] for more information on this. From aad8d04f0b10dc8890b20fd7855ac47e2c8a2814 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Fri, 29 Apr 2016 16:21:20 -0400 Subject: [PATCH 085/149] 2nd draft --- topics/clustering/load-balancer.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topics/clustering/load-balancer.adoc b/topics/clustering/load-balancer.adoc index 119c797e69..72257c22fc 100755 --- a/topics/clustering/load-balancer.adoc +++ b/topics/clustering/load-balancer.adoc @@ -3,7 +3,7 @@ This section only covers configuring the built in load balancer that is discussed in the <>. The link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}} -has some information on using some other software based load balancers that may help you. +has information on using some other software based load balancers that may help you. The <> is only designed to run on one machine. To bring up a slave on another host, you'll need to @@ -62,7 +62,7 @@ binding needs to point to the host and port of the new host. === Master Bind Addresses Next thing you'll have to do is to change the `public` and `management` bind addresses for the master host. Either -edit the _domain.xml_ file as discussed in the <> chapter +edit the _domain.xml_ file as discussed in the <> chapter or specify these bind addresses on the command line as follows: [source] From 16e4b237f643196b5bcabca66599784d316e7878 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Sat, 30 Apr 2016 00:39:32 -0400 Subject: [PATCH 086/149] gitlab conversion script --- gitlab-conversion.py | 103 +++ topics/cache.adoc | 1 + topics/cache/clear.adoc | 1 + topics/cache/disable.adoc | 1 + topics/cache/eviction.adoc | 1 + topics/cache/replication.adoc | 1 + topics/clustering.adoc | 1 + topics/clustering/booting.adoc | 1 + topics/clustering/example.adoc | 1 + topics/clustering/load-balancer.adoc | 5 +- topics/clustering/multicast.adoc | 1 + topics/clustering/recommended.adoc | 1 + topics/clustering/serialized.adoc | 1 + topics/clustering/troubleshooting.adoc | 4 + topics/database/checklist.adoc | 1 + topics/database/datasource.adoc | 1 + topics/database/hibernate.adoc | 1 + topics/database/jdbc.adoc | 1 + topics/installation.adoc | 1 + topics/installation/directory-structure.adoc | 1 + .../distribution-files-community.adoc | 1 + .../distribution-files-product.adoc | 1 + topics/installation/system-requirements.adoc | 1 + topics/manage.adoc | 3 +- topics/mongo.adoc | 3 +- topics/network.adoc | 1 + topics/network/bind-address.adoc | 1 + topics/network/https.adoc | 1 + topics/network/outgoing.adoc | 1 + topics/network/ports.adoc | 1 + topics/old-installation.adoc | 610 ------------------ topics/openshift.adoc | 1 + topics/operating-mode.adoc | 1 + topics/operating-mode/domain.adoc | 6 +- topics/operating-mode/standalone-ha.adoc | 1 + topics/operating-mode/standalone.adoc | 1 + topics/overview.adoc | 1 + topics/overview/recommended-reading.adoc | 1 + topics/proxy.adoc | 3 +- 39 files changed, 151 insertions(+), 617 deletions(-) create mode 100755 gitlab-conversion.py delete mode 100755 topics/old-installation.adoc diff --git a/gitlab-conversion.py b/gitlab-conversion.py new file mode 100755 index 0000000000..d500ce3bc9 --- /dev/null +++ b/gitlab-conversion.py @@ -0,0 +1,103 @@ +import sys, os, re, json, shutil, errno + +def transform(root, f, targetdir): + full = os.path.join(root, f) + print full + input = open(full, 'r').read() + dir = os.path.join(targetdir, root) + if not os.path.exists(dir): + os.makedirs(dir) + output = open(os.path.join(dir, f), 'w') + for variable in re.findall(r"\{\{(.*?)\}\}", input): + tmp = variable.replace('.', '_') + input = input.replace(variable, tmp) + input = input.replace('{{', '{').replace('}}','}') + input = re.sub(r"<}==true]\g<2>endif::[]", input) + input = re.sub(r"image:(\.\./)*", "image:", input) + output.write(input) + +indir = 'topics' +targetdir = 'target' +if len(sys.argv) > 1: + targetdir = sys.argv[1] + +shutil.rmtree(os.path.join(targetdir, 'images')) +shutil.rmtree(os.path.join(targetdir, 'keycloak-images')) +shutil.rmtree(os.path.join(targetdir, 'rhsso-images')) +shutil.copytree('images',os.path.join(targetdir, 'images')) +shutil.copytree('keycloak-images',os.path.join(targetdir, 'keycloak-images')) +shutil.copytree('rhsso-images',os.path.join(targetdir, 'rhsso-images')) + +tmp = os.path.join(targetdir, 'topics') +if not os.path.exists(tmp): + os.makedirs(tmp) + +# transform files +for root, dirs, filenames in os.walk(indir): + for f in filenames: + transform(root,f,targetdir) + +# Create master.doc includes +input = open('SUMMARY.adoc', 'r').read() +output = open(os.path.join(targetdir, 'master.adoc'), 'w') + +output.write(""" +:toc: +:toclevels: 3 +:numbered: + +include::document-attributes.adoc[] +""") + +input = re.sub(r"[ ]*\.+\s*link:(.*)\[(.*)\]", "include::\g<1>[]", input) +for variable in re.findall(r"[ ]*{% if (.*?) %}", input): + tmp = variable.replace('.', '_') + input = input.replace(variable, tmp) +exp = re.compile("[ ]*{% if (.*?) %}(.*?)[ ]*{% endif %}", re.DOTALL) +input = re.sub(exp, "ifeval::[{\g<1>}==true]\g<2>endif::[]", input) +output.write(input) + +# parse book.json file and create document attributes +with open('book.json') as data_file: + data = json.load(data_file) + +variables = data['variables'] + +def makeAttributes(variables, variable, list): + for i in variables.keys(): + if variable is None: + tmp = i + else: + tmp = variable + '_' + i + if isinstance(variables[i],dict): + makeAttributes(variables[i], tmp, list) + elif isinstance(variables[i],bool): + boolval = 'false' + if variables[i]: + boolval = 'true' + list.append({tmp: boolval}) + else: + list.append({tmp: str(variables[i])}) + + +attributeList = [] +makeAttributes(variables, None, attributeList) + +output = open(os.path.join(targetdir, 'document-attributes.adoc'), 'w') +for attribute in attributeList: + for k in attribute.keys(): + output.write(':book_' + k + ": " + attribute[k] + "\n") + + + + + + + + + diff --git a/topics/cache.adoc b/topics/cache.adoc index 3ab0ebcad9..144acfdf02 100755 --- a/topics/cache.adoc +++ b/topics/cache.adoc @@ -1,3 +1,4 @@ + == Server Cache Configuration {{book.project.name}} has two types of caches. One type of cache sits in front of the database to decrease load on the DB diff --git a/topics/cache/clear.adoc b/topics/cache/clear.adoc index a69d971abb..b170f17548 100755 --- a/topics/cache/clear.adoc +++ b/topics/cache/clear.adoc @@ -1,3 +1,4 @@ + === Clearing Caches at Runtime To clear the realm or user cache, go to the {{book.project.name}} admin console Realm Settings->Cache Config page. diff --git a/topics/cache/disable.adoc b/topics/cache/disable.adoc index 72d856edb3..7e5f30bd19 100755 --- a/topics/cache/disable.adoc +++ b/topics/cache/disable.adoc @@ -1,3 +1,4 @@ + === Disabling Caching To disable the realm or user cache, you must edit the `keycloak-server.json` file in your distribution. Where diff --git a/topics/cache/eviction.adoc b/topics/cache/eviction.adoc index 152165dabb..9449949d77 100755 --- a/topics/cache/eviction.adoc +++ b/topics/cache/eviction.adoc @@ -1,3 +1,4 @@ + === Eviction and Expiration There are multiple different caches configured for {{book.project.name}}. diff --git a/topics/cache/replication.adoc b/topics/cache/replication.adoc index b07fc812ec..0cd44723bd 100755 --- a/topics/cache/replication.adoc +++ b/topics/cache/replication.adoc @@ -1,3 +1,4 @@ + === Replication and Failover The `sessions`, `offlineSessions` and `loginFailures` caches are the only caches that may perform replication. Entries are diff --git a/topics/clustering.adoc b/topics/clustering.adoc index 323b2c20c4..14ca4eb736 100755 --- a/topics/clustering.adoc +++ b/topics/clustering.adoc @@ -1,3 +1,4 @@ + [[_clustering]] == Clustering diff --git a/topics/clustering/booting.adoc b/topics/clustering/booting.adoc index 31ff5ab75a..065dd61fa9 100755 --- a/topics/clustering/booting.adoc +++ b/topics/clustering/booting.adoc @@ -1,3 +1,4 @@ + === Booting the Cluster Booting {{book.project.name}} in a cluster depends on your <> diff --git a/topics/clustering/example.adoc b/topics/clustering/example.adoc index cb3b18a5ee..b4f53998a4 100755 --- a/topics/clustering/example.adoc +++ b/topics/clustering/example.adoc @@ -1,3 +1,4 @@ + === Clustering Example {{book.project.name}} does come with an out of the box clustering demo that leverages domain mode. Review the diff --git a/topics/clustering/load-balancer.adoc b/topics/clustering/load-balancer.adoc index 72257c22fc..783b4c9760 100755 --- a/topics/clustering/load-balancer.adoc +++ b/topics/clustering/load-balancer.adoc @@ -1,3 +1,4 @@ + === Setting Up a Load Balancer This section only covers configuring the built in load balancer that is discussed in the @@ -59,7 +60,7 @@ binding needs to point to the host and port of the new host. ---- -=== Master Bind Addresses +==== Master Bind Addresses Next thing you'll have to do is to change the `public` and `management` bind addresses for the master host. Either edit the _domain.xml_ file as discussed in the <> chapter @@ -70,7 +71,7 @@ or specify these bind addresses on the command line as follows: $ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2 ---- -=== Host Slave Bind Addresses +==== Host Slave Bind Addresses Next you'll have to change the `public`, `management`, and domain controller bind addresses (`jboss.domain.master-address`). Either edit the _host-slave.xml_ file or specify them on the command line as follows: diff --git a/topics/clustering/multicast.adoc b/topics/clustering/multicast.adoc index 6702eeef16..ee7f3064d8 100755 --- a/topics/clustering/multicast.adoc +++ b/topics/clustering/multicast.adoc @@ -1,3 +1,4 @@ + === Multicast Network Setup Out of the box clustering support has a need to for IP Multicast. Multicast is a network broadcast protocol. This protocol diff --git a/topics/clustering/recommended.adoc b/topics/clustering/recommended.adoc index 1b5ae0d05f..dd2f99a7b2 100755 --- a/topics/clustering/recommended.adoc +++ b/topics/clustering/recommended.adoc @@ -1,3 +1,4 @@ + === Recommended Network Architecture The recommended network architecture for deploying {{book.project.name}} is to set up an HTTP/HTTPS load balancer on diff --git a/topics/clustering/serialized.adoc b/topics/clustering/serialized.adoc index 5afd9e09e7..1bd3e4aa49 100755 --- a/topics/clustering/serialized.adoc +++ b/topics/clustering/serialized.adoc @@ -1,3 +1,4 @@ + [[_clustering_db_lock]] === Serialized Cluster Startup diff --git a/topics/clustering/troubleshooting.adoc b/topics/clustering/troubleshooting.adoc index 48136012e8..ba611ab5df 100755 --- a/topics/clustering/troubleshooting.adoc +++ b/topics/clustering/troubleshooting.adoc @@ -1,3 +1,4 @@ + === Troubleshooting Note that when you run cluster, you should see message similar to this in the log of both cluster nodes: @@ -16,3 +17,6 @@ Default values are UDP port 55200 and multicast port 45688 with multicast addres Note that you may need more ports opened if you want to enable additional features like diagnostics for your JGroups stack. {{book.project.name}} delegates most of the clustering work to Infinispan/JGroups. Please consult the link:{{book.appserver.jgroups.link}}[JGroups] chapter of the {{book.appserver.jgroups.name}}. + + + diff --git a/topics/database/checklist.adoc b/topics/database/checklist.adoc index d578f89478..ae77da08a8 100755 --- a/topics/database/checklist.adoc +++ b/topics/database/checklist.adoc @@ -1,3 +1,4 @@ + === RDBMS Setup Checklist These are the steps you will need to perform to get an RDBMS configured for {{book.project.name}}. diff --git a/topics/database/datasource.adoc b/topics/database/datasource.adoc index 3699c2b355..b8dc9484c1 100755 --- a/topics/database/datasource.adoc +++ b/topics/database/datasource.adoc @@ -1,3 +1,4 @@ + === Modify the {{book.project.name}} Datasource After declaring your JDBC driver, you have to modify the existing datasource configuration that {{book.project.name}} uses diff --git a/topics/database/hibernate.adoc b/topics/database/hibernate.adoc index d251ccf480..15c924698f 100755 --- a/topics/database/hibernate.adoc +++ b/topics/database/hibernate.adoc @@ -1,3 +1,4 @@ + === Hibernate Configuration The Hibernate persistence API is already pre-configured out of the box and rarely needs to be changed. diff --git a/topics/database/jdbc.adoc b/topics/database/jdbc.adoc index f5ef1d2114..8c7ba0a705 100755 --- a/topics/database/jdbc.adoc +++ b/topics/database/jdbc.adoc @@ -1,3 +1,4 @@ + === Package the JDBC Driver Find and download the JDBC driver JAR for your RDBMS. Before you can use this driver, you must package it up into a module diff --git a/topics/installation.adoc b/topics/installation.adoc index 289e0ec6ed..b78634455b 100755 --- a/topics/installation.adoc +++ b/topics/installation.adoc @@ -1,3 +1,4 @@ + == Installation Installing {{book.project.name}} is as simple as downloading it and unzipping it. This chapter reviews system requirements diff --git a/topics/installation/directory-structure.adoc b/topics/installation/directory-structure.adoc index a85bbdbf14..d6468c0959 100755 --- a/topics/installation/directory-structure.adoc +++ b/topics/installation/directory-structure.adoc @@ -1,3 +1,4 @@ + === Distribution Directory Structure This chapter walks you through the directory structure of the server distribution. diff --git a/topics/installation/distribution-files-community.adoc b/topics/installation/distribution-files-community.adoc index 761fbae07b..3dd01d1210 100755 --- a/topics/installation/distribution-files-community.adoc +++ b/topics/installation/distribution-files-community.adoc @@ -1,3 +1,4 @@ + === Installing Distribution Files The Keycloak Server has three downloadable distributions: diff --git a/topics/installation/distribution-files-product.adoc b/topics/installation/distribution-files-product.adoc index 0db0d44c2e..f5d63994ef 100755 --- a/topics/installation/distribution-files-product.adoc +++ b/topics/installation/distribution-files-product.adoc @@ -1,3 +1,4 @@ + === Installing Distribution Files The {{book.project.name}} Server is contained in one distribution file: diff --git a/topics/installation/system-requirements.adoc b/topics/installation/system-requirements.adoc index a19a7b7306..1804157d5b 100755 --- a/topics/installation/system-requirements.adoc +++ b/topics/installation/system-requirements.adoc @@ -1,3 +1,4 @@ + === System Requirements These are the requirements to run the {{book.project.name}} authentication server: diff --git a/topics/manage.adoc b/topics/manage.adoc index 0325b6372d..aa0d2d98d4 100755 --- a/topics/manage.adoc +++ b/topics/manage.adoc @@ -7,7 +7,8 @@ shown how to edit the _standalone.xml_ or _domain.xml_ directly. This must be d Additionally, you may be shown how to apply config changes on a running server using the app server's command line interface ({{books.appserver.name}} CLI). This chapter discusses how you will do this. -=== Start the {{books.appserver.name}} CLI + +=== Start the {{book.appserver.name}} CLI To start the {{books.appserver.name}} CLI, you need to run the `jboss-cli` script. diff --git a/topics/mongo.adoc b/topics/mongo.adoc index b572d23b69..19ef3d2a98 100755 --- a/topics/mongo.adoc +++ b/topics/mongo.adoc @@ -1,3 +1,4 @@ + [[_mongo]] == Mongo DB Setup @@ -94,6 +95,6 @@ Therefore, a configuration like the following ---- will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. -==== MongoDB Replica Sets +=== MongoDB Replica Sets In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. diff --git a/topics/network.adoc b/topics/network.adoc index 5b73d20178..baef04e38e 100755 --- a/topics/network.adoc +++ b/topics/network.adoc @@ -1,3 +1,4 @@ + [[_network]] == Network Setup diff --git a/topics/network/bind-address.adoc b/topics/network/bind-address.adoc index b542be25f0..884d1a2e60 100755 --- a/topics/network/bind-address.adoc +++ b/topics/network/bind-address.adoc @@ -1,3 +1,4 @@ + [[_bind-address]] === Bind Addresses diff --git a/topics/network/https.adoc b/topics/network/https.adoc index 30cdd83083..8557e75fd9 100755 --- a/topics/network/https.adoc +++ b/topics/network/https.adoc @@ -1,3 +1,4 @@ + === Setting up HTTPS/SSL WARNING: {{book.project.name}} is not set up by default to handle SSL/HTTPS. diff --git a/topics/network/outgoing.adoc b/topics/network/outgoing.adoc index 97c3bbd169..b0d3271526 100755 --- a/topics/network/outgoing.adoc +++ b/topics/network/outgoing.adoc @@ -1,3 +1,4 @@ + === Outgoing HTTP Requests The {{book.project.name}} server often needs to make non-browser HTTP requests to the applications and services it secures. diff --git a/topics/network/ports.adoc b/topics/network/ports.adoc index 8d9aea288d..0c3d67dac1 100755 --- a/topics/network/ports.adoc +++ b/topics/network/ports.adoc @@ -1,3 +1,4 @@ + [[_ports]] === Socket Port Bindings diff --git a/topics/old-installation.adoc b/topics/old-installation.adoc deleted file mode 100755 index 697f2483e6..0000000000 --- a/topics/old-installation.adoc +++ /dev/null @@ -1,610 +0,0 @@ -[[_server_installation]] - -= Installation and Configuration of Keycloak Server - -== Installation - -Keycloak Server has three downloadable distributions. -To run the Keycloak server you need to have Java 8 already installed. - -* keycloak-.[zip|tar.gz] -* keycloak-overlay-.[zip|tar.gz] -* keycloak-demo-.[zip|tar.gz] - -[[_server_install]] -=== Install Standalone Server - -For production and for non-JavaEE developers we recommend using the standalone Keycloak server. -All you need to do is to download `keycloak-.zip` or `keycloak-.tar.gz`, unpackage and start to have a Keycloak server up and running. - -To install first download either the zip or tar.gz and extract. -Then start by running either: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -[[_overlay_install]] -=== Install on existing WildFly or JBoss EAP - -Keycloak can be installed into an existing installations of WildFly or JBoss EAP . To do this download `keycloak-overlay-.zip` or `keycloak-overlay-.tar.gz`. -Once downloaded extract into the root directory of your installation. - -To add Keycloak to existing standalone.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install.cli ----- -To add Keycloak to existing standalone-ha.xml server config run: - -[source] ----- - -bin/jboss-cli.sh --file=bin/keycloak-install-ha.cli ----- -If you want to add Keycloak to a different server config edit `keycloak-install.cli` or `keycloak-install-ha.cli` and change the name of the server config. - -=== Install Development Bundle - -The demo bundle contains everything you need to get started with Keycloak including documentation and examples. -To install it first download `keycloak-demo-.zip` or `keycloak-demo-.tar.gz`. -Once downloaded extract it inside `keycloak-demo-` you'll find `keycloak` which contains a full WildFly server with Keycloak Server and Adapters included. -You'll also find `docs` and `examples` which contains everything you need to get started developing applications that use Keycloak. - -To start WildFly with Keycloak run: - -[source] ----- -keycloak-/bin/standalone.sh ----- -or: - -[source] ----- -keycloak-/bin/standalone.bat ----- - -== Configuring the Server - -Although the Keycloak Server is designed to run out of the box, there's some things you'll need to configure before you go into production. -Specifically: - -* Configuring Keycloak to use a production database -* Setting up SSL/HTTPS -* Enforcing HTTPS connections - -=== Admin User - -To access the admin console to configure Keycloak you need an account to login. -There is no built in user, instead you have to first create an admin account. -This can done either by opening http://localhost:8080/auth (creating a user through the browser can only be done through localhost) or you can use the add-user script from the command-line. - -The `add-user` script creates a temporary file with the details of the user, which are imported at startup. -To add a user with this script run: - -[source] ----- - -bin/add-user.[sh|bat] -r master -u -p ----- -Then restart the server. -For `keycloak-overlay`, please make sure to use: - -[source] ----- -bin/add-user-keycloak.[sh|bat] -r master -u -p ----- - -=== Relational Database Configuration - -You might want to use a better relational database for Keycloak like PostgreSQL or MySQL. -You might also want to tweak the configuration settings of the datasource. -Please see the https://docs.jboss.org/author/display/WFLY8/DataSource+configuration[Wildfly] documentation on how to do this. - -Keycloak runs on a Hibernate/JPA backend which is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- -"connectionsJpa": { - "default": { - "dataSource": "java:jboss/datasources/KeycloakDS", - "databaseSchema": "update" - } -}, ----- -Possible configuration options are: - -dataSource:: - JNDI name of the dataSource - -jta:: - boolean property to specify if datasource is JTA capable - -driverDialect:: - Value of Hibernate dialect. - In most cases you don't need to specify this property as dialect will be autodetected by Hibernate. - -databaseSchema:: - Specify if schema should be updated or validated. - Valid values are "update" and "validate" ("update is default). - -showSql:: - Specify whether Hibernate should show all SQL commands in the console (false by default) - -formatSql:: - Specify whether Hibernate should format SQL commands (true by default) - -globalStatsInterval:: - Will log global statistics from Hibernate about executed DB queries and other things. - Statistics are always reported to server log at specified interval (in seconds) and are cleared after each report. - -schema:: - Specify the database schema to use - -===== Tested databases - -Here is list of RDBMS databases and corresponding JDBC drivers, which were tested with Keycloak. -Note that Hibernate dialect is usually set automatically according to your database, but you have possibility to override if default dialect doesn't work correctly. -You can setup dialect by adding property `driverDialect` to the `keycloak-server.json` into `connectionsJpa` section (see above). - -.Tested databases -[cols="1,1,1", frame="all", options="header"] -|=== -| Database -| JDBC driver -| Hibernate Dialect - - - - - - -|=== - -=== MongoDB based model - -Keycloak provides http://www.mongodb.com[MongoDB] based model implementation, which means that your identity data will be saved in MongoDB instead of traditional RDBMS. -To configure Keycloak to use Mongo open `standalone/configuration/keycloak-server.json` in your favourite editor, then change: - -[source] ----- - -"eventsStore": { - "provider": "jpa", - "jpa": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "jpa" -}, - -"user": { - "provider": "${keycloak.user.provider:jpa}" -}, ----- -to: - -[source] ----- - -"eventsStore": { - "provider": "mongo", - "mongo": { - "exclude-events": [ "REFRESH_TOKEN" ] - } -}, - -"realm": { - "provider": "mongo" -}, - -"user": { - "provider": "mongo" -}, ----- -And at the end of the file add the snippet like this where you can configure details about your Mongo database: - -[source] ----- - -"connectionsMongo": { - "default": { - "host": "127.0.0.1", - "port": "27017", - "db": "keycloak", - "connectionsPerHost": 100, - "databaseSchema": "update" - } -} ----- -All configuration options are optional. -Default values for host and port are localhost and 27017. -Default name of database is `keycloak` . You can also specify properties `user` and `password` if you want authenticate against your MongoDB. -If user and password are not specified, Keycloak will connect unauthenticated to your MongoDB. - -Finally there is set of optional configuration options, which can be used to specify connection-pooling capabilities of Mongo client. -Supported int options are: `connectionsPerHost`, `threadsAllowedToBlockForConnectionMultiplier`, `maxWaitTime`, `connectTimeout` `socketTimeout`. -Supported boolean options are: `socketKeepAlive`, `autoConnectRetry`. -Supported long option is `maxAutoConnectRetryTime`. -See http://api.mongodb.org/java/2.11.4/com/mongodb/MongoClientOptions.html[Mongo documentation] for details about those options and their default values. - -Alternatively, you can configure MongoDB using a MongoDB http://docs.mongodb.org/manual/reference/connection-string/[connection URI]. -In this case, you define all information concerning the connection and authentication within the URI, as described in the MongoDB documentation. -Please note that the database specified within the URI is only used for authentication. -To change the database used by keycloak you have to set `db` property as before. -Therefore, a configuration like the following - -[source] ----- - -"connectionsMongo": { - "default": { - "uri": "mongodb://user:password@127.0.0.1/authentication", - "db": "keycloak" - } -} ----- -will authenticate the user against the authentication database, but store all keycloak related data in the keycloak database. - -==== MongoDB Replica Sets - -In order to use a mongo replica set for Keycloak, one has to use URI based configuration, which supports the definition of replica sets out of the box: `mongodb://host1:27017,host2:27017,host3:27017/`. - -=== Outgoing Server HTTP Requests - -Keycloak server needs to invoke on remote HTTP endpoints to do things like backchannel logouts and other management functions. -Keycloak maintains a HTTP client connection pool which has various configuration settings you can specify before boot time. -This is configured in the `standalone/configuration/keycloak-server.json`. -By default the setting is like this: - -[source] ----- - -"connectionsHttpClient": { - "default": {} -}, ----- -Possible configuration options are: - -establish-connection-timeout-millis:: - Timeout for establishing a socket connection. - -socket-timeout-millis:: - If an outgoing request does not receive data for this amount of time, timeout the connection. - -connection-pool-size:: - How many connections can be in the pool (128 by default). - -max-pooled-per-route:: - How many connections can be pooled per host (64 by default). - -connection-ttl-millis:: - Maximum connection time to live in milliseconds. - Not set by default. - -max-connection-idle-time-millis:: - Maximum time the connection might stay idle in the connection pool (900 seconds by default). Will start background cleaner thread of Apache HTTP client. - Set to -1 to disable this checking and the background thread. - -disable-cookies:: - `true` by default. - When set to true, this will disable any cookie caching. - -client-keystore:: - This is the file path to a Java keystore file. - This keystore contains client certificate for two-way SSL. - -client-keystore-password:: - Password for the client keystore. - This is _REQUIRED_ if `client-keystore` is set. - -client-key-password:: - _Not supported yet, but we will support in future versions. Password for the client's key. - This is _REQUIRED_ if `client-keystore` is set. - -[[_truststore]] -=== Securing Outgoing Server HTTP Requests - -When Keycloak connects out to remote HTTP endpoints over secure https connection, it has to validate the other server's certificate in order to ensure it is connecting to a trusted server. -That is necessary in order to prevent man-in-the-middle attacks. - -How certificates are validated is configured in the `standalone/configuration/keycloak-server.json`. -By default truststore provider is not configured, and any https connections fall back to standard java truststore configuration as described in https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html[ - Java's JSSE Reference Guide] - using `javax.net.ssl.trustStore system property`, otherwise `cacerts` file that comes with java is used. - -Truststore is used when connecting securely to identity brokers, LDAP identity providers, when sending emails, and for backchannel communication with client applications. -Some of these facilities may - in case when no trusted certificate is found in your configured truststore - fallback to using the JSSE provided truststore. -The default JavaMail API implementation used to send out emails behaves in this way, for example. - -You can add your truststore configuration by using the following template: - -[source] ----- - -"truststore": { - "file": { - "file": "path to your .jks file containing public certificates", - "password": "password", - "hostname-verification-policy": "WILDCARD", - "disabled": false - } -} ----- - -Possible configuration options are: - -file:: - The value is the file path to a Java keystore file. - HTTPS requests need a way to verify the host of the server they are talking to. - This is what the trustore does. - The keystore contains one or more trusted host certificates or certificate authorities. - Truststore file should only contain public certificates of your secured hosts. - This is _REQUIRED_ if `disabled` is not true. - -password:: - Password for the truststore. - This is _REQUIRED_ if `disabled` is not true. - -hostname-verification-policy:: - `WILDCARD` by default. - For HTTPS requests, this verifies the hostname of the server's certificate. - `ANY` means that the hostname is not verified. `WILDCARD` Allows wildcards in subdomain names i.e. - *.foo.com. `STRICT` CN must match hostname exactly. - -disabled:: - If true (default value), truststore configuration will be ignored, and certificate checking will fall back to JSSE configuration as described. - If set to false, you must configure `file`, and `password` for the truststore. - -You can use _keytool_ to create a new truststore file and add trusted host certificates to it: - -[source] ----- - -$ keytool -import -alias HOSTDOMAIN -keystore truststore.jks -file host-certificate.cer ----- - -[[_ssl_modes]] -=== SSL/HTTPS Requirement/Modes - -WARNING: Keycloak is not set up by default to handle SSL/HTTPS. -It is highly recommended that you either enable SSL on the Keycloak server itself or on a reverse proxy in front of the Keycloak server. - -Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. -If you try to access Keycloak from a non-IP adress you will get an error. - -Keycloak has 3 SSL/HTTPS modes which you can set up in the admin console under the Settings->Login page and the `Require SSL` select box. -Each adapter config should mirror this server-side setting. -See adapter config section for more details. - -external:: - Keycloak can run out of the box without SSL so long as you stick to private IP addresses like localhost, 127.0.0.1, 10.0.x.x, 192.168.x.x, and 172..16.x.x. - If you try to access Keycloak from a non-IP adress you will get an error. - -none:: - Keycloak does not require SSL. - -all:: - Keycloak requires SSL for all IP addresses. - -=== SSL/HTTPS Setup - -First enable SSL on Keycloak or on a reverse proxy in front of Keycloak. -Then configure the Keycloak Server to enforce HTTPS connections. - -==== Enable SSL on Keycloak - -The following things need to be done - -* keytool -* Enable Wildfly to use this certificate and turn on SSL/HTTPS. - -===== Creating the Certificate and Java Keystore - -In order to allow HTTPS connections, you need to obtain a self signed or third-party signed certificate and import it into a Java keystore before you can enable HTTPS in the web container you are deploying the Keycloak Server to. - -====== Self Signed Certificate - -In development, you will probably not have a third party signed certificate available to test a Keycloak deployment so you'll need to generate a self-signed on. -Generate one is very easy to do with the `keytool` utility that comes with the Java jdk. - - -[source] ----- - -$ keytool -genkey -alias localhost -keyalg RSA -keystore keycloak.jks -validity 10950 - Enter keystore password: secret - Re-enter new password: secret - What is your first and last name? - [Unknown]: localhost - What is the name of your organizational unit? - [Unknown]: Keycloak - What is the name of your organization? - [Unknown]: Red Hat - What is the name of your City or Locality? - [Unknown]: Westford - What is the name of your State or Province? - [Unknown]: MA - What is the two-letter country code for this unit? - [Unknown]: US - Is CN=localhost, OU=Keycloak, O=Test, L=Westford, ST=MA, C=US correct? - [no]: yes ----- - -You should answer `What is your first and last name ?` question with the DNS name of the machine you're installing the server on. -For testing purposes, `localhost` should be used. -After executing this command, the `keycloak.jks` file will be generated in the same directory as you executed the `keytool` command in. - -If you want a third-party signed certificate, but don't have one, you can obtain one for free at http://cacert.org[cacert.org]. -You'll have to do a little set up first before doing this though. - -The first thing to do is generate a Certificate Request: - -[source] ----- - -$ keytool -certreq -alias yourdomain -keystore keycloak.jks > keycloak.careq ----- - -Where `yourdomain` is a DNS name for which this certificate is generated for. -Keytool generates the request: - -[source] ----- - ------BEGIN NEW CERTIFICATE REQUEST----- -MIIC2jCCAcICAQAwZTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk1BMREwDwYDVQQHEwhXZXN0Zm9y -ZDEQMA4GA1UEChMHUmVkIEhhdDEQMA4GA1UECxMHUmVkIEhhdDESMBAGA1UEAxMJbG9jYWxob3N0 -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr7kck2TaavlEOGbcpi9c0rncY4HhdzmY -Ax2nZfq1eZEaIPqI5aTxwQZzzLDK9qbeAd8Ji79HzSqnRDxNYaZu7mAYhFKHgixsolE3o5Yfzbw1 -29Rvy+eUVe+WZxv5oo9wolVVpdSINIMEL2LaFhtX/c1dqiqYVpfnvFshZQaIg2nL8juzZcBjj4as -H98gIS7khql/dkZKsw9NLvyxgJvp7PaXurX29fNf3ihG+oFrL22oFyV54BWWxXCKU/GPn61EGZGw -Ft2qSIGLdctpMD1aJR2bcnlhEjZKDksjQZoQ5YMXaAGkcYkG6QkgrocDE2YXDbi7GIdf9MegVJ35 -2DQMpwIDAQABoDAwLgYJKoZIhvcNAQkOMSEwHzAdBgNVHQ4EFgQUQwlZJBA+fjiDdiVzaO9vrE/i -n2swDQYJKoZIhvcNAQELBQADggEBAC5FRvMkhal3q86tHPBYWBuTtmcSjs4qUm6V6f63frhveWHf -PzRrI1xH272XUIeBk0gtzWo0nNZnf0mMCtUBbHhhDcG82xolikfqibZijoQZCiGiedVjHJFtniDQ -9bMDUOXEMQ7gHZg5q6mJfNG9MbMpQaUVEEFvfGEQQxbiFK7hRWU8S23/d80e8nExgQxdJWJ6vd0X -MzzFK6j4Dj55bJVuM7GFmfdNC52pNOD5vYe47Aqh8oajHX9XTycVtPXl45rrWAH33ftbrS8SrZ2S -vqIFQeuLL3BaHwpl3t7j2lMWcK1p80laAxEASib/fAwrRHpLHBXRcq6uALUOZl4Alt8= ------END NEW CERTIFICATE REQUEST----- ----- - -Send this ca request to your CA. -The CA will issue you a signed certificate and send it to you. -Before you import your new cert, you must obtain and import the root certificate of the CA. -You can download the cert from CA (ie.: root.crt) and import as follows: - -[source] ----- - -$ keytool -import -keystore keycloak.jks -file root.crt -alias root ----- - -Last step is import your new CA generated certificate to your keystore: - -[source] ----- - -$ keytool -import -alias yourdomain -keystore keycloak.jks -file your-certificate.cer ----- - -===== Installing the keystore to WildFly - -Now that you have a Java keystore with the appropriate certificates, you need to configure your Wildfly installation to use it. -First step is to move the keystore file to a directory you can reference in configuration. -I like to put it in `standalone/configuration`. -Then you need to edit `standalone/configuration/standalone.xml` to enable SSL/HTTPS. - -To the `security-realms` element add: - -[source] ----- - - - - - - - - ----- - -Find the element `server name="default-server"` (it's a child element of `subsystem xmlns="urn:jboss:domain:undertow:1.0"`) and add: - -[source] ----- - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[Wildfly Undertow] documentation for more information on fine tuning the socket connections. - -==== Enable SSL on a Reverse Proxy - -Follow the documentation for your web server to enable SSL and configure reverse proxy for Keycloak. -It is important that you make sure the web server sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to Keycloak. -Next you need to enable `proxy-address-forwarding` on the Keycloak http connector. -Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. - -===== Configure WildFly - -. Open `standalone/configuration/standalone.xml` in your favorite editor. - -. First add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: - -[source] ----- - - ... - - ... - ----- - -Then add a new `socket-binding` element to the `socket-binding-group` element: - -[source] ----- - - - ... - - ... - ----- - -Check the https://docs.jboss.org/author/display/WFLY8/Undertow+(web)+subsystem+configuration[WildFly] documentation for more information. - -== Keycloak server in Domain Mode - -In domain mode, you start the server with the "domain" command instead of the "standalone" command. -In this case, the Keycloak subsystem is defined in domain/configuration/domain.xml instead of standalone/configuration.standalone.xml. -Inside domain.xml, you will see more than one profile. -The Keycloak subsystem is defined for all initial profiles. - -THe server is also added to server profiles. -By default two servers are started in the main-server-group which uses the full profile. - -You need to make sure `domain/servers/SERVER NAME/configuration` is identical for all servers in a group. - -To deploy custom providers and themes you should deploys these as modules and make sure the modules are available to all servers in the group. -See <<_providers,Providers>> and <<_themes,Themes>> sections for more information on how to do this. - -== Installing Keycloak Server as Root Context - -The Keycloak server can be installed as the default web application. -In doing so, the server can be referenced at `http://mydomain.com/` instead of `http://mydomain.com/auth`. - -To do this, add the `default-web-module` attribute in the Undertow subystem in standalone.xml. - -[source] ----- - - - - - - ----- - -`keycloak-server.war` is the runtime name of the Keycloak server application. -Note that the WAR file does not exist as a file. -If its name changes (ie. `keycloak-server.war`) in the future, find its new name from the Keycloak log entry with `runtime-name:`. - - - -NOTE: If you have run your server before altering the root context, your database will contain references to the old /auth context. Your clients may also have incorrect references. -To fix this on the server side, you will need to export your database to json, make corrections, and then import. -Client-side `keycloak.json` files will need to be updated manually as well. diff --git a/topics/openshift.adoc b/topics/openshift.adoc index 3213e02a42..b6e8eb78b6 100755 --- a/topics/openshift.adoc +++ b/topics/openshift.adoc @@ -1,3 +1,4 @@ + [[_openshift]] == Running Keycloak Server on OpenShift diff --git a/topics/operating-mode.adoc b/topics/operating-mode.adoc index 2f0acd744f..a34d55f0bc 100755 --- a/topics/operating-mode.adoc +++ b/topics/operating-mode.adoc @@ -1,3 +1,4 @@ + [[_operating_mode]] == Choosing an Operating Mode diff --git a/topics/operating-mode/domain.adoc b/topics/operating-mode/domain.adoc index 6b3050805c..295fe634cf 100755 --- a/topics/operating-mode/domain.adoc +++ b/topics/operating-mode/domain.adoc @@ -1,3 +1,4 @@ + [[_domain-mode]] === Domain Clustered Mode @@ -72,7 +73,7 @@ The `auth-server-standalone` profile is a non-clustered setup. The `auth-server If you scroll down further, you'll see various `socket-binding-groups` defined. -.socket-binding-grous +.socket-binding-groups [source,xml] ---- @@ -86,7 +87,8 @@ If you scroll down further, you'll see various `socket-binding-groups` defined. ... - ---- + +---- This config defines the default port mappings for various connectors that are opened with each diff --git a/topics/operating-mode/standalone-ha.adoc b/topics/operating-mode/standalone-ha.adoc index a57988c492..339f8282d2 100755 --- a/topics/operating-mode/standalone-ha.adoc +++ b/topics/operating-mode/standalone-ha.adoc @@ -1,3 +1,4 @@ + [[_standalone-ha-mode]] === Standalone Clustered Mode diff --git a/topics/operating-mode/standalone.adoc b/topics/operating-mode/standalone.adoc index a33758789b..f389738ceb 100755 --- a/topics/operating-mode/standalone.adoc +++ b/topics/operating-mode/standalone.adoc @@ -1,3 +1,4 @@ + [[_standalone-mode]] === Standalone Mode diff --git a/topics/overview.adoc b/topics/overview.adoc index d6ae0e5945..b0670819b8 100755 --- a/topics/overview.adoc +++ b/topics/overview.adoc @@ -1,3 +1,4 @@ + == Guide Overview The purpose of this guide is to walk through the steps that need to be completed prior to booting up the diff --git a/topics/overview/recommended-reading.adoc b/topics/overview/recommended-reading.adoc index 15233acb47..3374658fc0 100755 --- a/topics/overview/recommended-reading.adoc +++ b/topics/overview/recommended-reading.adoc @@ -1,3 +1,4 @@ + === Recommended Additional External Documentation {{book.project.name}} is built upon a derivative of the {{book.appserver.name}} Application Server and projects embedded diff --git a/topics/proxy.adoc b/topics/proxy.adoc index 9135b8f5f8..1478b5bbc8 100755 --- a/topics/proxy.adoc +++ b/topics/proxy.adoc @@ -1,3 +1,4 @@ + [[_proxy]] == Keycloak Security Proxy @@ -147,7 +148,7 @@ adapter-config:: Same configuration as any other keycloak adapter. See <<_adapter_config,Adapter Config>> -===== Constraint Config +==== Constraint Config Next under each application you can define one or more constraints in the `constraints` array attribute. A constraint defines a URL pattern relative to the base-path. From a913482e2feaec5b66e630635bf3faaa66e076d4 Mon Sep 17 00:00:00 2001 From: aasingh Date: Mon, 2 May 2016 15:59:36 +0530 Subject: [PATCH 087/149] typo - attribute id corrected the typo in the attribute ID --- topics/operating-mode.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topics/operating-mode.adoc b/topics/operating-mode.adoc index a34d55f0bc..4f7835885a 100755 --- a/topics/operating-mode.adoc +++ b/topics/operating-mode.adoc @@ -1,5 +1,5 @@ -[[_operating_mode]] +[[_operating-mode]] == Choosing an Operating Mode @@ -9,4 +9,4 @@ your server configurations? Your choice of operating mode effects how you confi TIP: The {{book.project.name}} is built on top of the {{book.appserver.name}} Application Server. This guide will only go over the basics for deployment within a specific mode. If you want specific information on this, a better place - to go would be the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] \ No newline at end of file + to go would be the link:{{book.appserver.admindoc.link}}[{{book.appserver.admindoc.name}}] From 52a365835f92e15ca1b024c977f1c66c4996588e Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 3 May 2016 12:02:26 -0400 Subject: [PATCH 088/149] add title variable and apply it to script too --- SUMMARY.adoc | 2 +- book.json | 1 + gitlab-conversion.py | 19 +++++++++++-------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/SUMMARY.adoc b/SUMMARY.adoc index 88d775e501..4cf66acf7c 100755 --- a/SUMMARY.adoc +++ b/SUMMARY.adoc @@ -1,4 +1,4 @@ -= Summary += {{book.title}} . link:topics/overview.adoc[Overview] .. link:topics/overview/recommended-reading.adoc[Recommended Reading] diff --git a/book.json b/book.json index fe5534d5bf..009ed7b343 100755 --- a/book.json +++ b/book.json @@ -9,6 +9,7 @@ "splitter" ], "variables": { + "title": "Keycloak Installation and Configuration Guide", "community": true, "product": false, "images": "keycloak-images", diff --git a/gitlab-conversion.py b/gitlab-conversion.py index d500ce3bc9..21a1d67bbe 100755 --- a/gitlab-conversion.py +++ b/gitlab-conversion.py @@ -2,16 +2,20 @@ import sys, os, re, json, shutil, errno def transform(root, f, targetdir): full = os.path.join(root, f) - print full input = open(full, 'r').read() dir = os.path.join(targetdir, root) if not os.path.exists(dir): os.makedirs(dir) output = open(os.path.join(dir, f), 'w') + input = applyTransformation(input) + output.write(input) + + +def applyTransformation(input): for variable in re.findall(r"\{\{(.*?)\}\}", input): tmp = variable.replace('.', '_') input = input.replace(variable, tmp) - input = input.replace('{{', '{').replace('}}','}') + input = input.replace('{{', '{').replace('}}', '}') input = re.sub(r"<}==true]\g<2>endif::[]", input) input = re.sub(r"image:(\.\./)*", "image:", input) - output.write(input) + return input + indir = 'topics' targetdir = 'target' @@ -55,11 +60,7 @@ include::document-attributes.adoc[] """) input = re.sub(r"[ ]*\.+\s*link:(.*)\[(.*)\]", "include::\g<1>[]", input) -for variable in re.findall(r"[ ]*{% if (.*?) %}", input): - tmp = variable.replace('.', '_') - input = input.replace(variable, tmp) -exp = re.compile("[ ]*{% if (.*?) %}(.*?)[ ]*{% endif %}", re.DOTALL) -input = re.sub(exp, "ifeval::[{\g<1>}==true]\g<2>endif::[]", input) +input = applyTransformation(input) output.write(input) # parse book.json file and create document attributes @@ -93,6 +94,8 @@ for attribute in attributeList: for k in attribute.keys(): output.write(':book_' + k + ": " + attribute[k] + "\n") +print "Transformation complete!" + From 70e31a7546501fe23725891320db892a9c7e406a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 4 May 2016 11:06:04 -0400 Subject: [PATCH 089/149] proxy docs --- topics/clustering/load-balancer.adoc | 125 +++++++++++++++++++++++++-- topics/network/bind-address.adoc | 2 +- topics/network/https.adoc | 39 --------- 3 files changed, 119 insertions(+), 47 deletions(-) diff --git a/topics/clustering/load-balancer.adoc b/topics/clustering/load-balancer.adoc index 783b4c9760..9421d6547e 100755 --- a/topics/clustering/load-balancer.adoc +++ b/topics/clustering/load-balancer.adoc @@ -1,10 +1,113 @@ -=== Setting Up a Load Balancer +=== Setting Up a Load Balancer or Proxy -This section only covers configuring the built in load balancer that is discussed in the +This section discusses a number of things you need to configure before you can put a reverse proxy or load balancer +in front of your clustered {{book.project.name}} deployment. It also covers configuring the built in load balancer that +was <>. + + +==== Identifying Client IP Addresses + +A few features in {{book.project.name}} rely on the fact that the remote +address of the HTTP client connecting to the authentication server is the real IP address of the client machine. This can +be problematic when you have a reverse proxy or loadbalancer in front of your {{book.project.name}} authentication server. +The usual setup is that you have a frontend proxy sitting on a public network that load balances and forwards requests +to backend {{book.project.name}} server instances that sin on a private network. There is some extra configuration you have to do in this scenario +so that the actual client IP address is forwarded to and processed by the {{book.project.name}} server instances. Specifically: + +* Configure your reverse proxy (loadbalancer) to properly set `X-Forwarded-For` and `X-Forwarded-Proto` HTTP headers. +* Configure the authentication server to read the client's IP address from `X-Forwarded-For header`. + +Configuring your proxy to generate the `X-Forwarded-For` and `X-Forwarded-Proto` HTTP headers is beyond the scope of this +guide. Take extra precautions to ensure that the +`X-Forwared-For` header is set by your proxy. If your proxy isn't configured correctly, then _rogue_ clients can set this header themselves and trick {{book.project.name}} +into thinking the client is connecting from a different IP address than it actually is. This becomes really important if you are doing +any black or white listing of IP addresses. + +Beyond the proxy itself, there are a few things you need to configure on the {{book.project.name}} side of things. +If your proxy is forwarding requests via the HTTP protocol, then you need to configure {{book.project.name}} to pull the client's +IP address from the `X-Forwarded-For` header rather than from the network packet. +To do this, open up the profile configuration file (_standalone.xml, _standalone-ha.xml_, or _domain.xml_ depending on your +<>) and look for the `"urn:jboss:domain:undertow:3.0` XML block. + +.`X-Forwarded-For` HTTP Config +[source,xml] +---- + + + + + + ... + + ... + +---- + +Add the `proxy-address-forwarding` attribute to the `http-listener` element. Set the value to `true`. + +If your proxy is using the AJP protocol instead of HTTP to forward requests (i.e. Apache HTTPD + mod-cluster), then you have +to configure things a little differently. Instead of modifying the `http-listener`, you need to add a filter to +pull this information from the AJP packets. + + +.`X-Forwarded-For` AJP Config +[source,xml] +---- +< + + + + + + ... + + + + ... + + ... + + + +---- + +==== Enable HTTPS/SSL with a Reverse Proxy + +Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port HTTPS traffic is redirected to. +[source,xml] +---- + + ... + + ... + +---- + +Add the `redirect-socket` attribute to the `http-listener` element. The value should be `proxy-https` which points to a +socket binding you also need to define. + +Then add a new `socket-binding` element to the `socket-binding-group` element: + +[source] +---- + + + ... + + ... + +---- + +==== Using the Built-In Load Balancer + +This section covers configuring the built in load balancer that is discussed in the <>. -The link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}} -has information on using some other software based load balancers that may help you. The <> is only designed to run on one machine. To bring up a slave on another host, you'll need to @@ -14,7 +117,9 @@ on one machine. To bring up a slave on another host, you'll need to the _standalone/_ directory. . Edit the _host-slave.xml_ file to change the bind addresses used or override them on the command line -==== Register a New Host With Load Balancer + + +===== Register a New Host With Load Balancer Let's look first at registering the new host slave with the load balancer configuration in _domain.xml_. Open this file and go to the undertow configuration in the `load-balancer` profile. Add a new `host` definition called @@ -60,7 +165,7 @@ binding needs to point to the host and port of the new host. ---- -==== Master Bind Addresses +===== Master Bind Addresses Next thing you'll have to do is to change the `public` and `management` bind addresses for the master host. Either edit the _domain.xml_ file as discussed in the <> chapter @@ -71,7 +176,7 @@ or specify these bind addresses on the command line as follows: $ domain.sh --host-config=host-master.xml -Djboss.bind.address=192.168.0.2 -Djboss.bind.address.management=192.168.0.2 ---- -==== Host Slave Bind Addresses +===== Host Slave Bind Addresses Next you'll have to change the `public`, `management`, and domain controller bind addresses (`jboss.domain.master-address`). Either edit the _host-slave.xml_ file or specify them on the command line as follows: @@ -88,5 +193,11 @@ The values of `jboss.bind.address` and `jboss.bind.addres.management` pertain to The value of `jboss.domain.master.address` need to be the IP address of the domain controller which is the management address of the master host. +==== Configuring Other Load Balancers + +The link:{{book.appserver.loadbalancer.link}}[the load balancer] chapter of the {{book.appserver.loadbalancer.name}} +has information on using some other software based load balancers that may help you. + + diff --git a/topics/network/bind-address.adoc b/topics/network/bind-address.adoc index 884d1a2e60..9619ed0c77 100755 --- a/topics/network/bind-address.adoc +++ b/topics/network/bind-address.adoc @@ -20,7 +20,7 @@ The `-b` switch sets the IP bind address for any public interfaces. Alternatively, if you don't want to set the bind address at the command line, you can edit the profile configuration of your deployment. Open up the profile configuration file (_standalone.xml or _domain.xml_ depending on your -<> and look for the `interfaces` XML block. +<>) and look for the `interfaces` XML block. [source,xml] ---- diff --git a/topics/network/https.adoc b/topics/network/https.adoc index 8557e75fd9..0f70786fd6 100755 --- a/topics/network/https.adoc +++ b/topics/network/https.adoc @@ -22,45 +22,6 @@ all:: The SSL mode for each realm can be configured in the {{book.project.name}} admin console. -==== Enable HTTPS/SSL with a Reverse Proxy - -It is general best practice that {{book.project.name}} will be run in a cluster with a reverse proxy or hardware load balancer -setting in front of {{book.project.name}} server instances. - -To enable SSL/HTTPS in this deployment scenario, it is important that you make sure your reverse proxy sets the `X-Forwarded-For` and `X-Forwarded-Proto` headers on the requests made to {{book.project.name}}. -To make sure that {{book.project.name}} honors these headers, you need to enable the `proxy-address-forwarding` setting of the {{book.project.name}} http connector in {{book.project.name}} configuration. -Assuming that your reverse proxy doesn't use port 8443 for SSL you also need to configure what port http traffic is redirected to. - -. Open _standalone.xml_, _standalone-ha.xml_, or _domain.xml_ file (depends on your <>). - -. Add `proxy-address-forwarding` and `redirect-socket` to the `http-listener` element: - -[source] ----- - - ... - - ... - ----- - -Then add a new `socket-binding` element to the `socket-binding-group` element: - -[source] ----- - - - ... - - ... - ----- - -Also remember that when running in <> what `socket-binding-group` -you modify depends on how you have your server groups configured. - ==== Enabling SSL/HTTPS for the {{book.project.name}} Server If you are not using a reverse proxy or load balancer to handle HTTPS traffic for you, you'll need to enable HTTPS From 33a3e865cacc3b2852ebe9c21d55d372199f03fa Mon Sep 17 00:00:00 2001 From: --add Date: Tue, 10 May 2016 12:50:49 +0530 Subject: [PATCH 090/149] Replaced Keycloak with {{book.project.name}} as applicable --- _book/.gitattributes | 20 + _book/gitbook/app.js | 25001 ++++++++++++++++ .../gitbook/fonts/fontawesome/FontAwesome.otf | Bin 0 -> 75188 bytes .../fonts/fontawesome/fontawesome-webfont.eot | Bin 0 -> 72449 bytes .../fonts/fontawesome/fontawesome-webfont.svg | 504 + .../fonts/fontawesome/fontawesome-webfont.ttf | Bin 0 -> 141564 bytes .../fontawesome/fontawesome-webfont.woff | Bin 0 -> 83760 bytes .../apple-touch-icon-precomposed-152.png | Bin 0 -> 92815 bytes _book/gitbook/images/favicon.ico | Bin 0 -> 4286 bytes .../gitbook-plugin-fontsettings/buttons.js | 151 + .../gitbook-plugin-fontsettings/website.css | 291 + .../gitbook-plugin-highlight/ebook.css | 131 + .../gitbook-plugin-highlight/website.css | 426 + .../gitbook-plugin-livereload/plugin.js | 11 + .../plugins/gitbook-plugin-search/lunr.min.js | 7 + .../plugins/gitbook-plugin-search/search.css | 27 + .../plugins/gitbook-plugin-search/search.js | 135 + .../plugins/gitbook-plugin-sharing/buttons.js | 93 + .../gitbook-plugin-splitter/splitter.css | 22 + .../gitbook-plugin-splitter/splitter.js | 122 + .../gitbook-plugin-toggle-chapters/toggle.css | 0 .../gitbook-plugin-toggle-chapters/toggle.js | 27 + .../plugins/gitbook-plugin-ungrey/ungrey.js | 13 + _book/gitbook/style.css | 9 + _book/gitlab-conversion.py | 103 + _book/images/add-provider-dialog.png | Bin 0 -> 90246 bytes _book/images/add-provider-select.png | Bin 0 -> 60459 bytes _book/images/domain-mode.png | Bin 0 -> 105612 bytes _book/images/domain.png | Bin 0 -> 69245 bytes _book/images/email-simple-example.png | Bin 0 -> 14926 bytes _book/images/identity_broker_flow.png | Bin 0 -> 21625 bytes _book/images/keycloak_logo.png | Bin 0 -> 18350 bytes _book/images/update-server-config-dialog.png | Bin 0 -> 67031 bytes _book/images/update-server-config-select.png | Bin 0 -> 82234 bytes _book/index.html | 782 + _book/keycloak-images/db-module.png | Bin 0 -> 8482 bytes _book/keycloak-images/domain-boot-files.png | Bin 0 -> 6233 bytes _book/keycloak-images/domain-file.png | Bin 0 -> 8746 bytes _book/keycloak-images/domain-json-config.png | Bin 0 -> 7353 bytes _book/keycloak-images/domain-server-dir.png | Bin 0 -> 4581 bytes _book/keycloak-images/files.png | Bin 0 -> 6369 bytes _book/keycloak-images/host-files.png | Bin 0 -> 9027 bytes .../keycloak-images/standalone-boot-files.png | Bin 0 -> 6609 bytes .../standalone-config-file.png | Bin 0 -> 9690 bytes .../standalone-ha-config-file.png | Bin 0 -> 9506 bytes .../standalone-json-config-file.png | Bin 0 -> 9523 bytes _book/rhsso-images/db-module.png | Bin 0 -> 8762 bytes _book/rhsso-images/domain-boot-files.png | Bin 0 -> 5941 bytes _book/rhsso-images/domain-file.png | Bin 0 -> 8964 bytes _book/rhsso-images/domain-json-config.png | Bin 0 -> 7309 bytes _book/rhsso-images/domain-server-dir.png | Bin 0 -> 4705 bytes _book/rhsso-images/files.png | Bin 0 -> 6330 bytes _book/rhsso-images/host-files.png | Bin 0 -> 8933 bytes _book/rhsso-images/standalone-boot-files.png | Bin 0 -> 6260 bytes _book/rhsso-images/standalone-config-file.png | Bin 0 -> 9689 bytes .../standalone-ha-config-file.png | Bin 0 -> 9596 bytes .../standalone-json-config-file.png | Bin 0 -> 9426 bytes _book/search_index.json | 1 + _book/topics/cache.html | 794 + _book/topics/cache/clear.html | 778 + _book/topics/cache/disable.html | 797 + _book/topics/cache/eviction.html | 827 + _book/topics/cache/replication.html | 808 + _book/topics/clustering.html | 804 + _book/topics/clustering/booting.html | 789 + _book/topics/clustering/example.html | 777 + _book/topics/clustering/load-balancer.html | 880 + _book/topics/clustering/multicast.html | 811 + _book/topics/clustering/recommended.html | 791 + _book/topics/clustering/serialized.html | 796 + _book/topics/clustering/troubleshooting.html | 794 + _book/topics/database.html | 805 + _book/topics/database/checklist.html | 798 + _book/topics/database/datasource.html | 832 + _book/topics/database/hibernate.html | 847 + _book/topics/database/jdbc.html | 870 + _book/topics/installation.html | 779 + .../installation/directory-structure.html | 812 + .../distribution-files-community.html | 807 + .../distribution-files-product.adoc | 16 + .../installation/system-requirements.html | 804 + _book/topics/manage.html | 827 + _book/topics/mongo.html | 880 + _book/topics/network.html | 784 + _book/topics/network/bind-address.html | 840 + _book/topics/network/https.html | 1008 + _book/topics/network/outgoing.html | 921 + _book/topics/network/ports.html | 852 + _book/topics/openshift.adoc | 45 + _book/topics/operating-mode.html | 794 + _book/topics/operating-mode/domain.html | 1144 + .../topics/operating-mode/standalone-ha.html | 854 + _book/topics/operating-mode/standalone.html | 856 + _book/topics/overview.html | 789 + .../topics/overview/recommended-reading.html | 792 + _book/topics/proxy.html | 1075 + .../gitbook-plugin-splitter/.npmignore | 3 + .../gitbook-plugin-splitter/LICENSE.txt | 21 + .../gitbook-plugin-splitter/README.md | 34 + .../gitbook-plugin-splitter/book/splitter.css | 22 + .../gitbook-plugin-splitter/book/splitter.js | 122 + .../gitbook-splitter-demo.gif | Bin 0 -> 280642 bytes node_modules/gitbook-plugin-splitter/index.js | 11 + .../gitbook-plugin-splitter/jsconfig.json | 5 + .../gitbook-plugin-splitter/package.json | 48 + node_modules/gitbook-plugin-splitter/tsd.json | 12 + .../gitbook-plugin-toggle-chapters/.npmignore | 25 + .../gitbook-plugin-toggle-chapters/LICENSE | 201 + .../gitbook-plugin-toggle-chapters/README.md | 12 + .../book/toggle.css | 0 .../book/toggle.js | 27 + .../gitbook-plugin-toggle-chapters/index.js | 39 + .../package.json | 46 + node_modules/gitbook-plugin-ungrey/LICENSE | 21 + node_modules/gitbook-plugin-ungrey/README.md | 14 + .../gitbook-plugin-ungrey/book/ungrey.js | 13 + node_modules/gitbook-plugin-ungrey/index.js | 8 + .../gitbook-plugin-ungrey/package.json | 46 + topics/mongo.adoc | 8 +- topics/network/https.adoc | 2 +- topics/openshift.adoc | 24 +- topics/proxy.adoc | 16 +- 122 files changed, 58908 insertions(+), 25 deletions(-) create mode 100644 _book/.gitattributes create mode 100644 _book/gitbook/app.js create mode 100644 _book/gitbook/fonts/fontawesome/FontAwesome.otf create mode 100755 _book/gitbook/fonts/fontawesome/fontawesome-webfont.eot create mode 100755 _book/gitbook/fonts/fontawesome/fontawesome-webfont.svg create mode 100755 _book/gitbook/fonts/fontawesome/fontawesome-webfont.ttf create mode 100755 _book/gitbook/fonts/fontawesome/fontawesome-webfont.woff create mode 100644 _book/gitbook/images/apple-touch-icon-precomposed-152.png create mode 100644 _book/gitbook/images/favicon.ico create mode 100644 _book/gitbook/plugins/gitbook-plugin-fontsettings/buttons.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-fontsettings/website.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-highlight/ebook.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-highlight/website.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-livereload/plugin.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-search/lunr.min.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-search/search.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-search/search.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-sharing/buttons.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-splitter/splitter.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-splitter/splitter.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-toggle-chapters/toggle.css create mode 100644 _book/gitbook/plugins/gitbook-plugin-toggle-chapters/toggle.js create mode 100644 _book/gitbook/plugins/gitbook-plugin-ungrey/ungrey.js create mode 100755 _book/gitbook/style.css create mode 100755 _book/gitlab-conversion.py create mode 100755 _book/images/add-provider-dialog.png create mode 100755 _book/images/add-provider-select.png create mode 100755 _book/images/domain-mode.png create mode 100755 _book/images/domain.png create mode 100755 _book/images/email-simple-example.png create mode 100755 _book/images/identity_broker_flow.png create mode 100755 _book/images/keycloak_logo.png create mode 100755 _book/images/update-server-config-dialog.png create mode 100755 _book/images/update-server-config-select.png create mode 100644 _book/index.html create mode 100755 _book/keycloak-images/db-module.png create mode 100755 _book/keycloak-images/domain-boot-files.png create mode 100755 _book/keycloak-images/domain-file.png create mode 100755 _book/keycloak-images/domain-json-config.png create mode 100755 _book/keycloak-images/domain-server-dir.png create mode 100755 _book/keycloak-images/files.png create mode 100755 _book/keycloak-images/host-files.png create mode 100755 _book/keycloak-images/standalone-boot-files.png create mode 100755 _book/keycloak-images/standalone-config-file.png create mode 100755 _book/keycloak-images/standalone-ha-config-file.png create mode 100755 _book/keycloak-images/standalone-json-config-file.png create mode 100755 _book/rhsso-images/db-module.png create mode 100755 _book/rhsso-images/domain-boot-files.png create mode 100755 _book/rhsso-images/domain-file.png create mode 100755 _book/rhsso-images/domain-json-config.png create mode 100755 _book/rhsso-images/domain-server-dir.png create mode 100755 _book/rhsso-images/files.png create mode 100755 _book/rhsso-images/host-files.png create mode 100755 _book/rhsso-images/standalone-boot-files.png create mode 100755 _book/rhsso-images/standalone-config-file.png create mode 100755 _book/rhsso-images/standalone-ha-config-file.png create mode 100755 _book/rhsso-images/standalone-json-config-file.png create mode 100644 _book/search_index.json create mode 100644 _book/topics/cache.html create mode 100644 _book/topics/cache/clear.html create mode 100644 _book/topics/cache/disable.html create mode 100644 _book/topics/cache/eviction.html create mode 100644 _book/topics/cache/replication.html create mode 100644 _book/topics/clustering.html create mode 100644 _book/topics/clustering/booting.html create mode 100644 _book/topics/clustering/example.html create mode 100644 _book/topics/clustering/load-balancer.html create mode 100644 _book/topics/clustering/multicast.html create mode 100644 _book/topics/clustering/recommended.html create mode 100644 _book/topics/clustering/serialized.html create mode 100644 _book/topics/clustering/troubleshooting.html create mode 100644 _book/topics/database.html create mode 100644 _book/topics/database/checklist.html create mode 100644 _book/topics/database/datasource.html create mode 100644 _book/topics/database/hibernate.html create mode 100644 _book/topics/database/jdbc.html create mode 100644 _book/topics/installation.html create mode 100644 _book/topics/installation/directory-structure.html create mode 100644 _book/topics/installation/distribution-files-community.html create mode 100755 _book/topics/installation/distribution-files-product.adoc create mode 100644 _book/topics/installation/system-requirements.html create mode 100644 _book/topics/manage.html create mode 100644 _book/topics/mongo.html create mode 100644 _book/topics/network.html create mode 100644 _book/topics/network/bind-address.html create mode 100644 _book/topics/network/https.html create mode 100644 _book/topics/network/outgoing.html create mode 100644 _book/topics/network/ports.html create mode 100755 _book/topics/openshift.adoc create mode 100644 _book/topics/operating-mode.html create mode 100644 _book/topics/operating-mode/domain.html create mode 100644 _book/topics/operating-mode/standalone-ha.html create mode 100644 _book/topics/operating-mode/standalone.html create mode 100644 _book/topics/overview.html create mode 100644 _book/topics/overview/recommended-reading.html create mode 100644 _book/topics/proxy.html create mode 100644 node_modules/gitbook-plugin-splitter/.npmignore create mode 100644 node_modules/gitbook-plugin-splitter/LICENSE.txt create mode 100644 node_modules/gitbook-plugin-splitter/README.md create mode 100644 node_modules/gitbook-plugin-splitter/book/splitter.css create mode 100644 node_modules/gitbook-plugin-splitter/book/splitter.js create mode 100644 node_modules/gitbook-plugin-splitter/gitbook-splitter-demo.gif create mode 100644 node_modules/gitbook-plugin-splitter/index.js create mode 100644 node_modules/gitbook-plugin-splitter/jsconfig.json create mode 100644 node_modules/gitbook-plugin-splitter/package.json create mode 100644 node_modules/gitbook-plugin-splitter/tsd.json create mode 100644 node_modules/gitbook-plugin-toggle-chapters/.npmignore create mode 100644 node_modules/gitbook-plugin-toggle-chapters/LICENSE create mode 100644 node_modules/gitbook-plugin-toggle-chapters/README.md create mode 100644 node_modules/gitbook-plugin-toggle-chapters/book/toggle.css create mode 100644 node_modules/gitbook-plugin-toggle-chapters/book/toggle.js create mode 100644 node_modules/gitbook-plugin-toggle-chapters/index.js create mode 100644 node_modules/gitbook-plugin-toggle-chapters/package.json create mode 100644 node_modules/gitbook-plugin-ungrey/LICENSE create mode 100644 node_modules/gitbook-plugin-ungrey/README.md create mode 100644 node_modules/gitbook-plugin-ungrey/book/ungrey.js create mode 100644 node_modules/gitbook-plugin-ungrey/index.js create mode 100644 node_modules/gitbook-plugin-ungrey/package.json diff --git a/_book/.gitattributes b/_book/.gitattributes new file mode 100644 index 0000000000..2b70adf8d8 --- /dev/null +++ b/_book/.gitattributes @@ -0,0 +1,20 @@ +* text=auto + +*.html text eol=lf +*.java text eol=lf +*.js text eol=lf +*.json text eol=lf +*.jsp text eol=lf +*.md text eol=lf +*.properties text eol=lf +*.svg text auto +*.xml text eol=lf +*.xsl text eol=lf + +*.png binary +*.jpg binary +*.gif binary +*.ttf binary +*.eot binary +*.otf binary +*.woff binary diff --git a/_book/gitbook/app.js b/_book/gitbook/app.js new file mode 100644 index 0000000000..46a921bc44 --- /dev/null +++ b/_book/gitbook/app.js @@ -0,0 +1,25001 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 0 && j < len ? [ this[j] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray(src) ? src : []; + + } else { + clone = src && jQuery.isPlainObject(src) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type(obj) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0; + }, + + isPlainObject: function( obj ) { + // Not plain objects: + // - Any object or value whose internal [[Class]] property is not "[object Object]" + // - DOM nodes + // - window + if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.constructor && + !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { + return false; + } + + // If the function hasn't returned already, we're confident that + // |obj| is a plain object, created by {} or constructed with new Object + return true; + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + // Support: Android<4.0, iOS<6 (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call(obj) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + var script, + indirect = eval; + + code = jQuery.trim( code ); + + if ( code ) { + // If the code includes a valid, prologue position + // strict mode pragma, execute code by injecting a + // script tag into the document. + if ( code.indexOf("use strict") === 1 ) { + script = document.createElement("script"); + script.text = code; + document.head.appendChild( script ).parentNode.removeChild( script ); + } else { + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + indirect( code ); + } + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE9-11+ + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + // args is for internal usage only + each: function( obj, callback, args ) { + var value, + i = 0, + length = obj.length, + isArray = isArraylike( obj ); + + if ( args ) { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.apply( obj[ i ], args ); + + if ( value === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } else { + for ( i in obj ) { + value = callback.call( obj[ i ], i, obj[ i ] ); + + if ( value === false ) { + break; + } + } + } + } + + return obj; + }, + + // Support: Android<4.1 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArraylike( Object(arr) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var value, + i = 0, + length = elems.length, + isArray = isArraylike( elems ), + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +}); + +// Populate the class2type map +jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +}); + +function isArraylike( obj ) { + + // Support: iOS 8.2 (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + if ( obj.nodeType === 1 && length ) { + return true; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.2.0-pre + * http://sizzlejs.com/ + * + * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-12-16 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // http://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + // http://www.w3.org/TR/css3-syntax/#characters + characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Loosely modeled on CSS identifier characters + // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors + // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = characterEncoding.replace( "w", "w#" ), + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + characterEncoding + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + characterEncoding + ")" ), + "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), + "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var match, elem, m, nodeType, + // QSA vars + i, groups, old, nid, newContext, newSelector; + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + + context = context || document; + results = results || []; + nodeType = context.nodeType; + + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + if ( !seed && documentIsHTML ) { + + // Try to shortcut find operations when possible (e.g., not under DocumentFragment) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + // Speed-up: Sizzle("#ID") + if ( (m = match[1]) ) { + if ( nodeType === 9 ) { + elem = context.getElementById( m ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document (jQuery #6963) + if ( elem && elem.parentNode ) { + // Handle the case where IE, Opera, and Webkit return items + // by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + } else { + // Context is not a document + if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && + contains( context, elem ) && elem.id === m ) { + results.push( elem ); + return results; + } + } + + // Speed-up: Sizzle("TAG") + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Speed-up: Sizzle(".CLASS") + } else if ( (m = match[3]) && support.getElementsByClassName ) { + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // QSA path + if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + nid = old = expando; + newContext = context; + newSelector = nodeType !== 1 && selector; + + // qSA works strangely on Element-rooted queries + // We can work around this by specifying an extra ID on the root + // and working up from there (Thanks to Andrew Dupont for the technique) + // IE 8 doesn't work on object elements + if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { + groups = tokenize( selector ); + + if ( (old = context.getAttribute("id")) ) { + nid = old.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", nid ); + } + nid = "[id='" + nid + "'] "; + + i = groups.length; + while ( i-- ) { + groups[i] = nid + toSelector( groups[i] ); + } + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context; + newSelector = groups.join(","); + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch(qsaError) { + } finally { + if ( !old ) { + context.removeAttribute("id"); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {Function(string, Object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = attrs.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, parent, + doc = node ? node.ownerDocument || node : preferredDoc; + + // If no document and documentElement is available, return + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Set our document + document = doc; + docElem = doc.documentElement; + parent = doc.defaultView; + + // Support: IE>8 + // If iframe document is assigned to "document" variable and if iframe has been reloaded, + // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936 + // IE6-8 do not support the defaultView property so parent will be undefined + if ( parent && parent !== parent.top ) { + // IE11 does not have attachEvent, so all must suffer + if ( parent.addEventListener ) { + parent.addEventListener( "unload", unloadHandler, false ); + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", unloadHandler ); + } + } + + /* Support tests + ---------------------------------------------------------------------- */ + documentIsHTML = !isXML( doc ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( doc.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( doc.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !doc.getElementsByName || !doc.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + // Check parentNode to catch when Blackberry 4.6 returns + // nodes that are no longer in the document #6963 + return m && m.parentNode ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + docElem.appendChild( div ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+ + if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibing-combinator selector` fails + if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = doc.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully does not implement inclusive descendent + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === doc ? -1 : + b === doc ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return doc; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, outerCache, node, diff, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + // Seek `elem` from a previously-cached index + outerCache = parent[ expando ] || (parent[ expando ] = {}); + cache = outerCache[ type ] || []; + nodeIndex = cache[0] === dirruns && cache[1]; + diff = cache[0] === dirruns && cache[2]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + outerCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + // Use previously-cached element index if available + } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { + diff = cache[1]; + + // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) + } else { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { + // Cache the index of each encountered element + if ( useCache ) { + (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + if ( (oldCache = outerCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + outerCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context !== document && context; + } + + // Add elements passing elementMatchers directly to results + // Keep `i` a string if there are no elements so `matchedCount` will be "00" below + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // Apply set filters to unmatched elements + matchedCount += i; + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is no seed and only one group + if ( match.length === 1 ) { + + // Take a shortcut and set the context if the root selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.pseudos; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + }); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + }); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) >= 0 ) !== not; + }); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + })); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var i, + len = this.length, + ret = [], + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter(function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow(this, selector || [], false) ); + }, + not: function( selector ) { + return this.pushStack( winnow(this, selector || [], true) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +}); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) { + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + context = context instanceof jQuery ? context[0] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[1], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[2] ); + + // Support: Blackberry 4.6 + // gEBID returns nodes no longer in the document (#6963) + if ( elem && elem.parentNode ) { + // Inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || rootjQuery ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return typeof rootjQuery.ready !== "undefined" ? + rootjQuery.ready( selector ) : + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.extend({ + dir: function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; + }, + + sibling: function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; + } +}); + +jQuery.fn.extend({ + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter(function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) { + // Always skip document fragments + if ( cur.nodeType < 11 && (pos ? + pos.index(cur) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector(cur, selectors)) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.unique( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter(selector) + ); + } +}); + +function sibling( cur, dir ) { + while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.unique( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +}); +var rnotwhite = (/\S+/g); + + + +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache +function createOptions( options ) { + var object = optionsCache[ options ] = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + }); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + ( optionsCache[ options ] || createOptions( options ) ) : + jQuery.extend( {}, options ); + + var // Last fire value (for non-forgettable lists) + memory, + // Flag to know if list was already fired + fired, + // Flag to know if list is currently firing + firing, + // First callback to fire (used internally by add and fireWith) + firingStart, + // End of the loop when firing + firingLength, + // Index of currently firing callback (modified by remove if needed) + firingIndex, + // Actual callback list + list = [], + // Stack of fire calls for repeatable lists + stack = !options.once && [], + // Fire callbacks + fire = function( data ) { + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { + memory = false; // To prevent further calls using add + break; + } + } + firing = false; + if ( list ) { + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } + } else if ( memory ) { + list = []; + } else { + self.disable(); + } + } + }, + // Actual Callbacks object + self = { + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + // First, we save the current length + var start = list.length; + (function add( args ) { + jQuery.each( args, function( _, arg ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && type !== "string" ) { + // Inspect recursively + add( arg ); + } + }); + })( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); + } + } + return this; + }, + // Remove a callback from the list + remove: function() { + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } + } + }); + } + return this; + }, + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + }, + // Remove all callbacks from the list + empty: function() { + list = []; + firingLength = 0; + return this; + }, + // Have the list do nothing anymore + disable: function() { + list = stack = memory = undefined; + return this; + }, + // Is it disabled? + disabled: function() { + return !list; + }, + // Lock the list in its current state + lock: function() { + stack = undefined; + if ( !memory ) { + self.disable(); + } + return this; + }, + // Is it locked? + locked: function() { + return !stack; + }, + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( list && ( !fired || stack ) ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + if ( firing ) { + stack.push( args ); + } else { + fire( args ); + } + } + return this; + }, + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend({ + + Deferred: function( func ) { + var tuples = [ + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], + [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], + [ "notify", "progress", jQuery.Callbacks("memory") ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred(function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[1] ](function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .done( newDefer.resolve ) + .fail( newDefer.reject ) + .progress( newDefer.notify ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); + } + }); + }); + fns = null; + }).promise(); + }, + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[1] ] = list.add; + + // Handle state + if ( stateString ) { + list.add(function() { + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[0] ] = function() { + deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[0] + "With" ] = list.fireWith; + }); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // Add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ) + .progress( updateFunc( i, progressContexts, progressValues ) ); + } else { + --remaining; + } + } + } + + // If we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +}); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend({ + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +}); + +/** + * The ready event handler and self cleanup method + */ +function completed() { + document.removeEventListener( "DOMContentLoaded", completed, false ); + window.removeEventListener( "load", completed, false ); + jQuery.ready(); +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called after the browser event has already occurred. + // We once tried to use readyState "interactive" here, but it caused issues like the one + // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 + if ( document.readyState === "complete" ) { + // Handle it asynchronously to allow scripts the opportunity to delay ready + setTimeout( jQuery.ready ); + + } else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed, false ); + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + len ? fn( elems[0], key ) : emptyGet; +}; + + +/** + * Determines whether an object can have data + */ +jQuery.acceptData = function( owner ) { + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + /* jshint -W018 */ + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + +function Data() { + // Support: Android<4, + // Old WebKit does not have Object.preventExtensions/freeze method, + // return new empty object instead with no [[set]] accessor + Object.defineProperty( this.cache = {}, 0, { + get: function() { + return {}; + } + }); + + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; +Data.accepts = jQuery.acceptData; + +Data.prototype = { + key: function( owner ) { + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return the key for a frozen object. + if ( !Data.accepts( owner ) ) { + return 0; + } + + var descriptor = {}, + // Check if the owner object already has a cache key + unlock = owner[ this.expando ]; + + // If not, create one + if ( !unlock ) { + unlock = Data.uid++; + + // Secure it in a non-enumerable, non-writable property + try { + descriptor[ this.expando ] = { value: unlock }; + Object.defineProperties( owner, descriptor ); + + // Support: Android<4 + // Fallback to a less secure definition + } catch ( e ) { + descriptor[ this.expando ] = unlock; + jQuery.extend( owner, descriptor ); + } + } + + // Ensure the cache object + if ( !this.cache[ unlock ] ) { + this.cache[ unlock ] = {}; + } + + return unlock; + }, + set: function( owner, data, value ) { + var prop, + // There may be an unlock assigned to this node, + // if there is no entry for this "owner", create one inline + // and set the unlock as though an owner entry had always existed + unlock = this.key( owner ), + cache = this.cache[ unlock ]; + + // Handle: [ owner, key, value ] args + if ( typeof data === "string" ) { + cache[ data ] = value; + + // Handle: [ owner, { properties } ] args + } else { + // Fresh assignments by object are shallow copied + if ( jQuery.isEmptyObject( cache ) ) { + jQuery.extend( this.cache[ unlock ], data ); + // Otherwise, copy the properties one-by-one to the cache object + } else { + for ( prop in data ) { + cache[ prop ] = data[ prop ]; + } + } + } + return cache; + }, + get: function( owner, key ) { + // Either a valid cache is found, or will be created. + // New caches will be created and the unlock returned, + // allowing direct access to the newly created + // empty data object. A valid owner object must be provided. + var cache = this.cache[ this.key( owner ) ]; + + return key === undefined ? + cache : cache[ key ]; + }, + access: function( owner, key, value ) { + var stored; + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ((key && typeof key === "string") && value === undefined) ) { + + stored = this.get( owner, key ); + + return stored !== undefined ? + stored : this.get( owner, jQuery.camelCase(key) ); + } + + // [*]When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, name, camel, + unlock = this.key( owner ), + cache = this.cache[ unlock ]; + + if ( key === undefined ) { + this.cache[ unlock ] = {}; + + } else { + // Support array or space separated string of keys + if ( jQuery.isArray( key ) ) { + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = key.concat( key.map( jQuery.camelCase ) ); + } else { + camel = jQuery.camelCase( key ); + // Try the string as a key before any manipulation + if ( key in cache ) { + name = [ key, camel ]; + } else { + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + name = camel; + name = name in cache ? + [ name ] : ( name.match( rnotwhite ) || [] ); + } + } + + i = name.length; + while ( i-- ) { + delete cache[ name[ i ] ]; + } + } + }, + hasData: function( owner ) { + return !jQuery.isEmptyObject( + this.cache[ owner[ this.expando ] ] || {} + ); + }, + discard: function( owner ) { + if ( owner[ this.expando ] ) { + delete this.cache[ owner[ this.expando ] ]; + } + } +}; +var data_priv = new Data(); + +var data_user = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /([A-Z])/g; + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch( e ) {} + + // Make sure we set the data so it isn't changed later + data_user.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend({ + hasData: function( elem ) { + return data_user.hasData( elem ) || data_priv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return data_user.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + data_user.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to data_priv methods, these can be deprecated. + _data: function( elem, name, data ) { + return data_priv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + data_priv.remove( elem, name ); + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = data_user.get( elem ); + + if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice(5) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + data_priv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each(function() { + data_user.set( this, key ); + }); + } + + return access( this, function( value ) { + var data, + camelKey = jQuery.camelCase( key ); + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + // Attempt to get data from the cache + // with the key as-is + data = data_user.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to get data from the cache + // with the key camelized + data = data_user.get( elem, camelKey ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, camelKey, undefined ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each(function() { + // First, attempt to store a copy or reference of any + // data that might've been store with a camelCased key. + var data = data_user.get( this, camelKey ); + + // For HTML5 data-* attribute interop, we have to + // store property names with dashes in a camelCase form. + // This might not apply to all properties...* + data_user.set( this, camelKey, value ); + + // *... In the case of properties that might _actually_ + // have dashes, we need to also store a copy of that + // unchanged property. + if ( key.indexOf("-") !== -1 && data !== undefined ) { + data_user.set( this, key, value ); + } + }); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each(function() { + data_user.remove( this, key ); + }); + } +}); + + +jQuery.extend({ + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = data_priv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = data_priv.access( elem, type, jQuery.makeArray(data) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return data_priv.get( elem, key ) || data_priv.access( elem, key, { + empty: jQuery.Callbacks("once memory").add(function() { + data_priv.remove( elem, [ type + "queue", key ] ); + }) + }); + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[0], type ); + } + + return data === undefined ? + this : + this.each(function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = data_priv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +}); +var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source; + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); + }; + +var rcheckableType = (/^(?:checkbox|radio)$/i); + + + +(function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Safari<=5.1 + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari<=5.1, Android<4.2 + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<=11+ + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +})(); +var strundefined = typeof undefined; + + + +support.focusinBubbles = "onfocusin" in window; + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, + rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = data_priv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !(events = elemData.events) ) { + events = elemData.events = {}; + } + if ( !(eventHandle = elemData.handle) ) { + eventHandle = elemData.handle = function( e ) { + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend({ + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join(".") + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !(handlers = events[ type ]) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = data_priv.hasData( elem ) && data_priv.get( elem ); + + if ( !elemData || !(events = elemData.events) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[t] ) || []; + type = origType = tmp[1]; + namespaces = ( tmp[2] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + delete elemData.handle; + data_priv.remove( elem, "events" ); + } + }, + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; + + cur = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf(":") < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join("."); + event.namespace_re = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === (elem.ownerDocument || document) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { + + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && jQuery.acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) && + jQuery.acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + elem[ type ](); + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[0] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) + .apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( (event.result = ret) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // Avoid non-left-click bubbling in Firefox (#3861) + if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.disabled !== true || event.type !== "click" ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) >= 0 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push({ elem: cur, handlers: matches }); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); + } + + return handlerQueue; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split(" "), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: Cordova 2.5 (WebKit) (#13255) + // All events should have a target; Cordova deviceready doesn't + if ( !event.target ) { + event.target = document; + } + + // Support: Safari 6.0+, Chrome<28 + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + }, + + simulate: function( type, elem, event, bubble ) { + // Piggyback on a donor event to simulate a different one. + // Fake originalEvent to avoid donor's stopPropagation, but if the + // simulated event prevents default then we do the same on the donor. + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true, + originalEvent: {} + } + ); + if ( bubble ) { + jQuery.event.trigger( e, null, elem ); + } else { + jQuery.event.dispatch.call( elem, e ); + } + if ( e.isDefaultPrevented() ) { + event.preventDefault(); + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle, false ); + } +}; + +jQuery.Event = function( src, props ) { + // Allow instantiation without the 'new' keyword + if ( !(this instanceof jQuery.Event) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + // Support: Android<4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && e.preventDefault ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && e.stopPropagation ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +// Support: Chrome 15+ +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || (related !== target && !jQuery.contains( target, related )) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +}); + +// Support: Firefox, Chrome, Safari +// Create "bubbling" focus and blur events +if ( !support.focusinBubbles ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + var doc = this.ownerDocument || this, + attaches = data_priv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + data_priv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this, + attaches = data_priv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + data_priv.remove( doc, fix ); + + } else { + data_priv.access( doc, fix, attaches ); + } + } + }; + }); +} + +jQuery.fn.extend({ + + on: function( types, selector, data, fn, /*INTERNAL*/ one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + this.on( type, selector, data, types[ type ], one ); + } + return this; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return this; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return this.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); + }, + one: function( types, selector, data, fn ) { + return this.on( types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each(function() { + jQuery.event.remove( this, types, fn, selector ); + }); + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + triggerHandler: function( type, data ) { + var elem = this[0]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +}); + + +var + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + rtagName = /<([\w:]+)/, + rhtml = /<|&#?\w+;/, + rnoInnerhtml = /<(?:script|style|link)/i, + // checked="checked" or checked + rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, + rscriptType = /^$|\/(?:java|ecma)script/i, + rscriptTypeMasked = /^true\/(.*)/, + rcleanScript = /^\s*\s*$/g, + + // We have to close these tags to support XHTML (#13200) + wrapMap = { + + // Support: IE9 + option: [ 1, "" ], + + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] + }; + +// Support: IE9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: 1.x compatibility +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName("tbody")[0] || + elem.appendChild( elem.ownerDocument.createElement("tbody") ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute("type"); + } + + return elem; +} + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + data_priv.set( + elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" ) + ); + } +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( data_priv.hasData( src ) ) { + pdataOld = data_priv.access( src ); + pdataCur = data_priv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( data_user.hasData( src ) ) { + udataOld = data_user.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + data_user.set( dest, udataCur ); + } +} + +function getAll( context, tag ) { + var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) : + context.querySelectorAll ? context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +jQuery.extend({ + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + buildFragment: function( elems, context, scripts, selection ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + // Support: QtWebKit, PhantomJS + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement("div") ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: QtWebKit, PhantomJS + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( (elem = nodes[ i++ ]) ) { + + // #4087 - If origin and destination elements are the same, and this is + // that element, do not do anything + if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( (elem = tmp[ j++ ]) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; + }, + + cleanData: function( elems ) { + var data, elem, type, key, + special = jQuery.event.special, + i = 0; + + for ( ; (elem = elems[ i ]) !== undefined; i++ ) { + if ( jQuery.acceptData( elem ) ) { + key = elem[ data_priv.expando ]; + + if ( key && (data = data_priv.cache[ key ]) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + if ( data_priv.cache[ key ] ) { + // Discard any remaining `private` data + delete data_priv.cache[ key ]; + } + } + } + // Discard any remaining `user` data + delete data_user.cache[ elem[ data_user.expando ] ]; + } + } +}); + +jQuery.fn.extend({ + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each(function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + }); + }, null, value, arguments.length ); + }, + + append: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + }); + }, + + prepend: function() { + return this.domManip( arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + }); + }, + + before: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + }); + }, + + after: function() { + return this.domManip( arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + }); + }, + + remove: function( selector, keepData /* Internal Use Only */ ) { + var elem, + elems = selector ? jQuery.filter( selector, this ) : this, + i = 0; + + for ( ; (elem = elems[i]) != null; i++ ) { + if ( !keepData && elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem ) ); + } + + if ( elem.parentNode ) { + if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { + setGlobalEval( getAll( elem, "script" ) ); + } + elem.parentNode.removeChild( elem ); + } + } + + return this; + }, + + empty: function() { + var elem, + i = 0; + + for ( ; (elem = this[i]) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map(function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + }); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = value.replace( rxhtmlTag, "<$1>" ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var arg = arguments[ 0 ]; + + // Make the changes, replacing each context element with the new content + this.domManip( arguments, function( elem ) { + arg = this.parentNode; + + jQuery.cleanData( getAll( this ) ); + + if ( arg ) { + arg.replaceChild( elem, this ); + } + }); + + // Force removal if there was no new content (e.g., from empty arguments) + return arg && (arg.length || arg.nodeType) ? this : this.remove(); + }, + + detach: function( selector ) { + return this.remove( selector, true ); + }, + + domManip: function( args, callback ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = this.length, + set = this, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return this.each(function( index ) { + var self = set.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + self.domManip( args, callback ); + }); + } + + if ( l ) { + fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + if ( first ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + // Support: QtWebKit + // jQuery.merge because push.apply(_, arraylike) throws + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( this[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) { + + if ( node.src ) { + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); + } + } + } + } + } + } + + return this; + } +}); + +jQuery.each({ + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: QtWebKit + // .get() because push.apply(_, arraylike) throws + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +}); + + +var iframe, + elemdisplay = {}; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + // getDefaultComputedStyle might be reliably used only on attached element + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? + + // Use of this method is a temporary fix (more like optimization) until something better comes along, + // since it was removed from specification and supported only in FF + style.display : jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = (iframe || jQuery( "

  • ?a>sFpT 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 NIjOt1vL$q%{~!6q$Ql3u literal 0 HcmV?d00001 diff --git a/images/add-provider-select.png b/images/add-provider-select.png new file mode 100755 index 0000000000000000000000000000000000000000..1c2e51af89a1ec5e06c8f41b0dd409cd2dbe3429 GIT binary patch literal 60459 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 literal 0 HcmV?d00001 diff --git a/images/domain-mode.png b/images/domain-mode.png new file mode 100755 index 0000000000000000000000000000000000000000..9d96bd0624d7c2225e34263fe88f9aab152d8df3 GIT binary patch literal 105612 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≧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