Compare commits
1020
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a249b74e3 | ||
|
|
3b160d6313 | ||
|
|
aad5cfe897 | ||
|
|
aba7495d9d | ||
|
|
b1033c3ed1 | ||
|
|
bf0d1a3133 | ||
|
|
fe84b53c50 | ||
|
|
40adf58ef2 | ||
|
|
1bcb77f000 | ||
|
|
ea89ad4d5c | ||
|
|
912ed11a62 | ||
|
|
caef494c69 | ||
|
|
10987b4a06 | ||
|
|
e600fc9694 | ||
|
|
b4fd43be18 | ||
|
|
57a153c11e | ||
|
|
d55a5d3f4b | ||
|
|
3a2addc7d4 | ||
|
|
77d65941d6 | ||
|
|
9774ca7170 | ||
|
|
06e5027c9f | ||
|
|
9aa0e49839 | ||
|
|
661d2ba68f | ||
|
|
20c3176e38 | ||
|
|
240a5ef0e5 | ||
|
|
adb7700a62 | ||
|
|
cbfa7ef6e9 | ||
|
|
7bb71c757c | ||
|
|
fb0519c3a0 | ||
|
|
145ae5a740 | ||
|
|
534a1a336c | ||
|
|
fc5d1bea1d | ||
|
|
91dd570ecc | ||
|
|
e3b3381f07 | ||
|
|
2e6d884153 | ||
|
|
64582ad8fb | ||
|
|
966fba8cd7 | ||
|
|
f29332be96 | ||
|
|
06a9c7e35d | ||
|
|
08a5c790b2 | ||
|
|
538dc2da2c | ||
|
|
6b1287a553 | ||
|
|
256ca2b665 | ||
|
|
e4412523d4 | ||
|
|
073d82b367 | ||
|
|
484c5ebb15 | ||
|
|
4c33704c56 | ||
|
|
511763d4bc | ||
|
|
605c80a68d | ||
|
|
2325143803 | ||
|
|
9cc5ca3ce4 | ||
|
|
d13c120b6c | ||
|
|
9942c7b519 | ||
|
|
4587fd23b6 | ||
|
|
c21b56d596 | ||
|
|
4ee5c32b1e | ||
|
|
6386d95904 | ||
|
|
f99395aebe | ||
|
|
82a7173dba | ||
|
|
2bf6f4b0fd | ||
|
|
d8e90028af | ||
|
|
d2afb4892a | ||
|
|
eb9f69eee0 | ||
|
|
39f985e04a | ||
|
|
41a51d924b | ||
|
|
ce996f6a41 | ||
|
|
244848afc4 | ||
|
|
2910db5595 | ||
|
|
a6556a49c2 | ||
|
|
e4961056db | ||
|
|
c8eee38471 | ||
|
|
1e4b3fc3b6 | ||
|
|
14426f26f2 | ||
|
|
19ad846306 | ||
|
|
235ffb2ff6 | ||
|
|
181fdeb0d0 | ||
|
|
8674578d0d | ||
|
|
9cf4186eb2 | ||
|
|
92ed01a61b | ||
|
|
99028e9cab | ||
|
|
20f18eec15 | ||
|
|
67435791ed | ||
|
|
b4520baee5 | ||
|
|
802a39b1ce | ||
|
|
229b964867 | ||
|
|
b413bcb41d | ||
|
|
0c39e30241 | ||
|
|
11a8d3842e | ||
|
|
2c460c3adc | ||
|
|
aaddaa6c25 | ||
|
|
96099e0798 | ||
|
|
e582de2837 | ||
|
|
e1fc863421 | ||
|
|
7de4051c9b | ||
|
|
5b7b5b1b60 | ||
|
|
f8effaee58 | ||
|
|
bf7d43fffb | ||
|
|
870702fd81 | ||
|
|
2a3e5fa7a4 | ||
|
|
90063cafec | ||
|
|
2b6fcc05e1 | ||
|
|
f585ed5582 | ||
|
|
192387047f | ||
|
|
78664e2571 | ||
|
|
bc71739fb2 | ||
|
|
5563118d79 | ||
|
|
aadd63e2b0 | ||
|
|
59d548228a | ||
|
|
68c3f2f65b | ||
|
|
b54bb25121 | ||
|
|
7f65a2be16 | ||
|
|
b907f8f92c | ||
|
|
3381ed50d1 | ||
|
|
c2c2b835b2 | ||
|
|
f92fe6bea9 | ||
|
|
6aa029784a | ||
|
|
325072c74d | ||
|
|
1e48143db0 | ||
|
|
8c72ef2980 | ||
|
|
e7febbd5a5 | ||
|
|
d9211d6bc9 | ||
|
|
8121a9391f | ||
|
|
65b05fd4e4 | ||
|
|
940c9f8bf1 | ||
|
|
c85e0248dd | ||
|
|
2ec143a3ba | ||
|
|
a279ff3d7f | ||
|
|
128c26043b | ||
|
|
fe9b5a6588 | ||
|
|
0f93e72b02 | ||
|
|
bdba5ff8b1 | ||
|
|
7071161a7c | ||
|
|
672103e363 | ||
|
|
f579d7ffe9 | ||
|
|
d1f0b353e8 | ||
|
|
ef56dca050 | ||
|
|
07c3772b08 | ||
|
|
85a886da18 | ||
|
|
4ce93171ba | ||
|
|
c987d57b9e | ||
|
|
a416327124 | ||
|
|
285ef50341 | ||
|
|
0d22074826 | ||
|
|
b76fb68ff7 | ||
|
|
f03128f5ed | ||
|
|
8fb05bacd1 | ||
|
|
f8842b3df1 | ||
|
|
b376d1fb6d | ||
|
|
d4e0901599 | ||
|
|
217c359530 | ||
|
|
4fbf6841be | ||
|
|
2deb20a2c9 | ||
|
|
20b92c410f | ||
|
|
1d829a8365 | ||
|
|
10b4bd24a4 | ||
|
|
788501f13d | ||
|
|
345bea50b6 | ||
|
|
ab7bfa6d90 | ||
|
|
4f7979d9fc | ||
|
|
286458b94a | ||
|
|
61a8c422df | ||
|
|
baaf445727 | ||
|
|
2faf0eccdb | ||
|
|
639b5b617b | ||
|
|
115663a32d | ||
|
|
b277afa6d9 | ||
|
|
960cd8c822 | ||
|
|
4acc69c604 | ||
|
|
0230e008c5 | ||
|
|
382b8d60d0 | ||
|
|
0ad29c9737 | ||
|
|
9ced56d8d7 | ||
|
|
eb197c46f7 | ||
|
|
63947cd37a | ||
|
|
938ce9612c | ||
|
|
d6119c04d6 | ||
|
|
14646781ad | ||
|
|
1b41832946 | ||
|
|
57d0bac96a | ||
|
|
2ca3ce2dba | ||
|
|
e5d404fdb3 | ||
|
|
8829fe8658 | ||
|
|
9ccb0b1f65 | ||
|
|
7bb70f2d00 | ||
|
|
3ab7edbbcd | ||
|
|
d4060cce92 | ||
|
|
1342904fae | ||
|
|
fc0a3c3e73 | ||
|
|
756a9f095c | ||
|
|
021e48d6d6 | ||
|
|
91f78c61b7 | ||
|
|
d39aee0a72 | ||
|
|
7c600e2f4b | ||
|
|
14079b950a | ||
|
|
173c112f8e | ||
|
|
67d8ca0207 | ||
|
|
e690f4e645 | ||
|
|
4c554b4af6 | ||
|
|
3aee5eeecf | ||
|
|
366a1629e5 | ||
|
|
7fec1677ee | ||
|
|
8e391ffa4e | ||
|
|
d65ce5d1d4 | ||
|
|
6741dffe38 | ||
|
|
894af03323 | ||
|
|
80dea9c0bd | ||
|
|
0b83325470 | ||
|
|
368ea64b51 | ||
|
|
450e031da9 | ||
|
|
1796a45a68 | ||
|
|
c9437595b7 | ||
|
|
a1b315adbd | ||
|
|
1781588597 | ||
|
|
f29aff4bed | ||
|
|
ac91839e69 | ||
|
|
9c0c8e37b6 | ||
|
|
d40237b08d | ||
|
|
59527e12f0 | ||
|
|
6d0483667f | ||
|
|
dcf8747d7e | ||
|
|
7a3b4823b0 | ||
|
|
64ecc3b153 | ||
|
|
cc41a1fd78 | ||
|
|
255b1cb3bf | ||
|
|
a1bb202bd4 | ||
|
|
332e3f6099 | ||
|
|
6b41d79058 | ||
|
|
3b4b5c11e6 | ||
|
|
0c9e764e11 | ||
|
|
00cbc22d8b | ||
|
|
0a3de09b5a | ||
|
|
4e0ad5ac0b | ||
|
|
72256fd6ac | ||
|
|
d06237a3fd | ||
|
|
28fad68486 | ||
|
|
53b86cbace | ||
|
|
a53aebcddf | ||
|
|
af307c695a | ||
|
|
7816f053a6 | ||
|
|
ed54ba9064 | ||
|
|
8acdaf462b | ||
|
|
c5efd34a46 | ||
|
|
75343986b0 | ||
|
|
424d357c9c | ||
|
|
56116038d6 | ||
|
|
c76da8f3b8 | ||
|
|
589eb3206e | ||
|
|
5419ec32e4 | ||
|
|
c9e0a7a97d | ||
|
|
5b5f99fdfe | ||
|
|
d3bd0a67a7 | ||
|
|
2a36185419 | ||
|
|
76e3c6394c | ||
|
|
9e15b20591 | ||
|
|
05bd51ac1c | ||
|
|
d648ba73de | ||
|
|
c6b34f32a1 | ||
|
|
974c0a50e7 | ||
|
|
07d3b26722 | ||
|
|
510b03476f | ||
|
|
4f6d3c8dca | ||
|
|
95fe2fe74b | ||
|
|
e937216cf7 | ||
|
|
fd8d93663e | ||
|
|
a048cfc102 | ||
|
|
272272634d | ||
|
|
01947f46b9 | ||
|
|
5ec73a81e9 | ||
|
|
4cba764ac3 | ||
|
|
84b9963609 | ||
|
|
99c216635f | ||
|
|
25a6fcc382 | ||
|
|
acefd3cacd | ||
|
|
15a5c87cc5 | ||
|
|
3044138e10 | ||
|
|
6fbb8ccf71 | ||
|
|
018866aa81 | ||
|
|
18b2b572ac | ||
|
|
d9e67aa5ee | ||
|
|
e675ce44d5 | ||
|
|
df46a8ea0d | ||
|
|
e277d5b55e | ||
|
|
4bd1d899db | ||
|
|
3e3d92c2e4 | ||
|
|
55deedd3b8 | ||
|
|
8b6251eb23 | ||
|
|
35919da0a4 | ||
|
|
ec018d2739 | ||
|
|
b1a23a13d6 | ||
|
|
3ebbe96786 | ||
|
|
cfaa4c60c9 | ||
|
|
e104450fc8 | ||
|
|
c22b0f4da8 | ||
|
|
302d0b58cc | ||
|
|
72999f0acb | ||
|
|
a942322d99 | ||
|
|
8902502c4d | ||
|
|
8d19741f53 | ||
|
|
e60549d764 | ||
|
|
0a42a28eeb | ||
|
|
88355d7eb4 | ||
|
|
67db5917ac | ||
|
|
8f1daf5d77 | ||
|
|
6d5e3b2a17 | ||
|
|
75c0d5089f | ||
|
|
5b1fcbfc51 | ||
|
|
0c80255f3a | ||
|
|
121f8e9174 | ||
|
|
c1cb50b39f | ||
|
|
791a740f32 | ||
|
|
546cdd7d8f | ||
|
|
8ef6602f82 | ||
|
|
2938759db4 | ||
|
|
f7bcca8553 | ||
|
|
4eaf893492 | ||
|
|
0ba6ab198a | ||
|
|
49a530f2b4 | ||
|
|
c14d3d7963 | ||
|
|
fe26d6ecec | ||
|
|
35a00b449d | ||
|
|
1e9c09d23a | ||
|
|
ec4f8a7f15 | ||
|
|
d109bf7b56 | ||
|
|
4625ab917d | ||
|
|
7d239f8990 | ||
|
|
22f7efd977 | ||
|
|
2a349673b9 | ||
|
|
361019fc6a | ||
|
|
abb099745f | ||
|
|
046edbbd54 | ||
|
|
8cc4c8c5e2 | ||
|
|
d2d3a3f216 | ||
|
|
cbf5c920ea | ||
|
|
7ac1d1f14c | ||
|
|
e811b87679 | ||
|
|
d08fca4e0a | ||
|
|
30aa41a2ee | ||
|
|
9d8d690100 | ||
|
|
43541d3028 | ||
|
|
880e831e71 | ||
|
|
fe2278b320 | ||
|
|
f7a8bbbcc8 | ||
|
|
fde4bc99aa | ||
|
|
cc9d6d0cf7 | ||
|
|
b17bbc9b86 | ||
|
|
d4c5349e1a | ||
|
|
2865a3c047 | ||
|
|
522fc7412c | ||
|
|
7ec3f86efb | ||
|
|
c11539cccb | ||
|
|
09488b8df3 | ||
|
|
e16cc493d2 | ||
|
|
379fc8961e | ||
|
|
43114f176b | ||
|
|
f01d959f7c | ||
|
|
28f4409768 | ||
|
|
364aecda2a | ||
|
|
9bfbac6be5 | ||
|
|
db20fd9eeb | ||
|
|
53a198fde8 | ||
|
|
861a13501a | ||
|
|
0f24bd2ea4 | ||
|
|
9dc54815eb | ||
|
|
cb8ca619ae | ||
|
|
ac91deac96 | ||
|
|
71e2be5d3d | ||
|
|
4878073867 | ||
|
|
dc327ddddb | ||
|
|
e6467403ef | ||
|
|
cf0fab2d66 | ||
|
|
2eaa03539c | ||
|
|
b7e49dc88d | ||
|
|
ca05455aa0 | ||
|
|
7ae3eb8321 | ||
|
|
ae54babbbb | ||
|
|
a8378fe84b | ||
|
|
85df0b6a67 | ||
|
|
95967b9c79 | ||
|
|
8396b999a2 | ||
|
|
3bbe82057c | ||
|
|
0c49fce78f | ||
|
|
f9af8ba1a0 | ||
|
|
80f91b5fa5 | ||
|
|
6478e8f5c7 | ||
|
|
55dc42e147 | ||
|
|
f55ab0d689 | ||
|
|
fe79c9b01e | ||
|
|
6291e90f9c | ||
|
|
a32fefb597 | ||
|
|
3e04d045ee | ||
|
|
fb4645a3dc | ||
|
|
e0eac89e5a | ||
|
|
90d34bfd06 | ||
|
|
e58b5762f3 | ||
|
|
3fd4d23bed | ||
|
|
1c38bb7158 | ||
|
|
149ef706dd | ||
|
|
75bd8d4627 | ||
|
|
f1c40dd345 | ||
|
|
6225ccfc06 | ||
|
|
34de631b2a | ||
|
|
86f0092622 | ||
|
|
e455cbf319 | ||
|
|
cee2d69718 | ||
|
|
ff17123123 | ||
|
|
e118a06a09 | ||
|
|
4898d74c6d | ||
|
|
76f3842dad | ||
|
|
d818ebdd9e | ||
|
|
4d90898dd9 | ||
|
|
298b9e01d8 | ||
|
|
d0b08cacd8 | ||
|
|
050c65a520 | ||
|
|
be0c359160 | ||
|
|
3f792030d3 | ||
|
|
5c2fc1120b | ||
|
|
3d2acbe780 | ||
|
|
bce0e0ea90 | ||
|
|
931102ff26 | ||
|
|
5a3938d12f | ||
|
|
dca1751a63 | ||
|
|
f6ec9af61e | ||
|
|
64f2f84ffa | ||
|
|
5df5e53f11 | ||
|
|
81f4c50574 | ||
|
|
2550d16127 | ||
|
|
333ad0efac | ||
|
|
f3675681c3 | ||
|
|
28de8dc5b7 | ||
|
|
35e63a9398 | ||
|
|
f23f1cc813 | ||
|
|
b0095154d1 | ||
|
|
79ea9ed314 | ||
|
|
413db0dce1 | ||
|
|
e6745532ce | ||
|
|
59da0f90f8 | ||
|
|
76f0f52ee3 | ||
|
|
73c230f1ca | ||
|
|
ddee72c756 | ||
|
|
6318964374 | ||
|
|
853f1af40d | ||
|
|
d429b2151a | ||
|
|
b223e1a7af | ||
|
|
c806b8911e | ||
|
|
9f30a51925 | ||
|
|
a8b7129269 | ||
|
|
991b0e8ee2 | ||
|
|
e9d1475475 | ||
|
|
bc189554aa | ||
|
|
d0f26ae4cf | ||
|
|
ab6d247ef1 | ||
|
|
fcc82a47e4 | ||
|
|
25e53db96f | ||
|
|
89660d06e5 | ||
|
|
493fd0ad6a | ||
|
|
11422524f3 | ||
|
|
957214ed78 | ||
|
|
f013cca3b8 | ||
|
|
a1cfc0a0ff | ||
|
|
e8b3b3acf3 | ||
|
|
0cfb03be03 | ||
|
|
7d4b93e01e | ||
|
|
2f3793805b | ||
|
|
a310c13d32 | ||
|
|
38a721425d | ||
|
|
dfc34d99c5 | ||
|
|
6c58fd03a4 | ||
|
|
5b9d1286cc | ||
|
|
d9e330802c | ||
|
|
085de8a069 | ||
|
|
5af4c63a3e | ||
|
|
5177365c28 | ||
|
|
4df5ff3004 | ||
|
|
00f6841dc7 | ||
|
|
be8394158f | ||
|
|
fbf62b2a63 | ||
|
|
a047fb947b | ||
|
|
eec3a3d5c3 | ||
|
|
9387de1d1a | ||
|
|
b9c90f128a | ||
|
|
5699efc0f5 | ||
|
|
6ead008bf4 | ||
|
|
34e52839f7 | ||
|
|
bd54e1c60c | ||
|
|
03006522e2 | ||
|
|
7492ae2990 | ||
|
|
6edf890699 | ||
|
|
43fd24f02b | ||
|
|
22ebb81650 | ||
|
|
fd074278f7 | ||
|
|
ad497a66cd | ||
|
|
41275b0e91 | ||
|
|
b82502af1d | ||
|
|
43f2199d46 | ||
|
|
d44541fc9e | ||
|
|
24147a3d84 | ||
|
|
244d879d00 | ||
|
|
f5f67a629e | ||
|
|
aad1d57502 | ||
|
|
cf75c2378f | ||
|
|
3a64c4d582 | ||
|
|
d36376ffcd | ||
|
|
434197c10d | ||
|
|
d4af694c6f | ||
|
|
f245b67036 | ||
|
|
945673c7da | ||
|
|
c25967bd61 | ||
|
|
165fba6b9c | ||
|
|
76209dd899 | ||
|
|
8c8cc53989 | ||
|
|
6f463196ef | ||
|
|
b0e2624343 | ||
|
|
99fda3a7cb | ||
|
|
457039d7ba | ||
|
|
eb4ffbca29 | ||
|
|
c9afe8fcc4 | ||
|
|
d8d6348f67 | ||
|
|
87f7ec5909 | ||
|
|
18583eb6ed | ||
|
|
b9d0219f04 | ||
|
|
d9cb1fc4a9 | ||
|
|
1654be0a85 | ||
|
|
d5944163d6 | ||
|
|
5ca3a48094 | ||
|
|
1fb3d7cd3b | ||
|
|
f827b2dc0d | ||
|
|
0295824923 | ||
|
|
8fee0c946b | ||
|
|
bd13b8a5fe | ||
|
|
743ea95a78 | ||
|
|
2998a0fa35 | ||
|
|
7b0a3989e2 | ||
|
|
06fcb7595a | ||
|
|
bd3c4d4215 | ||
|
|
b969d9edfa | ||
|
|
3ef0fb63a9 | ||
|
|
bf706a9191 | ||
|
|
26be615a80 | ||
|
|
81928eb61a | ||
|
|
126f517520 | ||
|
|
7028496601 | ||
|
|
3a4897c7d2 | ||
|
|
b3f142d715 | ||
|
|
a4e16ca9c7 | ||
|
|
57176dee75 | ||
|
|
f87ba8a3a9 | ||
|
|
8c0b33f902 | ||
|
|
51e927adf7 | ||
|
|
bf4b681506 | ||
|
|
3c88d2cc18 | ||
|
|
c7b5975ac1 | ||
|
|
09901997c1 | ||
|
|
c0f3d851db | ||
|
|
98b6344f03 | ||
|
|
e4b6e4c167 | ||
|
|
d6983e829a | ||
|
|
374a2ad957 | ||
|
|
52fd2d7e75 | ||
|
|
25bb0ade1b | ||
|
|
6d7be80930 | ||
|
|
1f13f6372a | ||
|
|
39fcd84d53 | ||
|
|
d11a83d6e2 | ||
|
|
1978e23cfd | ||
|
|
4cc1a774df | ||
|
|
8a23463328 | ||
|
|
fad2913665 | ||
|
|
c4c27973f3 | ||
|
|
2ae733bd07 | ||
|
|
7665b9f81e | ||
|
|
248322c748 | ||
|
|
523bdd5ec9 | ||
|
|
a8ad00156b | ||
|
|
8f820713fa | ||
|
|
fc7d4b072c | ||
|
|
1801526f65 | ||
|
|
58e37b6a3f | ||
|
|
0bd9cad6ad | ||
|
|
bcc2c893ef | ||
|
|
ac71bbd4b5 | ||
|
|
ae94b30066 | ||
|
|
b3c307affe | ||
|
|
03d3f4229e | ||
|
|
c627b83cc5 | ||
|
|
5469db311d | ||
|
|
75793a36cf | ||
|
|
d68603e4ea | ||
|
|
33e402e7be | ||
|
|
375dce14e6 | ||
|
|
08ae3aee50 | ||
|
|
1ad7d4f1d8 | ||
|
|
f9e8f1f7b7 | ||
|
|
fa0b45625c | ||
|
|
c5459b2614 | ||
|
|
8232773d97 | ||
|
|
53b752ccfe | ||
|
|
07efba364e | ||
|
|
2e52d8ea7a | ||
|
|
a46a7a42a1 | ||
|
|
060a193b48 | ||
|
|
06ee06ae50 | ||
|
|
17a5a9f033 | ||
|
|
e27a754f5f | ||
|
|
61d5ba6a92 | ||
|
|
eff0054b4a | ||
|
|
99cd6c7383 | ||
|
|
5087392162 | ||
|
|
7474a31d95 | ||
|
|
a0197bc9da | ||
|
|
3b2e679aed | ||
|
|
75d69a1ec1 | ||
|
|
930fc66ebf | ||
|
|
04d3d26cb1 | ||
|
|
de940ccff9 | ||
|
|
aedc54cc89 | ||
|
|
de3a776b9a | ||
|
|
5d6cc61d4d | ||
|
|
f32b38cdbc | ||
|
|
f3bfb06dec | ||
|
|
630597746e | ||
|
|
f98036296c | ||
|
|
bf1f867f23 | ||
|
|
8215a85930 | ||
|
|
10a5686955 | ||
|
|
2e3c7a3acf | ||
|
|
06713da67b | ||
|
|
46fb1b6582 | ||
|
|
1b3f98db1e | ||
|
|
a190cdd8f2 | ||
|
|
8e25369001 | ||
|
|
8d90ad816a | ||
|
|
da9e42cb21 | ||
|
|
cbab3ff0d0 | ||
|
|
210b570c89 | ||
|
|
a2203df6a3 | ||
|
|
6a2b369014 | ||
|
|
fda6a6657f | ||
|
|
04565dad00 | ||
|
|
ac0ae06463 | ||
|
|
a8775f757f | ||
|
|
e4f4ed923d | ||
|
|
c7915fa95d | ||
|
|
652b118634 | ||
|
|
f122ff1471 | ||
|
|
f76b90fab9 | ||
|
|
ccd8beae92 | ||
|
|
33f01009d2 | ||
|
|
a0e3a71109 | ||
|
|
f35ecba801 | ||
|
|
0d7f26bd14 | ||
|
|
2f7bdd2640 | ||
|
|
3125e4ddd2 | ||
|
|
c624cb27da | ||
|
|
06adf9a094 | ||
|
|
94ed55ee35 | ||
|
|
95c8603b69 | ||
|
|
9ad2a8272e | ||
|
|
6dc17da00a | ||
|
|
97aa1c6b2c | ||
|
|
084fed8377 | ||
|
|
68d86e4fa1 | ||
|
|
5203373047 | ||
|
|
86de481ba1 | ||
|
|
5d075a97dd | ||
|
|
e89499f5db | ||
|
|
a1f0208767 | ||
|
|
d1964c20ab | ||
|
|
1e035bf2e5 | ||
|
|
f3b87f9cf9 | ||
|
|
d2ea45e1eb | ||
|
|
58ad6b1a40 | ||
|
|
772ef3cd10 | ||
|
|
204dfd52c8 | ||
|
|
244d3452d0 | ||
|
|
e65f8a7150 | ||
|
|
90d6991b9d | ||
|
|
87ca3f203a | ||
|
|
3f3a20e178 | ||
|
|
ce1a19fdbe | ||
|
|
26ac92a6b1 | ||
|
|
1c7dd0a533 | ||
|
|
ceb29d76b2 | ||
|
|
6efb354cce | ||
|
|
8ae242a6ed | ||
|
|
5f0f92fd15 | ||
|
|
e521fa3554 | ||
|
|
b8f73cf21f | ||
|
|
d068cddbaf | ||
|
|
99422835ab | ||
|
|
68263360c7 | ||
|
|
34f5ddab0f | ||
|
|
0cc4630fc6 | ||
|
|
ee57c79784 | ||
|
|
7e41b8df27 | ||
|
|
79c1d7bafa | ||
|
|
652b2fee86 | ||
|
|
dfb871c26a | ||
|
|
99f74acb94 | ||
|
|
83f7682606 | ||
|
|
c4a07f3098 | ||
|
|
c9451f4f35 | ||
|
|
dff4922783 | ||
|
|
c05b666f3c | ||
|
|
9905024f08 | ||
|
|
b0cb457287 | ||
|
|
d4946c1c08 | ||
|
|
1d745b5cbd | ||
|
|
c99785f266 | ||
|
|
9ecdec3f45 | ||
|
|
866f45bd95 | ||
|
|
320a79dbff | ||
|
|
1e0b6f1aad | ||
|
|
251ad6727a | ||
|
|
1b1f56d183 | ||
|
|
7dc05a45ac | ||
|
|
7257bab289 | ||
|
|
48a76c2d0d | ||
|
|
d78c83b236 | ||
|
|
d9b0415047 | ||
|
|
af2e3de96d | ||
|
|
1c142cb170 | ||
|
|
d5dae7d444 | ||
|
|
85816be967 | ||
|
|
e66d658955 | ||
|
|
1916fded95 | ||
|
|
8cc8f4c49c | ||
|
|
1a3bf16729 | ||
|
|
5304b533fc | ||
|
|
0156d47d97 | ||
|
|
b04ac6cdba | ||
|
|
f43e4200da | ||
|
|
2ba7aef2b1 | ||
|
|
7a1932cab4 | ||
|
|
59f189229c | ||
|
|
29af7a1d29 | ||
|
|
3d9ddc53e6 | ||
|
|
1a34feda65 | ||
|
|
d8c1081578 | ||
|
|
1085a1da62 | ||
|
|
576db8e0e1 | ||
|
|
fe9dc4a28d | ||
|
|
d2aaae2340 | ||
|
|
84e40cbc2c | ||
|
|
42672a9ae2 | ||
|
|
2dd2173553 | ||
|
|
fcd5400cda | ||
|
|
23b69bb7a7 | ||
|
|
c31b0945d8 | ||
|
|
c71a4ac4e8 | ||
|
|
38c7ca64cb | ||
|
|
bc187fe7b3 | ||
|
|
548c0db0ae | ||
|
|
3ecd1307b0 | ||
|
|
b51661b790 | ||
|
|
02d6e41ce3 | ||
|
|
f884aed25e | ||
|
|
f2dee1a470 | ||
|
|
d5d806760f | ||
|
|
efe2a8f789 | ||
|
|
69bbed999f | ||
|
|
5b7d4184f0 | ||
|
|
422b7ed5ef | ||
|
|
66a2b916f2 | ||
|
|
27ac253098 | ||
|
|
1839b24b90 | ||
|
|
a60ebb6210 | ||
|
|
4dba4f3c02 | ||
|
|
6727af2f35 | ||
|
|
5bcf334bc5 | ||
|
|
ef49bd685e | ||
|
|
092562fb94 | ||
|
|
44e2983803 | ||
|
|
2e848da1a8 | ||
|
|
22ae4ecb23 | ||
|
|
1642ac2394 | ||
|
|
be8aa93cca | ||
|
|
fc7ba85639 | ||
|
|
11d1dd6419 | ||
|
|
e8bd7270e9 | ||
|
|
99e2afa81b | ||
|
|
676792d07d | ||
|
|
0bec2bcd1e | ||
|
|
25328048aa | ||
|
|
e51d2137cf | ||
|
|
5695677873 | ||
|
|
9d86f582ac | ||
|
|
97b0558f71 | ||
|
|
e825be1c79 | ||
|
|
88252c3dfc | ||
|
|
02997b593f | ||
|
|
9de81a0b14 | ||
|
|
ab13182091 | ||
|
|
e75e4580ae | ||
|
|
b7f031d199 | ||
|
|
808d27be2d | ||
|
|
dcf8751ff7 | ||
|
|
ec6e3d80ee | ||
|
|
5a9badf683 | ||
|
|
dd11dcef93 | ||
|
|
e9851957f0 | ||
|
|
57cfbb3770 | ||
|
|
da2590819d | ||
|
|
d74d93a522 | ||
|
|
b3eadcc990 | ||
|
|
f4d4405c20 | ||
|
|
1ebec0e2e5 | ||
|
|
4433347ff3 | ||
|
|
08c539ba51 | ||
|
|
4e538dd138 | ||
|
|
66373ccab2 | ||
|
|
9c82c0700d | ||
|
|
a480e50c16 | ||
|
|
4391bf4f70 | ||
|
|
18f46cb527 | ||
|
|
32b89adc04 | ||
|
|
5a213fcad9 | ||
|
|
d6f1d1bb3c | ||
|
|
c8c0d0e804 | ||
|
|
aeddf2a860 | ||
|
|
b876a5f7bd | ||
|
|
af8949c291 | ||
|
|
e3da38df7c | ||
|
|
a16079e38d | ||
|
|
e13b0fac63 | ||
|
|
26190350c4 | ||
|
|
7598cc62d3 | ||
|
|
b3211fa8c2 | ||
|
|
8dcc909b6e | ||
|
|
fafaf2c490 | ||
|
|
11e2f19503 | ||
|
|
d67bd0eff2 | ||
|
|
43bbea9a7c | ||
|
|
dc366c53a7 | ||
|
|
fe1ede26be | ||
|
|
aca799b28c | ||
|
|
1017a0af1d | ||
|
|
ff25484a34 | ||
|
|
af922920ab | ||
|
|
919a3f1b91 | ||
|
|
1ec8e63e9e | ||
|
|
96c76a059a | ||
|
|
608701aea7 | ||
|
|
142d44a01f | ||
|
|
83c0f537ce | ||
|
|
aeab25b7fe | ||
|
|
ef255c6a5c | ||
|
|
474ebed0ee | ||
|
|
6e55604dc3 | ||
|
|
2dfdfefb1a | ||
|
|
48f78cf80a | ||
|
|
69cc28dd4b | ||
|
|
adb8bcf791 | ||
|
|
bd22d30674 | ||
|
|
afbf1cc33f | ||
|
|
485df59c5b | ||
|
|
43308b326d | ||
|
|
6c9708c700 | ||
|
|
4a962aa75a | ||
|
|
e786158071 | ||
|
|
ea5a767948 | ||
|
|
bde65a6c57 | ||
|
|
94c0a436b5 | ||
|
|
bddf1adeba | ||
|
|
9406a577c2 | ||
|
|
40344726e1 | ||
|
|
08ffea23b7 | ||
|
|
f1ddaa8051 | ||
|
|
7ae62c1060 | ||
|
|
7c51046d8a | ||
|
|
df6d75e2c5 | ||
|
|
3c88d9666d | ||
|
|
ee74025f38 | ||
|
|
d49c7d47a2 | ||
|
|
8f18e9bbbc | ||
|
|
be96a3785b | ||
|
|
f3aeb5ec9f | ||
|
|
71ea61e7a6 | ||
|
|
c6c73e5e59 | ||
|
|
ae242f8480 | ||
|
|
351a17f68d | ||
|
|
1c4f7cb339 | ||
|
|
2713af189f | ||
|
|
be62d1a915 | ||
|
|
68d71a6767 | ||
|
|
46c88ad1bf | ||
|
|
917151123f | ||
|
|
b9e9d6a787 | ||
|
|
db20077c37 | ||
|
|
ec3d027f90 | ||
|
|
50678085c9 | ||
|
|
5af4785ba1 | ||
|
|
f59d42d5d3 | ||
|
|
fc7ae1ee96 | ||
|
|
2699bb9a44 | ||
|
|
212f5b4082 | ||
|
|
9591f48077 | ||
|
|
0a8494a0f2 | ||
|
|
39f2a4ab71 | ||
|
|
39aa09ca36 | ||
|
|
45c5a2ae78 | ||
|
|
a1c612f833 | ||
|
|
bc39bb32d4 | ||
|
|
884308ecb5 | ||
|
|
2d7f232c3d | ||
|
|
afa65d9ead | ||
|
|
605c88a029 | ||
|
|
09994d1730 | ||
|
|
bb9c99ebf6 | ||
|
|
d4819886a6 | ||
|
|
23445123a2 | ||
|
|
773bb43b41 | ||
|
|
493dddde02 | ||
|
|
2e5704c6b4 | ||
|
|
be6c843bba | ||
|
|
064d677fdc | ||
|
|
084ab782da | ||
|
|
1a10a1ef75 | ||
|
|
acc77e4e6c | ||
|
|
2c0ff9be60 | ||
|
|
b9f5946cf0 | ||
|
|
c403968fa8 | ||
|
|
14baef425e | ||
|
|
8da532da93 | ||
|
|
facf701897 | ||
|
|
f9fe9ea5d6 | ||
|
|
f5a80c3007 | ||
|
|
7cff37e707 | ||
|
|
4e8c6b3fc4 | ||
|
|
82282c1c75 | ||
|
|
d7379f29da | ||
|
|
000159226d | ||
|
|
4ebdb8d24b | ||
|
|
fc2df08e15 | ||
|
|
aaa83dc19a | ||
|
|
adff0d5da0 | ||
|
|
285d6931bc | ||
|
|
114b687c5c | ||
|
|
a26ade3988 | ||
|
|
94e2983310 | ||
|
|
fb2f5f6756 | ||
|
|
d7b818cba2 | ||
|
|
8d885d14ed | ||
|
|
39e0023a5f | ||
|
|
84faac0cd6 | ||
|
|
1bce639d35 | ||
|
|
f2061610b9 | ||
|
|
8716f9b41a | ||
|
|
a24c817bb7 | ||
|
|
47997e0056 | ||
|
|
70fd7bea99 | ||
|
|
52565375b3 | ||
|
|
2c327d9eee | ||
|
|
caeb710444 | ||
|
|
0b0b101184 | ||
|
|
f5b4a0788e | ||
|
|
1aa338fe3e | ||
|
|
5615d8d870 | ||
|
|
9711ccd914 | ||
|
|
fbc2b845ad | ||
|
|
39ecca0989 | ||
|
|
f19b6afd85 | ||
|
|
dca347398d | ||
|
|
de6341bd87 | ||
|
|
5cb9dbb87a | ||
|
|
dddc5181e7 | ||
|
|
3b78fa2d5d | ||
|
|
2a64f5e3ce | ||
|
|
8f5b53e3ce | ||
|
|
605f5decb3 | ||
|
|
d00e128920 | ||
|
|
226c1c53c0 | ||
|
|
001b874903 | ||
|
|
cc523ea356 | ||
|
|
5dc2b7b1d5 | ||
|
|
cd84e78b27 | ||
|
|
dedaa24972 | ||
|
|
1b0c4e5d1f | ||
|
|
b7e3fc5f73 | ||
|
|
9b9ec09788 | ||
|
|
bd7ceb0b73 | ||
|
|
9638c0dd83 | ||
|
|
60f40544bb | ||
|
|
066fb7178d | ||
|
|
cd762e5e8c | ||
|
|
f990d68cee | ||
|
|
88f14b39a7 | ||
|
|
eda64584d7 | ||
|
|
2f2a2dced6 | ||
|
|
38a2ea2fdf | ||
|
|
43bad9a608 | ||
|
|
be5f3086ce | ||
|
|
663f12d5e6 | ||
|
|
6e758d721d | ||
|
|
4c98b04ab7 | ||
|
|
f846645989 | ||
|
|
6bc79b590c | ||
|
|
2ad7e870d8 | ||
|
|
87636669ae | ||
|
|
8d627f1329 | ||
|
|
c51cc4703b | ||
|
|
a1124c9e1f | ||
|
|
20e245cb05 | ||
|
|
5c8e165080 | ||
|
|
afe088a9e8 | ||
|
|
162f31baa2 | ||
|
|
28a50df746 | ||
|
|
5a0d600322 | ||
|
|
38c1945ce4 | ||
|
|
392fa21f1e | ||
|
|
fa99b5415d | ||
|
|
c52d16da6d | ||
|
|
3f62cd9271 | ||
|
|
3dd282e11b | ||
|
|
95349e6e2e | ||
|
|
dcc40b0a63 | ||
|
|
dc0d9a8dce | ||
|
|
021b01f0bd | ||
|
|
9ab023cc6c | ||
|
|
b54061fc3f | ||
|
|
c12fe28b2d |
No files matched your search
@@ -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
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
language: java
|
language: java
|
||||||
|
|
||||||
|
jdk:
|
||||||
|
- oraclejdk8
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.m2
|
- $HOME/.m2
|
||||||
@@ -7,4 +10,10 @@ cache:
|
|||||||
before_cache:
|
before_cache:
|
||||||
- rm -rf $HOME/.m2/repository/org/keycloak
|
- rm -rf $HOME/.m2/repository/org/keycloak
|
||||||
|
|
||||||
|
install: mvn install -Pdistribution -DskipTests=true -B -V
|
||||||
|
|
||||||
|
script:
|
||||||
|
- mvn test -B
|
||||||
|
- mvn -file testsuite/integration-arquillian test -B
|
||||||
|
|
||||||
sudo: false
|
sudo: false
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ public abstract class AbstractIdentityProvider<C extends IdentityProviderModel>
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response performLogin(AuthenticationRequest request) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
|
public Response keycloakInitiatedBrowserLogout(UserSessionModel userSession, UriInfo uriInfo, RealmModel realm) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.keycloak.broker.provider;
|
package org.keycloak.broker.provider;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientSessionModel;
|
||||||
import org.keycloak.models.IdentityProviderModel;
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -43,6 +44,7 @@ public class BrokeredIdentityContext {
|
|||||||
private IdentityProviderModel idpConfig;
|
private IdentityProviderModel idpConfig;
|
||||||
private IdentityProvider idp;
|
private IdentityProvider idp;
|
||||||
private Map<String, Object> contextData = new HashMap<>();
|
private Map<String, Object> contextData = new HashMap<>();
|
||||||
|
private ClientSessionModel clientSession;
|
||||||
|
|
||||||
public BrokeredIdentityContext(String id) {
|
public BrokeredIdentityContext(String id) {
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
@@ -166,6 +168,14 @@ public class BrokeredIdentityContext {
|
|||||||
this.lastName = lastName;
|
this.lastName = lastName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClientSessionModel getClientSession() {
|
||||||
|
return clientSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClientSession(ClientSessionModel clientSession) {
|
||||||
|
this.clientSession = clientSession;
|
||||||
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
int i = name.lastIndexOf(' ');
|
int i = name.lastIndexOf(' ');
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
package org.keycloak.broker.provider;
|
||||||
|
|
||||||
|
import org.keycloak.models.ClientModel;
|
||||||
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.RoleModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class HardcodedAttributeMapper extends AbstractIdentityProviderMapper {
|
||||||
|
public static final String ATTRIBUTE = "attribute";
|
||||||
|
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
||||||
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ProviderConfigProperty property;
|
||||||
|
property = new ProviderConfigProperty();
|
||||||
|
property.setName(ATTRIBUTE);
|
||||||
|
property.setLabel("User Attribute");
|
||||||
|
property.setHelpText("Name of user attribute you want to hardcode");
|
||||||
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ProviderConfigProperty();
|
||||||
|
property.setName(ATTRIBUTE_VALUE);
|
||||||
|
property.setLabel("User Attribute Value");
|
||||||
|
property.setHelpText("Value you want to hardcode");
|
||||||
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
|
configProperties.add(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return configProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return "Attribute Importer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Hardcoded Attribute";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER};
|
||||||
|
|
||||||
|
|
||||||
|
public static final String PROVIDER_ID = "hardcoded-attribute-idp-mapper";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getCompatibleProviders() {
|
||||||
|
return COMPATIBLE_PROVIDERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
|
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
|
||||||
|
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
|
||||||
|
user.setSingleAttribute(attribute, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
|
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
|
||||||
|
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
|
||||||
|
user.setSingleAttribute(attribute, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpText() {
|
||||||
|
return "When user is imported from provider, hardcode a value to a specific user attribute.";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,15 +27,15 @@ public class HardcodedRoleMapper extends AbstractIdentityProviderMapper {
|
|||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(ROLE);
|
property.setName(ROLE);
|
||||||
property.setLabel("Role");
|
property.setLabel("Role");
|
||||||
property.setHelpText("Role to grant to user. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
property.setHelpText("Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.ROLE_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static String[] parseRole(String role) {
|
public static String[] parseRole(String role) {
|
||||||
int scopeIndex = role.indexOf('.');
|
int scopeIndex = role.lastIndexOf('.');
|
||||||
if (scopeIndex > -1) {
|
if (scopeIndex > -1) {
|
||||||
String appName = role.substring(0, scopeIndex);
|
String appName = role.substring(0, scopeIndex);
|
||||||
role = role.substring(scopeIndex + 1);
|
role = role.substring(scopeIndex + 1);
|
||||||
|
|||||||
Executable
+87
@@ -0,0 +1,87 @@
|
|||||||
|
package org.keycloak.broker.provider;
|
||||||
|
|
||||||
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.models.RealmModel;
|
||||||
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class HardcodedUserSessionAttributeMapper extends AbstractIdentityProviderMapper {
|
||||||
|
public static final String ATTRIBUTE = "attribute";
|
||||||
|
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
||||||
|
protected static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ProviderConfigProperty property;
|
||||||
|
property = new ProviderConfigProperty();
|
||||||
|
property.setName(ATTRIBUTE);
|
||||||
|
property.setLabel("User Session Attribute");
|
||||||
|
property.setHelpText("Name of user session attribute you want to hardcode");
|
||||||
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
|
configProperties.add(property);
|
||||||
|
property = new ProviderConfigProperty();
|
||||||
|
property.setName(ATTRIBUTE_VALUE);
|
||||||
|
property.setLabel("User Session Attribute Value");
|
||||||
|
property.setHelpText("Value you want to hardcode");
|
||||||
|
property.setType(ProviderConfigProperty.STRING_TYPE);
|
||||||
|
configProperties.add(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
|
return configProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayCategory() {
|
||||||
|
return "Attribute Importer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayType() {
|
||||||
|
return "Hardcoded User Session Attribute";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String[] COMPATIBLE_PROVIDERS = {ANY_PROVIDER};
|
||||||
|
|
||||||
|
|
||||||
|
public static final String PROVIDER_ID = "hardcoded-user-session-attribute-idp-mapper";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return PROVIDER_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getCompatibleProviders() {
|
||||||
|
return COMPATIBLE_PROVIDERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void importNewUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
|
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
|
||||||
|
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
|
||||||
|
context.getClientSession().setUserSessionNote(attribute, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
|
String attribute = mapperModel.getConfig().get(ATTRIBUTE);
|
||||||
|
String attributeValue = mapperModel.getConfig().get(ATTRIBUTE_VALUE);
|
||||||
|
context.getClientSession().setUserSessionNote(attribute, attributeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHelpText() {
|
||||||
|
return "When user is imported from provider, hardcode a value to a specific user session attribute.";
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -1 +1,3 @@
|
|||||||
org.keycloak.broker.provider.HardcodedRoleMapper
|
org.keycloak.broker.provider.HardcodedRoleMapper
|
||||||
|
org.keycloak.broker.provider.HardcodedAttributeMapper
|
||||||
|
org.keycloak.broker.provider.HardcodedUserSessionAttributeMapper
|
||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ package org.keycloak.broker.oidc;
|
|||||||
import org.codehaus.jackson.JsonNode;
|
import org.codehaus.jackson.JsonNode;
|
||||||
import org.codehaus.jackson.map.ObjectMapper;
|
import org.codehaus.jackson.map.ObjectMapper;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.broker.provider.util.SimpleHttp;
|
import org.keycloak.broker.provider.util.SimpleHttp;
|
||||||
import org.keycloak.broker.provider.AbstractIdentityProvider;
|
import org.keycloak.broker.provider.AbstractIdentityProvider;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import org.keycloak.services.messages.Messages;
|
|||||||
import org.keycloak.services.resources.IdentityBrokerService;
|
import org.keycloak.services.resources.IdentityBrokerService;
|
||||||
import org.keycloak.services.resources.RealmsResource;
|
import org.keycloak.services.resources.RealmsResource;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
import org.keycloak.util.PemUtils;
|
import org.keycloak.common.util.PemUtils;
|
||||||
|
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
import javax.ws.rs.Path;
|
import javax.ws.rs.Path;
|
||||||
@@ -289,10 +289,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
|||||||
}
|
}
|
||||||
JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
|
JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
|
||||||
|
|
||||||
String aud = token.getAudience();
|
|
||||||
String iss = token.getIssuer();
|
String iss = token.getIssuer();
|
||||||
|
|
||||||
if (aud != null && !aud.equals(getConfig().getClientId())) {
|
if (!token.hasAudience(getConfig().getClientId())) {
|
||||||
throw new IdentityBrokerException("Wrong audience from token.");
|
throw new IdentityBrokerException("Wrong audience from token.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ public abstract class AbstractJsonUserAttributeMapper extends AbstractIdentityPr
|
|||||||
|
|
||||||
String value = getJsonValue(mapperModel, context);
|
String value = getJsonValue(mapperModel, context);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
user.setAttribute(attribute, value);
|
user.setSingleAttribute(attribute, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public class ClaimToRoleMapper extends AbstractClaimMapper {
|
|||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(HardcodedRoleMapper.ROLE);
|
property.setName(HardcodedRoleMapper.ROLE);
|
||||||
property.setLabel("Role");
|
property.setLabel("Role");
|
||||||
property.setHelpText("Role to grant to user if claim is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
property.setHelpText("Role to grant to user if claim is present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.ROLE_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -40,8 +40,8 @@ public class ExternalKeycloakRoleToRoleMapper extends AbstractClaimMapper {
|
|||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(HardcodedRoleMapper.ROLE);
|
property.setName(HardcodedRoleMapper.ROLE);
|
||||||
property.setLabel("Role");
|
property.setLabel("Role");
|
||||||
property.setHelpText("Role to grant to user if external role is present. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
property.setHelpText("Role to grant to user if external role is present. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.ROLE_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,16 +3,14 @@ package org.keycloak.broker.oidc.mappers;
|
|||||||
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
|
import org.keycloak.broker.oidc.KeycloakOIDCIdentityProviderFactory;
|
||||||
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
import org.keycloak.broker.oidc.OIDCIdentityProviderFactory;
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -76,7 +74,7 @@ public class UserAttributeMapper extends AbstractClaimMapper {
|
|||||||
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
||||||
Object value = getClaimValue(mapperModel, context);
|
Object value = getClaimValue(mapperModel, context);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
user.setAttribute(attribute, value.toString());
|
user.setSingleAttribute(attribute, value.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,9 +82,9 @@ public class UserAttributeMapper extends AbstractClaimMapper {
|
|||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
||||||
Object value = getClaimValue(mapperModel, context);
|
Object value = getClaimValue(mapperModel, context);
|
||||||
String current = user.getAttribute(attribute);
|
String current = user.getFirstAttribute(attribute);
|
||||||
if (value != null && !value.equals(current)) {
|
if (value != null && !value.equals(current)) {
|
||||||
user.setAttribute(attribute, value.toString());
|
user.setSingleAttribute(attribute, value.toString());
|
||||||
} else if (value == null) {
|
} else if (value == null) {
|
||||||
user.removeAttribute(attribute);
|
user.removeAttribute(attribute);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package org.keycloak.broker.saml;
|
package org.keycloak.broker.saml;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
import org.keycloak.VerificationException;
|
import org.keycloak.common.VerificationException;
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||||
import org.keycloak.broker.provider.IdentityProvider;
|
import org.keycloak.broker.provider.IdentityProvider;
|
||||||
@@ -10,7 +10,6 @@ import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
|||||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
|
import org.keycloak.dom.saml.v2.assertion.AuthnStatementType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.EncryptedAssertionType;
|
|
||||||
import org.keycloak.dom.saml.v2.assertion.NameIDType;
|
import org.keycloak.dom.saml.v2.assertion.NameIDType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.SubjectType;
|
import org.keycloak.dom.saml.v2.assertion.SubjectType;
|
||||||
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
|
import org.keycloak.dom.saml.v2.protocol.LogoutRequestType;
|
||||||
@@ -24,31 +23,23 @@ import org.keycloak.events.EventType;
|
|||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.protocol.saml.SAML2LogoutResponseBuilder;
|
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
|
||||||
import org.keycloak.protocol.saml.SAMLRequestParser;
|
import org.keycloak.saml.SAML2LogoutResponseBuilder;
|
||||||
|
import org.keycloak.saml.SAMLRequestParser;
|
||||||
import org.keycloak.protocol.saml.SamlProtocol;
|
import org.keycloak.protocol.saml.SamlProtocol;
|
||||||
import org.keycloak.protocol.saml.SamlProtocolUtils;
|
import org.keycloak.protocol.saml.SamlProtocolUtils;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLConstants;
|
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
import org.keycloak.saml.common.exceptions.ProcessingException;
|
||||||
import org.keycloak.saml.common.util.DocumentUtil;
|
|
||||||
import org.keycloak.saml.common.util.StaxParserUtil;
|
|
||||||
import org.keycloak.saml.processing.api.saml.v2.response.SAML2Response;
|
|
||||||
import org.keycloak.saml.processing.core.parsers.saml.SAMLParser;
|
|
||||||
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
import org.keycloak.saml.processing.core.saml.v2.common.SAMLDocumentHolder;
|
||||||
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
|
||||||
import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
|
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
|
||||||
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
|
|
||||||
import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
|
import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
|
||||||
import org.keycloak.saml.processing.web.util.PostBindingUtil;
|
import org.keycloak.saml.processing.web.util.PostBindingUtil;
|
||||||
import org.keycloak.services.ErrorPage;
|
import org.keycloak.services.ErrorPage;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.FormParam;
|
import javax.ws.rs.FormParam;
|
||||||
@@ -61,9 +52,7 @@ import javax.ws.rs.core.MediaType;
|
|||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import javax.xml.namespace.QName;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -155,7 +144,7 @@ public class SAMLEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract String getBindingType();
|
protected abstract String getBindingType();
|
||||||
protected abstract void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException;
|
protected abstract void verifySignature(String key, SAMLDocumentHolder documentHolder) throws VerificationException;
|
||||||
protected abstract SAMLDocumentHolder extractRequestDocument(String samlRequest);
|
protected abstract SAMLDocumentHolder extractRequestDocument(String samlRequest);
|
||||||
protected abstract SAMLDocumentHolder extractResponseDocument(String response);
|
protected abstract SAMLDocumentHolder extractResponseDocument(String response);
|
||||||
protected PublicKey getIDPKey() {
|
protected PublicKey getIDPKey() {
|
||||||
@@ -188,7 +177,7 @@ public class SAMLEndpoint {
|
|||||||
}
|
}
|
||||||
if (config.isValidateSignature()) {
|
if (config.isValidateSignature()) {
|
||||||
try {
|
try {
|
||||||
verifySignature(holder);
|
verifySignature(GeneralConstants.SAML_REQUEST_KEY, holder);
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
logger.error("validation failed", e);
|
logger.error("validation failed", e);
|
||||||
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
||||||
@@ -247,16 +236,18 @@ public class SAMLEndpoint {
|
|||||||
builder.logoutRequestID(request.getID());
|
builder.logoutRequestID(request.getID());
|
||||||
builder.destination(config.getSingleLogoutServiceUrl());
|
builder.destination(config.getSingleLogoutServiceUrl());
|
||||||
builder.issuer(issuerURL);
|
builder.issuer(issuerURL);
|
||||||
builder.relayState(relayState);
|
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||||
|
.relayState(relayState);
|
||||||
if (config.isWantAuthnRequestsSigned()) {
|
if (config.isWantAuthnRequestsSigned()) {
|
||||||
builder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||||
|
.signatureAlgorithm(provider.getSignatureAlgorithm())
|
||||||
.signDocument();
|
.signDocument();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (config.isPostBindingResponse()) {
|
if (config.isPostBindingResponse()) {
|
||||||
return builder.postBinding().response();
|
return binding.postBinding(builder.buildDocument()).response(config.getSingleLogoutServiceUrl());
|
||||||
} else {
|
} else {
|
||||||
return builder.redirectBinding().response();
|
return binding.redirectBinding(builder.buildDocument()).response(config.getSingleLogoutServiceUrl());
|
||||||
}
|
}
|
||||||
} catch (ConfigurationException e) {
|
} catch (ConfigurationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@@ -274,7 +265,7 @@ public class SAMLEndpoint {
|
|||||||
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState) {
|
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
AssertionType assertion = getAssertion(responseType);
|
AssertionType assertion = AssertionUtil.getAssertion(responseType, realm.getPrivateKey());
|
||||||
SubjectType subject = assertion.getSubject();
|
SubjectType subject = assertion.getSubject();
|
||||||
SubjectType.STSubType subType = subject.getSubType();
|
SubjectType.STSubType subType = subject.getSubType();
|
||||||
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
||||||
@@ -286,7 +277,8 @@ public class SAMLEndpoint {
|
|||||||
|
|
||||||
identity.setUsername(subjectNameID.getValue());
|
identity.setUsername(subjectNameID.getValue());
|
||||||
|
|
||||||
if (subjectNameID.getFormat().toString().equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) {
|
//SAML Spec 2.2.2 Format is optional
|
||||||
|
if (subjectNameID.getFormat() != null && subjectNameID.getFormat().toString().equals(JBossSAMLURIConstants.NAMEID_FORMAT_EMAIL.get())) {
|
||||||
identity.setEmail(subjectNameID.getValue());
|
identity.setEmail(subjectNameID.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,22 +325,6 @@ public class SAMLEndpoint {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private AssertionType getAssertion(ResponseType responseType) throws ProcessingException {
|
|
||||||
List<ResponseType.RTChoiceType> assertions = responseType.getAssertions();
|
|
||||||
|
|
||||||
if (assertions.isEmpty()) {
|
|
||||||
throw new IdentityBrokerException("No assertion from response.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ResponseType.RTChoiceType rtChoiceType = assertions.get(0);
|
|
||||||
EncryptedAssertionType encryptedAssertion = rtChoiceType.getEncryptedAssertion();
|
|
||||||
|
|
||||||
if (encryptedAssertion != null) {
|
|
||||||
decryptAssertion(responseType, realm.getPrivateKey());
|
|
||||||
|
|
||||||
}
|
|
||||||
return responseType.getAssertions().get(0).getAssertion();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Response handleSamlResponse(String samlResponse, String relayState) {
|
public Response handleSamlResponse(String samlResponse, String relayState) {
|
||||||
SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
|
SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
|
||||||
@@ -362,7 +338,7 @@ public class SAMLEndpoint {
|
|||||||
}
|
}
|
||||||
if (config.isValidateSignature()) {
|
if (config.isValidateSignature()) {
|
||||||
try {
|
try {
|
||||||
verifySignature(holder);
|
verifySignature(GeneralConstants.SAML_RESPONSE_KEY, holder);
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
logger.error("validation failed", e);
|
logger.error("validation failed", e);
|
||||||
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
||||||
@@ -405,43 +381,14 @@ public class SAMLEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected ResponseType decryptAssertion(ResponseType responseType, PrivateKey privateKey) throws ProcessingException {
|
|
||||||
SAML2Response saml2Response = new SAML2Response();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Document doc = saml2Response.convert(responseType);
|
|
||||||
Element enc = DocumentUtil.getElement(doc, new QName(JBossSAMLConstants.ENCRYPTED_ASSERTION.get()));
|
|
||||||
|
|
||||||
if (enc == null) {
|
|
||||||
throw new IdentityBrokerException("No encrypted assertion found.");
|
|
||||||
}
|
|
||||||
|
|
||||||
String oldID = enc.getAttribute(JBossSAMLConstants.ID.get());
|
|
||||||
Document newDoc = DocumentUtil.createDocument();
|
|
||||||
Node importedNode = newDoc.importNode(enc, true);
|
|
||||||
newDoc.appendChild(importedNode);
|
|
||||||
|
|
||||||
Element decryptedDocumentElement = XMLEncryptionUtil.decryptElementInDocument(newDoc, privateKey);
|
|
||||||
SAMLParser parser = new SAMLParser();
|
|
||||||
|
|
||||||
JAXPValidationUtil.checkSchemaValidation(decryptedDocumentElement);
|
|
||||||
AssertionType assertion = (AssertionType) parser.parse(StaxParserUtil.getXMLEventReader(DocumentUtil
|
|
||||||
.getNodeAsStream(decryptedDocumentElement)));
|
|
||||||
|
|
||||||
responseType.replaceAssertion(oldID, new ResponseType.RTChoiceType(assertion));
|
|
||||||
|
|
||||||
return responseType;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IdentityBrokerException("Could not decrypt assertion.", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class PostBinding extends Binding {
|
protected class PostBinding extends Binding {
|
||||||
@Override
|
@Override
|
||||||
protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
|
protected void verifySignature(String key, SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||||
SamlProtocolUtils.verifyDocumentSignature(documentHolder.getSamlDocument(), getIDPKey());
|
SamlProtocolUtils.verifyDocumentSignature(documentHolder.getSamlDocument(), getIDPKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,9 +411,9 @@ public class SAMLEndpoint {
|
|||||||
|
|
||||||
protected class RedirectBinding extends Binding {
|
protected class RedirectBinding extends Binding {
|
||||||
@Override
|
@Override
|
||||||
protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
|
protected void verifySignature(String key, SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||||
PublicKey publicKey = getIDPKey();
|
PublicKey publicKey = getIDPKey();
|
||||||
SamlProtocolUtils.verifyRedirectSignature(publicKey, uriInfo);
|
SamlProtocolUtils.verifyRedirectSignature(publicKey, uriInfo, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,20 +33,18 @@ import org.keycloak.models.ClientSessionModel;
|
|||||||
import org.keycloak.models.FederatedIdentityModel;
|
import org.keycloak.models.FederatedIdentityModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
|
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
|
||||||
import org.keycloak.protocol.saml.SAML2LogoutRequestBuilder;
|
import org.keycloak.saml.SAML2AuthnRequestBuilder;
|
||||||
import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
|
import org.keycloak.saml.SAML2LogoutRequestBuilder;
|
||||||
|
import org.keycloak.saml.SAML2NameIDPolicyBuilder;
|
||||||
|
import org.keycloak.saml.SignatureAlgorithm;
|
||||||
import org.keycloak.saml.common.constants.GeneralConstants;
|
import org.keycloak.saml.common.constants.GeneralConstants;
|
||||||
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
|
||||||
import org.keycloak.saml.common.exceptions.ConfigurationException;
|
|
||||||
import org.keycloak.saml.common.exceptions.ParsingException;
|
|
||||||
import org.keycloak.saml.common.exceptions.ProcessingException;
|
|
||||||
|
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.io.IOException;
|
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
@@ -92,7 +90,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
.issuer(issuerURL)
|
.issuer(issuerURL)
|
||||||
.forceAuthn(getConfig().isForceAuthn())
|
.forceAuthn(getConfig().isForceAuthn())
|
||||||
.protocolBinding(protocolBinding)
|
.protocolBinding(protocolBinding)
|
||||||
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat))
|
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat));
|
||||||
|
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||||
.relayState(request.getState());
|
.relayState(request.getState());
|
||||||
|
|
||||||
if (getConfig().isWantAuthnRequestsSigned()) {
|
if (getConfig().isWantAuthnRequestsSigned()) {
|
||||||
@@ -109,14 +108,15 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
|
|
||||||
KeyPair keypair = new KeyPair(publicKey, privateKey);
|
KeyPair keypair = new KeyPair(publicKey, privateKey);
|
||||||
|
|
||||||
authnRequestBuilder.signWith(keypair);
|
binding.signWith(keypair);
|
||||||
authnRequestBuilder.signDocument();
|
binding.signatureAlgorithm(getSignatureAlgorithm());
|
||||||
|
binding.signDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getConfig().isPostBindingAuthnRequest()) {
|
if (getConfig().isPostBindingAuthnRequest()) {
|
||||||
return authnRequestBuilder.postBinding().request();
|
return binding.postBinding(authnRequestBuilder.toDocument()).request(destinationUrl);
|
||||||
} else {
|
} else {
|
||||||
return authnRequestBuilder.redirectBinding().request();
|
return binding.redirectBinding(authnRequestBuilder.toDocument()).request(destinationUrl);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new IdentityBrokerException("Could not create authentication request.", e);
|
throw new IdentityBrokerException("Could not create authentication request.", e);
|
||||||
@@ -153,9 +153,10 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
|
String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
|
||||||
if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("") || !getConfig().isBackchannelSupported()) return;
|
if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("") || !getConfig().isBackchannelSupported()) return;
|
||||||
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
||||||
|
JaxrsSAML2BindingBuilder binding = buildLogoutBinding(userSession, realm);
|
||||||
try {
|
try {
|
||||||
int status = SimpleHttp.doPost(singleLogoutServiceUrl)
|
int status = SimpleHttp.doPost(singleLogoutServiceUrl)
|
||||||
.param(GeneralConstants.SAML_REQUEST_KEY, logoutBuilder.postBinding().encoded())
|
.param(GeneralConstants.SAML_REQUEST_KEY, binding.postBinding(logoutBuilder.buildDocument()).encoded())
|
||||||
.param(GeneralConstants.RELAY_STATE, userSession.getId()).asStatus();
|
.param(GeneralConstants.RELAY_STATE, userSession.getId()).asStatus();
|
||||||
boolean success = status >=200 && status < 400;
|
boolean success = status >=200 && status < 400;
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -178,7 +179,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
||||||
return logoutBuilder.postBinding().request();
|
JaxrsSAML2BindingBuilder binding = buildLogoutBinding(userSession, realm);
|
||||||
|
return binding.postBinding(logoutBuilder.buildDocument()).request(singleLogoutServiceUrl);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -192,13 +194,19 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
.issuer(getEntityId(uriInfo, realm))
|
.issuer(getEntityId(uriInfo, realm))
|
||||||
.sessionIndex(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SESSION_INDEX))
|
.sessionIndex(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SESSION_INDEX))
|
||||||
.userPrincipal(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT), userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT_NAMEFORMAT))
|
.userPrincipal(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT), userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SUBJECT_NAMEFORMAT))
|
||||||
.destination(singleLogoutServiceUrl)
|
.destination(singleLogoutServiceUrl);
|
||||||
|
return logoutBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JaxrsSAML2BindingBuilder buildLogoutBinding(UserSessionModel userSession, RealmModel realm) {
|
||||||
|
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||||
.relayState(userSession.getId());
|
.relayState(userSession.getId());
|
||||||
if (getConfig().isWantAuthnRequestsSigned()) {
|
if (getConfig().isWantAuthnRequestsSigned()) {
|
||||||
logoutBuilder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||||
|
.signatureAlgorithm(getSignatureAlgorithm())
|
||||||
.signDocument();
|
.signDocument();
|
||||||
}
|
}
|
||||||
return logoutBuilder;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -220,7 +228,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
|
|
||||||
|
|
||||||
String descriptor =
|
String descriptor =
|
||||||
"<EntityDescriptor entityID=\"" + getEntityId(uriInfo, realm) + "\">\n" +
|
"<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + getEntityId(uriInfo, realm) + "\">\n" +
|
||||||
" <SPSSODescriptor AuthnRequestsSigned=\"" + getConfig().isWantAuthnRequestsSigned() + "\"\n" +
|
" <SPSSODescriptor AuthnRequestsSigned=\"" + getConfig().isWantAuthnRequestsSigned() + "\"\n" +
|
||||||
" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n" +
|
" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n" +
|
||||||
" <NameIDFormat>" + getConfig().getNameIDPolicyFormat() + "\n" +
|
" <NameIDFormat>" + getConfig().getNameIDPolicyFormat() + "\n" +
|
||||||
@@ -245,4 +253,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
|||||||
"</EntityDescriptor>\n";
|
"</EntityDescriptor>\n";
|
||||||
return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
|
return Response.ok(descriptor, MediaType.APPLICATION_XML_TYPE).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SignatureAlgorithm getSignatureAlgorithm() {
|
||||||
|
String alg = getConfig().getSignatureAlgorithm();
|
||||||
|
if (alg != null) {
|
||||||
|
SignatureAlgorithm algorithm = SignatureAlgorithm.valueOf(alg);
|
||||||
|
if (algorithm != null) return algorithm;
|
||||||
|
}
|
||||||
|
return SignatureAlgorithm.RSA_SHA256;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -87,6 +87,14 @@ public class SAMLIdentityProviderConfig extends IdentityProviderModel {
|
|||||||
getConfig().put("wantAuthnRequestsSigned", String.valueOf(wantAuthnRequestsSigned));
|
getConfig().put("wantAuthnRequestsSigned", String.valueOf(wantAuthnRequestsSigned));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSignatureAlgorithm() {
|
||||||
|
return getConfig().get("signatureAlgorithm");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSignatureAlgorithm(String signatureAlgorithm) {
|
||||||
|
getConfig().put("signatureAlgorithm", signatureAlgorithm);
|
||||||
|
}
|
||||||
|
|
||||||
public String getEncryptionPublicKey() {
|
public String getEncryptionPublicKey() {
|
||||||
return getConfig().get("encryptionPublicKey");
|
return getConfig().get("encryptionPublicKey");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,12 +73,17 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
|||||||
List<EntityDescriptorType.EDTChoiceType> choiceType = entityType.getChoiceType();
|
List<EntityDescriptorType.EDTChoiceType> choiceType = entityType.getChoiceType();
|
||||||
|
|
||||||
if (!choiceType.isEmpty()) {
|
if (!choiceType.isEmpty()) {
|
||||||
EntityDescriptorType.EDTChoiceType edtChoiceType = choiceType.get(0);
|
IDPSSODescriptorType idpDescriptor = null;
|
||||||
|
|
||||||
|
//Metadata documents can contain multiple Descriptors (See ADFS metadata documents) such as RoleDescriptor, SPSSODescriptor, IDPSSODescriptor.
|
||||||
|
//So we need to loop through to find the IDPSSODescriptor.
|
||||||
|
for(EntityDescriptorType.EDTChoiceType edtChoiceType : entityType.getChoiceType()) {
|
||||||
List<EntityDescriptorType.EDTDescriptorChoiceType> descriptors = edtChoiceType.getDescriptors();
|
List<EntityDescriptorType.EDTDescriptorChoiceType> descriptors = edtChoiceType.getDescriptors();
|
||||||
|
|
||||||
if (!descriptors.isEmpty()) {
|
if(!descriptors.isEmpty() && descriptors.get(0).getIdpDescriptor() != null) {
|
||||||
EntityDescriptorType.EDTDescriptorChoiceType edtDescriptorChoiceType = descriptors.get(0);
|
idpDescriptor = descriptors.get(0).getIdpDescriptor();
|
||||||
IDPSSODescriptorType idpDescriptor = edtDescriptorChoiceType.getIdpDescriptor();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (idpDescriptor != null) {
|
if (idpDescriptor != null) {
|
||||||
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
||||||
@@ -142,7 +147,6 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
|||||||
return samlIdentityProviderConfig.getConfig();
|
return samlIdentityProviderConfig.getConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch (ParsingException pe) {
|
} catch (ParsingException pe) {
|
||||||
throw new RuntimeException("Could not parse IdP SAML Metadata", pe);
|
throw new RuntimeException("Could not parse IdP SAML Metadata", pe);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -59,8 +59,8 @@ public class AttributeToRoleMapper extends AbstractIdentityProviderMapper {
|
|||||||
property = new ProviderConfigProperty();
|
property = new ProviderConfigProperty();
|
||||||
property.setName(HardcodedRoleMapper.ROLE);
|
property.setName(HardcodedRoleMapper.ROLE);
|
||||||
property.setLabel("Role");
|
property.setLabel("Role");
|
||||||
property.setHelpText("Role to grant to user. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
property.setHelpText("Role to grant to user. Click 'Select Role' button to browse roles, or just type it in the textbox. To reference an application role the syntax is appname.approle, i.e. myapp.myrole");
|
||||||
property.setType(ProviderConfigProperty.STRING_TYPE);
|
property.setType(ProviderConfigProperty.ROLE_TYPE);
|
||||||
configProperties.add(property);
|
configProperties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,14 @@ package org.keycloak.broker.saml.mappers;
|
|||||||
|
|
||||||
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
import org.keycloak.broker.provider.AbstractIdentityProviderMapper;
|
||||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
|
||||||
import org.keycloak.broker.saml.SAMLEndpoint;
|
import org.keycloak.broker.saml.SAMLEndpoint;
|
||||||
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
import org.keycloak.broker.saml.SAMLIdentityProviderFactory;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
import org.keycloak.dom.saml.v2.assertion.AssertionType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeStatementType;
|
||||||
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
import org.keycloak.dom.saml.v2.assertion.AttributeType;
|
||||||
import org.keycloak.models.ClientModel;
|
|
||||||
import org.keycloak.models.IdentityProviderMapperModel;
|
import org.keycloak.models.IdentityProviderMapperModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RoleModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
|
|
||||||
@@ -87,7 +84,7 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper {
|
|||||||
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
||||||
Object value = getAttribute(mapperModel, context);
|
Object value = getAttribute(mapperModel, context);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
user.setAttribute(attribute, value.toString());
|
user.setSingleAttribute(attribute, value.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +98,7 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper {
|
|||||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||||
AttributeType attr = choice.getAttribute();
|
AttributeType attr = choice.getAttribute();
|
||||||
if (name != null && !name.equals(attr.getName())) continue;
|
if (name != null && !name.equals(attr.getName())) continue;
|
||||||
if (friendly != null && !name.equals(attr.getFriendlyName())) continue;
|
if (friendly != null && !friendly.equals(attr.getFriendlyName())) continue;
|
||||||
|
|
||||||
List<Object> attributeValue = attr.getAttributeValue();
|
List<Object> attributeValue = attr.getAttributeValue();
|
||||||
if (attributeValue == null || attributeValue.isEmpty()) return null;
|
if (attributeValue == null || attributeValue.isEmpty()) return null;
|
||||||
@@ -115,9 +112,9 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper {
|
|||||||
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
public void updateBrokeredUser(KeycloakSession session, RealmModel realm, UserModel user, IdentityProviderMapperModel mapperModel, BrokeredIdentityContext context) {
|
||||||
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
String attribute = mapperModel.getConfig().get(USER_ATTRIBUTE);
|
||||||
Object value = getAttribute(mapperModel, context);
|
Object value = getAttribute(mapperModel, context);
|
||||||
String current = user.getAttribute(attribute);
|
String current = user.getFirstAttribute(attribute);
|
||||||
if (value != null && !value.equals(current)) {
|
if (value != null && !value.equals(current)) {
|
||||||
user.setAttribute(attribute, value.toString());
|
user.setSingleAttribute(attribute, value.toString());
|
||||||
} else if (value == null) {
|
} else if (value == null) {
|
||||||
user.removeAttribute(attribute);
|
user.removeAttribute(attribute);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,25 +4,27 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>keycloak-model-sessions-mem</artifactId>
|
<artifactId>keycloak-client-api</artifactId>
|
||||||
<name>Keycloak Model Sessions Mem</name>
|
<name>Keycloak Client API</name>
|
||||||
<description/>
|
<description/>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<artifactId>keycloak-core</artifactId>
|
<artifactId>keycloak-core</artifactId>
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
<artifactId>keycloak-model-api</artifactId>
|
<artifactId>httpclient</artifactId>
|
||||||
<scope>provided</scope>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
package org.keycloak.client.registration;
|
||||||
|
|
||||||
|
import org.apache.http.HttpHeaders;
|
||||||
|
import org.apache.http.HttpRequest;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.HttpClient;
|
||||||
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.client.methods.HttpPut;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.common.util.Base64;
|
||||||
|
import org.keycloak.util.JsonSerialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ClientRegistration {
|
||||||
|
|
||||||
|
private String clientRegistrationUrl;
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private Auth auth;
|
||||||
|
|
||||||
|
public static ClientRegistrationBuilder create() {
|
||||||
|
return new ClientRegistrationBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClientRegistration() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRepresentation create(ClientRepresentation client) throws ClientRegistrationException {
|
||||||
|
String content = serialize(client);
|
||||||
|
InputStream resultStream = doPost(content);
|
||||||
|
return deserialize(resultStream, ClientRepresentation.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRepresentation get() throws ClientRegistrationException {
|
||||||
|
if (auth instanceof ClientIdSecretAuth) {
|
||||||
|
String clientId = ((ClientIdSecretAuth) auth).clientId;
|
||||||
|
return get(clientId);
|
||||||
|
} else {
|
||||||
|
throw new ClientRegistrationException("Requires client authentication");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRepresentation get(String clientId) throws ClientRegistrationException {
|
||||||
|
InputStream resultStream = doGet(clientId);
|
||||||
|
return resultStream != null ? deserialize(resultStream, ClientRepresentation.class) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(ClientRepresentation client) throws ClientRegistrationException {
|
||||||
|
String content = serialize(client);
|
||||||
|
doPut(content, client.getClientId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() throws ClientRegistrationException {
|
||||||
|
if (auth instanceof ClientIdSecretAuth) {
|
||||||
|
String clientId = ((ClientIdSecretAuth) auth).clientId;
|
||||||
|
delete(clientId);
|
||||||
|
} else {
|
||||||
|
throw new ClientRegistrationException("Requires client authentication");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(String clientId) throws ClientRegistrationException {
|
||||||
|
doDelete(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws ClientRegistrationException {
|
||||||
|
if (httpClient instanceof CloseableHttpClient) {
|
||||||
|
try {
|
||||||
|
((CloseableHttpClient) httpClient).close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to close http client", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream doPost(String content) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
HttpPost request = new HttpPost(clientRegistrationUrl);
|
||||||
|
|
||||||
|
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
||||||
|
request.setHeader(HttpHeaders.ACCEPT, "application/json");
|
||||||
|
request.setEntity(new StringEntity(content));
|
||||||
|
|
||||||
|
auth.addAuth(request);
|
||||||
|
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
InputStream responseStream = null;
|
||||||
|
if (response.getEntity() != null) {
|
||||||
|
responseStream = response.getEntity().getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() == 201) {
|
||||||
|
return responseStream;
|
||||||
|
} else {
|
||||||
|
responseStream.close();
|
||||||
|
throw new HttpErrorException(response.getStatusLine());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to send request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InputStream doGet(String endpoint) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
HttpGet request = new HttpGet(clientRegistrationUrl + "/" + endpoint);
|
||||||
|
|
||||||
|
request.setHeader(HttpHeaders.ACCEPT, "application/json");
|
||||||
|
|
||||||
|
auth.addAuth(request);
|
||||||
|
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
InputStream responseStream = null;
|
||||||
|
if (response.getEntity() != null) {
|
||||||
|
responseStream = response.getEntity().getContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() == 200) {
|
||||||
|
return responseStream;
|
||||||
|
} else if (response.getStatusLine().getStatusCode() == 404) {
|
||||||
|
responseStream.close();
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
responseStream.close();
|
||||||
|
throw new HttpErrorException(response.getStatusLine());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to send request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doPut(String content, String endpoint) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
HttpPut request = new HttpPut(clientRegistrationUrl + "/" + endpoint);
|
||||||
|
|
||||||
|
request.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
|
||||||
|
request.setHeader(HttpHeaders.ACCEPT, "application/json");
|
||||||
|
request.setEntity(new StringEntity(content));
|
||||||
|
|
||||||
|
auth.addAuth(request);
|
||||||
|
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
if (response.getEntity() != null) {
|
||||||
|
response.getEntity().getContent().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() != 200) {
|
||||||
|
throw new HttpErrorException(response.getStatusLine());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to send request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doDelete(String endpoint) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
HttpDelete request = new HttpDelete(clientRegistrationUrl + "/" + endpoint);
|
||||||
|
|
||||||
|
auth.addAuth(request);
|
||||||
|
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
if (response.getEntity() != null) {
|
||||||
|
response.getEntity().getContent().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.getStatusLine().getStatusCode() != 200) {
|
||||||
|
throw new HttpErrorException(response.getStatusLine());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to send request", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String serialize(ClientRepresentation client) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
return JsonSerialization.writeValueAsString(client);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to write json object", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T deserialize(InputStream inputStream, Class<T> clazz) throws ClientRegistrationException {
|
||||||
|
try {
|
||||||
|
return JsonSerialization.readValue(inputStream, clazz);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ClientRegistrationException("Failed to read json object", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ClientRegistrationBuilder {
|
||||||
|
|
||||||
|
private String realm;
|
||||||
|
|
||||||
|
private String authServerUrl;
|
||||||
|
|
||||||
|
private Auth auth;
|
||||||
|
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
public ClientRegistrationBuilder realm(String realm) {
|
||||||
|
this.realm = realm;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public ClientRegistrationBuilder authServerUrl(String authServerUrl) {
|
||||||
|
this.authServerUrl = authServerUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationBuilder auth(String token) {
|
||||||
|
this.auth = new TokenAuth(token);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationBuilder auth(String clientId, String clientSecret) {
|
||||||
|
this.auth = new ClientIdSecretAuth(clientId, clientSecret);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationBuilder httpClient(HttpClient httpClient) {
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistration build() {
|
||||||
|
ClientRegistration clientRegistration = new ClientRegistration();
|
||||||
|
clientRegistration.clientRegistrationUrl = authServerUrl + "/realms/" + realm + "/client-registration/default";
|
||||||
|
|
||||||
|
clientRegistration.httpClient = httpClient != null ? httpClient : HttpClients.createDefault();
|
||||||
|
clientRegistration.auth = auth;
|
||||||
|
|
||||||
|
return clientRegistration;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface Auth {
|
||||||
|
void addAuth(HttpRequest httpRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AuthorizationHeaderAuth implements Auth {
|
||||||
|
private String credentials;
|
||||||
|
|
||||||
|
public AuthorizationHeaderAuth(String credentials) {
|
||||||
|
this.credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAuth(HttpRequest httpRequest) {
|
||||||
|
httpRequest.setHeader(HttpHeaders.AUTHORIZATION, credentials);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TokenAuth extends AuthorizationHeaderAuth {
|
||||||
|
public TokenAuth(String token) {
|
||||||
|
super("Bearer " + token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ClientIdSecretAuth extends AuthorizationHeaderAuth {
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
public ClientIdSecretAuth(String clientId, String clientSecret) {
|
||||||
|
super("Basic " + Base64.encodeBytes((clientId + ":" + clientSecret).getBytes()));
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package org.keycloak.client.registration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class ClientRegistrationException extends Exception {
|
||||||
|
|
||||||
|
public ClientRegistrationException(String s, Throwable throwable) {
|
||||||
|
super(s, throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientRegistrationException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.keycloak.client.registration;
|
||||||
|
|
||||||
|
import org.apache.http.StatusLine;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
*/
|
||||||
|
public class HttpErrorException extends IOException {
|
||||||
|
|
||||||
|
private StatusLine statusLine;
|
||||||
|
|
||||||
|
public HttpErrorException(StatusLine statusLine) {
|
||||||
|
this.statusLine = statusLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StatusLine getStatusLine() {
|
||||||
|
return statusLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Executable
+94
@@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.6.1.Final</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>keycloak-common</artifactId>
|
||||||
|
<name>Keycloak Common</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<description>Common library and dependencies shared with server and all adapters</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<timestamp>${maven.build.timestamp}</timestamp>
|
||||||
|
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||||
|
<keycloak.osgi.export>
|
||||||
|
org.keycloak.common.*
|
||||||
|
</keycloak.osgi.export>
|
||||||
|
<keycloak.osgi.import>
|
||||||
|
*;resolution:=optional
|
||||||
|
</keycloak.osgi.import>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcpkix-jdk15on</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>${maven.compiler.source}</source>
|
||||||
|
<target>${maven.compiler.target}</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>bundle-manifest</id>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>manifest</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<instructions>
|
||||||
|
<Bundle-ClassPath>.</Bundle-ClassPath>
|
||||||
|
<Bundle-Name>${project.name}</Bundle-Name>
|
||||||
|
<Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
|
||||||
|
<Import-Package>${keycloak.osgi.import}</Import-Package>
|
||||||
|
<Export-Package>${keycloak.osgi.export}</Export-Package>
|
||||||
|
</instructions>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak;
|
package org.keycloak.common;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the client connection
|
* Information about the client connection
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak;
|
package org.keycloak.common;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package org.keycloak.common;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.Time;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class Version {
|
||||||
|
public static final String UNKNOWN = "UNKNOWN";
|
||||||
|
public static String VERSION;
|
||||||
|
public static String RESOURCES_VERSION;
|
||||||
|
public static String BUILD_TIME;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Properties props = new Properties();
|
||||||
|
InputStream is = Version.class.getResourceAsStream("/keycloak-version.properties");
|
||||||
|
try {
|
||||||
|
props.load(is);
|
||||||
|
Version.VERSION = props.getProperty("version");
|
||||||
|
Version.BUILD_TIME = props.getProperty("build-time");
|
||||||
|
Version.RESOURCES_VERSION = Version.VERSION.toLowerCase();
|
||||||
|
if (Version.RESOURCES_VERSION.endsWith("-snapshot")) {
|
||||||
|
Version.RESOURCES_VERSION = Version.RESOURCES_VERSION.replace("-snapshot", "-" + Time.currentTime());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Version.VERSION= Version.UNKNOWN;
|
||||||
|
Version.BUILD_TIME= Version.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.constants;
|
package org.keycloak.common.constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.constants;
|
package org.keycloak.common.constants;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.keycloak.common.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public interface ServiceAccountConstants {
|
||||||
|
|
||||||
|
String CLIENT_AUTH = "client_auth";
|
||||||
|
|
||||||
|
String SERVICE_ACCOUNT_USER_PREFIX = "service-account-";
|
||||||
|
|
||||||
|
String CLIENT_ID_PROTOCOL_MAPPER = "Client ID";
|
||||||
|
String CLIENT_HOST_PROTOCOL_MAPPER = "Client Host";
|
||||||
|
String CLIENT_ADDRESS_PROTOCOL_MAPPER = "Client IP Address";
|
||||||
|
String CLIENT_ID = "clientId";
|
||||||
|
String CLIENT_HOST = "clientHost";
|
||||||
|
String CLIENT_ADDRESS = "clientAddress";
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.enums;
|
package org.keycloak.common.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package org.keycloak.enums;
|
package org.keycloak.common.enums;
|
||||||
|
|
||||||
import org.keycloak.ClientConnection;
|
import org.keycloak.common.ClientConnection;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
File diff suppressed because it is too large.
Load diff
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
|
|
||||||
import net.iharder.Base64;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
|
|
||||||
+1
-2
@@ -1,10 +1,9 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import org.keycloak.constants.GenericConstants;
|
import org.keycloak.common.constants.GenericConstants;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
+1
-1
@@ -15,7 +15,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author pedroigor
|
* @author pedroigor
|
||||||
+3
-4
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -12,13 +12,12 @@ import java.lang.reflect.Method;
|
|||||||
|
|
||||||
import javax.security.auth.kerberos.KerberosTicket;
|
import javax.security.auth.kerberos.KerberosTicket;
|
||||||
|
|
||||||
import net.iharder.Base64;
|
|
||||||
import org.ietf.jgss.GSSCredential;
|
import org.ietf.jgss.GSSCredential;
|
||||||
import org.ietf.jgss.GSSException;
|
import org.ietf.jgss.GSSException;
|
||||||
import org.ietf.jgss.GSSManager;
|
import org.ietf.jgss.GSSManager;
|
||||||
import org.ietf.jgss.Oid;
|
import org.ietf.jgss.Oid;
|
||||||
import org.keycloak.constants.KerberosConstants;
|
import org.keycloak.common.constants.KerberosConstants;
|
||||||
import org.keycloak.util.reflections.Reflections;
|
import org.keycloak.common.util.reflections.Reflections;
|
||||||
import sun.security.jgss.GSSCredentialImpl;
|
import sun.security.jgss.GSSCredentialImpl;
|
||||||
import sun.security.jgss.GSSManagerImpl;
|
import sun.security.jgss.GSSManagerImpl;
|
||||||
import sun.security.jgss.krb5.Krb5InitCredential;
|
import sun.security.jgss.krb5.Krb5InitCredential;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
|
||||||
|
import org.keycloak.common.constants.GenericConstants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class KeystoreUtil {
|
||||||
|
static {
|
||||||
|
BouncyIntegration.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum KeystoreFormat {
|
||||||
|
JKS,
|
||||||
|
PKCS12
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
|
||||||
|
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||||
|
InputStream trustStream = (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH))
|
||||||
|
?KeystoreUtil.class.getResourceAsStream(filename.replace(GenericConstants.PROTOCOL_CLASSPATH, ""))
|
||||||
|
:new FileInputStream(new File(filename));
|
||||||
|
trustStore.load(trustStream, password.toCharArray());
|
||||||
|
trustStream.close();
|
||||||
|
return trustStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrivateKey loadPrivateKeyFromKeystore(String keystoreFile, String storePassword, String keyPassword, String keyAlias, KeystoreFormat format) {
|
||||||
|
InputStream stream = FindFile.findFile(keystoreFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
KeyStore keyStore = null;
|
||||||
|
if (format == KeystoreFormat.JKS) {
|
||||||
|
keyStore = KeyStore.getInstance(format.toString());
|
||||||
|
} else {
|
||||||
|
keyStore = KeyStore.getInstance(format.toString(), "BC");
|
||||||
|
}
|
||||||
|
|
||||||
|
keyStore.load(stream, storePassword.toCharArray());
|
||||||
|
PrivateKey key = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
|
||||||
|
if (key == null) {
|
||||||
|
throw new RuntimeException("Couldn't load key with alias '" + keyAlias + "' from keystore");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to load private key: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import javax.activation.MimetypesFileTypeMap;
|
import javax.activation.MimetypesFileTypeMap;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JBoss, Home of Professional Open Source.
|
* JBoss, Home of Professional Open Source.
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
|
|
||||||
import net.iharder.Base64;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
*/
|
*/
|
||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util;
|
package org.keycloak.common.util;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util.reflections;
|
package org.keycloak.common.util.reflections;
|
||||||
|
|
||||||
import java.beans.Introspector;
|
import java.beans.Introspector;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util.reflections;
|
package org.keycloak.common.util.reflections;
|
||||||
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
import java.lang.reflect.AccessibleObject;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package org.keycloak.util.reflections;
|
package org.keycloak.common.util.reflections;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
version=${product.version}
|
||||||
|
build-time=${product.build-time}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+1
-12
@@ -90,18 +90,7 @@ public class DefaultFileConnectionProviderFactory implements FileConnectionProvi
|
|||||||
ImportUtils.importFromStream(session, JsonSerialization.mapper, fis, Strategy.IGNORE_EXISTING);
|
ImportUtils.importFromStream(session, JsonSerialization.mapper, fis, Strategy.IGNORE_EXISTING);
|
||||||
session.realms().getMigrationModel().setStoredVersion(model.getModelVersion());
|
session.realms().getMigrationModel().setStoredVersion(model.getModelVersion());
|
||||||
|
|
||||||
List<RealmRepresentation> realmReps = new ArrayList<RealmRepresentation>();
|
ImportUtils.importRealms(session, model.getRealms(), Strategy.IGNORE_EXISTING);
|
||||||
for (RealmRepresentation realmRep : model.getRealms()) {
|
|
||||||
if (Config.getAdminRealm().equals(realmRep.getRealm())) {
|
|
||||||
realmReps.add(0, realmRep);
|
|
||||||
} else {
|
|
||||||
realmReps.add(realmRep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (RealmRepresentation realmRep : realmReps) {
|
|
||||||
ImportUtils.importRealm(session, realmRep, Strategy.IGNORE_EXISTING);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
logger.error("Unable to read model file " + kcdata.getAbsolutePath(), ioe);
|
logger.error("Unable to read model file " + kcdata.getAbsolutePath(), ioe);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+2
-2
@@ -12,8 +12,8 @@ import org.jboss.logging.Logger;
|
|||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.util.EnvUtil;
|
import org.keycloak.common.util.EnvUtil;
|
||||||
import org.keycloak.util.KeystoreUtil;
|
import org.keycloak.common.util.KeystoreUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@@ -27,5 +27,6 @@
|
|||||||
<artifactId>infinispan-core</artifactId>
|
<artifactId>infinispan-core</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
+13
@@ -66,6 +66,19 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
|
|||||||
} else {
|
} else {
|
||||||
initEmbedded();
|
initEmbedded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backwards compatibility
|
||||||
|
if (cacheManager.getCacheConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME) == null) {
|
||||||
|
logger.warnf("No configuration provided for '%s' cache. Using '%s' configuration as template",
|
||||||
|
InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, InfinispanConnectionProvider.SESSION_CACHE_NAME);
|
||||||
|
|
||||||
|
Configuration sessionCacheConfig = cacheManager.getCacheConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME);
|
||||||
|
if (sessionCacheConfig != null) {
|
||||||
|
ConfigurationBuilder confBuilder = new ConfigurationBuilder().read(sessionCacheConfig);
|
||||||
|
Configuration offlineSessionConfig = confBuilder.build();
|
||||||
|
cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, offlineSessionConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -11,6 +11,7 @@ public interface InfinispanConnectionProvider extends Provider {
|
|||||||
static final String REALM_CACHE_NAME = "realms";
|
static final String REALM_CACHE_NAME = "realms";
|
||||||
static final String USER_CACHE_NAME = "users";
|
static final String USER_CACHE_NAME = "users";
|
||||||
static final String SESSION_CACHE_NAME = "sessions";
|
static final String SESSION_CACHE_NAME = "sessions";
|
||||||
|
static final String OFFLINE_SESSION_CACHE_NAME = "offlineSessions";
|
||||||
static final String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
|
static final String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
|
||||||
|
|
||||||
<K, V> Cache<K, V> getCache(String name);
|
<K, V> Cache<K, V> getCache(String name);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+15
-8
@@ -46,26 +46,26 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||||||
private static final String CHANGELOG = "META-INF/jpa-changelog-master.xml";
|
private static final String CHANGELOG = "META-INF/jpa-changelog-master.xml";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCurrentVersionSql() {
|
public String getCurrentVersionSql(String defaultSchema) {
|
||||||
return "SELECT ID from DATABASECHANGELOG ORDER BY DATEEXECUTED DESC LIMIT 1";
|
return "SELECT ID from " + getTable("DATABASECHANGELOG", defaultSchema) + " ORDER BY DATEEXECUTED DESC LIMIT 1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(KeycloakSession session, Connection connection) {
|
public void update(KeycloakSession session, Connection connection, String defaultSchema) {
|
||||||
logger.debug("Starting database update");
|
logger.debug("Starting database update");
|
||||||
|
|
||||||
// Need ThreadLocal as liquibase doesn't seem to have API to inject custom objects into tasks
|
// Need ThreadLocal as liquibase doesn't seem to have API to inject custom objects into tasks
|
||||||
ThreadLocalSessionContext.setCurrentSession(session);
|
ThreadLocalSessionContext.setCurrentSession(session);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Liquibase liquibase = getLiquibase(connection);
|
Liquibase liquibase = getLiquibase(connection, defaultSchema);
|
||||||
|
|
||||||
List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
|
List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
|
||||||
if (!changeSets.isEmpty()) {
|
if (!changeSets.isEmpty()) {
|
||||||
if (changeSets.get(0).getId().equals(FIRST_VERSION)) {
|
if (changeSets.get(0).getId().equals(FIRST_VERSION)) {
|
||||||
Statement statement = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
try {
|
try {
|
||||||
statement.executeQuery("SELECT id FROM REALM");
|
statement.executeQuery("SELECT id FROM " + getTable("REALM", defaultSchema));
|
||||||
|
|
||||||
logger.infov("Updating database from {0} to {1}", FIRST_VERSION, changeSets.get(changeSets.size() - 1).getId());
|
logger.infov("Updating database from {0} to {1}", FIRST_VERSION, changeSets.get(changeSets.size() - 1).getId());
|
||||||
liquibase.markNextChangeSetRan(null);
|
liquibase.markNextChangeSetRan(null);
|
||||||
@@ -93,9 +93,9 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(Connection connection) {
|
public void validate(Connection connection, String defaultSchema) {
|
||||||
try {
|
try {
|
||||||
Liquibase liquibase = getLiquibase(connection);
|
Liquibase liquibase = getLiquibase(connection, defaultSchema);
|
||||||
|
|
||||||
liquibase.validate();
|
liquibase.validate();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -103,7 +103,7 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Liquibase getLiquibase(Connection connection) throws Exception {
|
private Liquibase getLiquibase(Connection connection, String defaultSchema) throws Exception {
|
||||||
ServiceLocator sl = ServiceLocator.getInstance();
|
ServiceLocator sl = ServiceLocator.getInstance();
|
||||||
|
|
||||||
if (!System.getProperties().containsKey("liquibase.scan.packages")) {
|
if (!System.getProperties().containsKey("liquibase.scan.packages")) {
|
||||||
@@ -125,6 +125,9 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||||||
|
|
||||||
LogFactory.setInstance(new LogWrapper());
|
LogFactory.setInstance(new LogWrapper());
|
||||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||||
|
if (defaultSchema != null) {
|
||||||
|
database.setDefaultSchemaName(defaultSchema);
|
||||||
|
}
|
||||||
return new Liquibase(CHANGELOG, new ClassLoaderResourceAccessor(getClass().getClassLoader()), database);
|
return new Liquibase(CHANGELOG, new ClassLoaderResourceAccessor(getClass().getClassLoader()), database);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,4 +231,8 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getTable(String table, String defaultSchema) {
|
||||||
|
return defaultSchema != null ? defaultSchema + "." + table : table;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-1
@@ -12,6 +12,7 @@ import liquibase.statement.SqlStatement;
|
|||||||
import liquibase.statement.core.UpdateStatement;
|
import liquibase.statement.core.UpdateStatement;
|
||||||
import liquibase.structure.core.Schema;
|
import liquibase.structure.core.Schema;
|
||||||
import liquibase.structure.core.Table;
|
import liquibase.structure.core.Table;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
@@ -36,7 +37,7 @@ public class AddRealmCodeSecret implements CustomSqlChange {
|
|||||||
|
|
||||||
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
||||||
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
|
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
|
||||||
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM REALM WHERE CODE_SECRET IS NULL");
|
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM " + LiquibaseJpaUpdaterProvider.getTable(correctedTableName, database.getDefaultSchemaName()) + " WHERE CODE_SECRET IS NULL");
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
String id = resultSet.getString(1);
|
String id = resultSet.getString(1);
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -16,6 +16,7 @@ import liquibase.snapshot.SnapshotGeneratorFactory;
|
|||||||
import liquibase.statement.SqlStatement;
|
import liquibase.statement.SqlStatement;
|
||||||
import liquibase.structure.core.Table;
|
import liquibase.structure.core.Table;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||||
import org.keycloak.connections.jpa.updater.liquibase.ThreadLocalSessionContext;
|
import org.keycloak.connections.jpa.updater.liquibase.ThreadLocalSessionContext;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||||
@@ -88,7 +89,7 @@ public abstract class CustomKeycloakTask implements CustomSqlChange {
|
|||||||
try {
|
try {
|
||||||
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
||||||
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
|
if (SnapshotGeneratorFactory.getInstance().has(new Table().setName(correctedTableName), database)) {
|
||||||
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM REALM");
|
ResultSet resultSet = connection.createStatement().executeQuery("SELECT ID FROM " + getTableName(correctedTableName));
|
||||||
try {
|
try {
|
||||||
return (resultSet.next());
|
return (resultSet.next());
|
||||||
} finally {
|
} finally {
|
||||||
@@ -108,4 +109,9 @@ public abstract class CustomKeycloakTask implements CustomSqlChange {
|
|||||||
protected abstract void generateStatementsImpl() throws CustomChangeException;
|
protected abstract void generateStatementsImpl() throws CustomChangeException;
|
||||||
|
|
||||||
protected abstract String getTaskId();
|
protected abstract String getTaskId();
|
||||||
|
|
||||||
|
// get Table name for sql selects
|
||||||
|
protected String getTableName(String tableName) {
|
||||||
|
return LiquibaseJpaUpdaterProvider.getTable(tableName, database.getDefaultSchemaName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+13
-8
@@ -11,6 +11,7 @@ import liquibase.statement.core.InsertStatement;
|
|||||||
import liquibase.statement.core.UpdateStatement;
|
import liquibase.statement.core.UpdateStatement;
|
||||||
import liquibase.structure.core.Table;
|
import liquibase.structure.core.Table;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||||
import org.keycloak.migration.MigrationProvider;
|
import org.keycloak.migration.MigrationProvider;
|
||||||
import org.keycloak.models.AdminRoles;
|
import org.keycloak.models.AdminRoles;
|
||||||
import org.keycloak.models.ClaimMask;
|
import org.keycloak.models.ClaimMask;
|
||||||
@@ -49,7 +50,10 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
String identityProviderTableName = database.correctObjectName("IDENTITY_PROVIDER", Table.class);
|
String identityProviderTableName = database.correctObjectName("IDENTITY_PROVIDER", Table.class);
|
||||||
String idpConfigTableName = database.correctObjectName("IDENTITY_PROVIDER_CONFIG", Table.class);
|
String idpConfigTableName = database.correctObjectName("IDENTITY_PROVIDER_CONFIG", Table.class);
|
||||||
|
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select RSC.NAME, VALUE, REALM_ID, UPDATE_PROFILE_ON_SOC_LOGIN from REALM_SOCIAL_CONFIG RSC,REALM where RSC.REALM_ID = REALM.ID ORDER BY RSC.REALM_ID, RSC.NAME");
|
String realmSocialConfigTable = getTableName("REALM_SOCIAL_CONFIG");
|
||||||
|
String realmTableName = getTableName("REALM");
|
||||||
|
PreparedStatement statement = jdbcConnection.prepareStatement("select RSC.NAME, VALUE, REALM_ID, UPDATE_PROFILE_ON_SOC_LOGIN from " + realmSocialConfigTable + " RSC," + realmTableName +
|
||||||
|
" REALM where RSC.REALM_ID = REALM.ID ORDER BY RSC.REALM_ID, RSC.NAME");
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
try {
|
try {
|
||||||
@@ -124,7 +128,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
|
|
||||||
protected void convertSocialToIdFedUsers() throws SQLException, DatabaseException {
|
protected void convertSocialToIdFedUsers() throws SQLException, DatabaseException {
|
||||||
String federatedIdentityTableName = database.correctObjectName("FEDERATED_IDENTITY", Table.class);
|
String federatedIdentityTableName = database.correctObjectName("FEDERATED_IDENTITY", Table.class);
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select REALM_ID, USER_ID, SOCIAL_PROVIDER, SOCIAL_USER_ID, SOCIAL_USERNAME from USER_SOCIAL_LINK");
|
PreparedStatement statement = jdbcConnection.prepareStatement("select REALM_ID, USER_ID, SOCIAL_PROVIDER, SOCIAL_USER_ID, SOCIAL_USERNAME from " + getTableName("USER_SOCIAL_LINK"));
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
try {
|
try {
|
||||||
@@ -170,7 +174,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
String adminRoleId = getAdminRoleId();
|
String adminRoleId = getAdminRoleId();
|
||||||
String masterRealmId = Config.getAdminRealm();
|
String masterRealmId = Config.getAdminRealm();
|
||||||
|
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME from REALM");
|
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME from " + getTableName("REALM"));
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
try {
|
try {
|
||||||
@@ -178,7 +182,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
String realmName = resultSet.getString("NAME");
|
String realmName = resultSet.getString("NAME");
|
||||||
String masterAdminAppName = realmName + "-realm";
|
String masterAdminAppName = realmName + "-realm";
|
||||||
|
|
||||||
PreparedStatement statement2 = jdbcConnection.prepareStatement("select ID from CLIENT where REALM_ID = ? AND NAME = ?");
|
PreparedStatement statement2 = jdbcConnection.prepareStatement("select ID from " + getTableName("CLIENT") + " where REALM_ID = ? AND NAME = ?");
|
||||||
statement2.setString(1, masterRealmId);
|
statement2.setString(1, masterRealmId);
|
||||||
statement2.setString(2, masterAdminAppName);
|
statement2.setString(2, masterAdminAppName);
|
||||||
|
|
||||||
@@ -209,7 +213,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getAdminRoleId() throws SQLException, DatabaseException {
|
private String getAdminRoleId() throws SQLException, DatabaseException {
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select ID from KEYCLOAK_ROLE where NAME = ? AND REALM = ?");
|
PreparedStatement statement = jdbcConnection.prepareStatement("select ID from " + getTableName("KEYCLOAK_ROLE") + " where NAME = ? AND REALM = ?");
|
||||||
statement.setString(1, AdminRoles.ADMIN);
|
statement.setString(1, AdminRoles.ADMIN);
|
||||||
statement.setString(2, Config.getAdminRealm());
|
statement.setString(2, Config.getAdminRealm());
|
||||||
|
|
||||||
@@ -231,7 +235,8 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
|
|
||||||
|
|
||||||
protected void addNewRealmAdminRoles() throws SQLException, DatabaseException {
|
protected void addNewRealmAdminRoles() throws SQLException, DatabaseException {
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select CLIENT.ID REALM_ADMIN_APP_ID, CLIENT.REALM_ID REALM_ID, KEYCLOAK_ROLE.ID ADMIN_ROLE_ID from CLIENT,KEYCLOAK_ROLE where KEYCLOAK_ROLE.APPLICATION = CLIENT.ID AND CLIENT.NAME = 'realm-management' AND KEYCLOAK_ROLE.NAME = ?");
|
PreparedStatement statement = jdbcConnection.prepareStatement("select CLIENT.ID REALM_ADMIN_APP_ID, CLIENT.REALM_ID REALM_ID, KEYCLOAK_ROLE.ID ADMIN_ROLE_ID from " +
|
||||||
|
getTableName("CLIENT") + " CLIENT," + getTableName("KEYCLOAK_ROLE") + " KEYCLOAK_ROLE where KEYCLOAK_ROLE.APPLICATION = CLIENT.ID AND CLIENT.NAME = 'realm-management' AND KEYCLOAK_ROLE.NAME = ?");
|
||||||
statement.setString(1, AdminRoles.REALM_ADMIN);
|
statement.setString(1, AdminRoles.REALM_ADMIN);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -280,7 +285,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
String protocolMapperTableName = database.correctObjectName("PROTOCOL_MAPPER", Table.class);
|
String protocolMapperTableName = database.correctObjectName("PROTOCOL_MAPPER", Table.class);
|
||||||
String protocolMapperCfgTableName = database.correctObjectName("PROTOCOL_MAPPER_CONFIG", Table.class);
|
String protocolMapperCfgTableName = database.correctObjectName("PROTOCOL_MAPPER_CONFIG", Table.class);
|
||||||
|
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select ID, NAME, ALLOWED_CLAIMS_MASK from CLIENT");
|
PreparedStatement statement = jdbcConnection.prepareStatement("select ID, NAME, ALLOWED_CLAIMS_MASK from " + getTableName("CLIENT"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
@@ -293,7 +298,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object acmObj = resultSet.getObject("ALLOWED_CLAIMS_MASK");
|
Object acmObj = resultSet.getObject("ALLOWED_CLAIMS_MASK");
|
||||||
long mask = (acmObj != null) ? (Long) acmObj : ClaimMask.ALL;
|
long mask = (acmObj != null) ? ((Number) acmObj).longValue() : ClaimMask.ALL;
|
||||||
|
|
||||||
MigrationProvider migrationProvider = this.kcSession.getProvider(MigrationProvider.class);
|
MigrationProvider migrationProvider = this.kcSession.getProvider(MigrationProvider.class);
|
||||||
List<ProtocolMapperRepresentation> protocolMappers = migrationProvider.getMappersForClaimMask(mask);
|
List<ProtocolMapperRepresentation> protocolMappers = migrationProvider.getMappersForClaimMask(mask);
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ public class JpaUpdate1_2_0_CR1 extends CustomKeycloakTask {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String trueValue = DataTypeFactory.getInstance().getTrueBooleanValue(database);
|
String trueValue = DataTypeFactory.getInstance().getTrueBooleanValue(database);
|
||||||
PreparedStatement statement = jdbcConnection.prepareStatement("select CLIENT.REALM_ID, CLIENT.ID CLIENT_ID from CLIENT where CLIENT.CONSENT_REQUIRED = " + trueValue);
|
PreparedStatement statement = jdbcConnection.prepareStatement("select CLIENT.REALM_ID, CLIENT.ID CLIENT_ID from " + getTableName("CLIENT") + " CLIENT where CLIENT.CONSENT_REQUIRED = " + trueValue);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = statement.executeQuery();
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package org.keycloak.connections.jpa.updater.liquibase.custom;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
import liquibase.datatype.DataTypeFactory;
|
||||||
|
import liquibase.exception.CustomChangeException;
|
||||||
|
import liquibase.statement.core.InsertStatement;
|
||||||
|
import liquibase.statement.core.UpdateStatement;
|
||||||
|
import liquibase.structure.core.Table;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class JpaUpdate1_4_0_Final extends CustomKeycloakTask {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateStatementsImpl() throws CustomChangeException {
|
||||||
|
String userAttributeTableName = database.correctObjectName("USER_ATTRIBUTE", Table.class);
|
||||||
|
|
||||||
|
try {
|
||||||
|
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME, USER_ID from " + getTableName("USER_ATTRIBUTE"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
ResultSet resultSet = statement.executeQuery();
|
||||||
|
try {
|
||||||
|
while (resultSet.next()) {
|
||||||
|
String name = resultSet.getString(1);
|
||||||
|
String userId = resultSet.getString(2);
|
||||||
|
|
||||||
|
UpdateStatement updateStatement = new UpdateStatement(null, null, userAttributeTableName)
|
||||||
|
.addNewColumnValue("ID", KeycloakModelUtils.generateId())
|
||||||
|
.setWhereClause("NAME='" + name + "' AND USER_ID='" + userId + "'");
|
||||||
|
statements.add(updateStatement);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
resultSet.close();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
confirmationMessage.append("Updated " + statements.size() + " attributes in USER_ATTRIBUTE table");
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CustomChangeException(getTaskId() + ": Exception when updating data from previous version", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTaskId() {
|
||||||
|
return "Update 1.4.0.Final";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -134,7 +134,7 @@
|
|||||||
<dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LOGIN"/>
|
<dropColumn tableName="IDENTITY_PROVIDER" columnName="UPDATE_PROFILE_FIRST_LOGIN"/>
|
||||||
|
|
||||||
<addColumn tableName="USER_REQUIRED_ACTION">
|
<addColumn tableName="USER_REQUIRED_ACTION">
|
||||||
<column name="REQUIRED_ACTION" type="VARCHAR(255)" defaultValue="">
|
<column name="REQUIRED_ACTION" type="VARCHAR(255)" defaultValue=" ">
|
||||||
<constraints nullable="false"/>
|
<constraints nullable="false"/>
|
||||||
</column>
|
</column>
|
||||||
</addColumn>
|
</addColumn>
|
||||||
@@ -177,9 +177,22 @@
|
|||||||
<dropDefaultValue tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED" />
|
<dropDefaultValue tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED" />
|
||||||
<dropColumn tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED"/>
|
<dropColumn tableName="REALM" columnName="PASSWORD_CRED_GRANT_ALLOWED"/>
|
||||||
|
|
||||||
|
<!-- KEYCLOAK-1298 Change constraint names to be upper-cased -->
|
||||||
|
<dropForeignKeyConstraint baseTableName="PROTOCOL_MAPPER_CONFIG" constraintName="FK_PMConfig" />
|
||||||
|
<dropPrimaryKey constraintName="CONSTRAINT_PMConfig" tableName="PROTOCOL_MAPPER_CONFIG"/>
|
||||||
|
<addPrimaryKey columnNames="PROTOCOL_MAPPER_ID, NAME" constraintName="CONSTRAINT_PMCONFIG" tableName="PROTOCOL_MAPPER_CONFIG"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="PROTOCOL_MAPPER_ID" baseTableName="PROTOCOL_MAPPER_CONFIG" constraintName="FK_PMCONFIG" referencedColumnNames="ID" referencedTableName="PROTOCOL_MAPPER"/>
|
||||||
|
|
||||||
|
<dropForeignKeyConstraint baseTableName="IDP_MAPPER_CONFIG" constraintName="FK_IDPMConfig" />
|
||||||
|
<dropPrimaryKey constraintName="CONSTRAINT_IDPMConfig" tableName="IDP_MAPPER_CONFIG"/>
|
||||||
|
<addPrimaryKey columnNames="IDP_MAPPER_ID, NAME" constraintName="CONSTRAINT_IDPMCONFIG" tableName="IDP_MAPPER_CONFIG"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="IDP_MAPPER_ID" baseTableName="IDP_MAPPER_CONFIG" constraintName="FK_IDPMCONFIG" referencedColumnNames="ID" referencedTableName="IDENTITY_PROVIDER_MAPPER"/>
|
||||||
|
|
||||||
<!-- Sybase specific hacks -->
|
<!-- Sybase specific hacks -->
|
||||||
<modifySql dbms="sybase">
|
<modifySql dbms="sybase">
|
||||||
<replace replace="DROP PRIMARY KEY" with="DROP CONSTRAINT CONSTRAINT_2" />
|
<replace replace="[USER_REQUIRED_ACTION] DROP PRIMARY KEY" with="[USER_REQUIRED_ACTION] DROP CONSTRAINT CONSTRAINT_2" />
|
||||||
|
<replace replace="[PROTOCOL_MAPPER_CONFIG] DROP PRIMARY KEY" with="[PROTOCOL_MAPPER_CONFIG] DROP CONSTRAINT CONSTRAINT_PMConfig" />
|
||||||
|
<replace replace="[IDP_MAPPER_CONFIG] DROP PRIMARY KEY" with="[IDP_MAPPER_CONFIG] DROP CONSTRAINT CONSTRAINT_IDPMConfig" />
|
||||||
<regExpReplace replace=".*(SET DEFAULT NULL)" with="SELECT 1" />
|
<regExpReplace replace=".*(SET DEFAULT NULL)" with="SELECT 1" />
|
||||||
</modifySql>
|
</modifySql>
|
||||||
|
|
||||||
|
|||||||
+156
@@ -0,0 +1,156 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
<changeSet author="bburke@redhat.com" id="1.4.0">
|
||||||
|
<delete tableName="CLIENT_SESSION_AUTH_STATUS"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_ROLE"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_PROT_MAPPER"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_NOTE"/>
|
||||||
|
<delete tableName="CLIENT_SESSION"/>
|
||||||
|
<delete tableName="USER_SESSION_NOTE"/>
|
||||||
|
<delete tableName="USER_SESSION"/>
|
||||||
|
|
||||||
|
<addColumn tableName="CLIENT">
|
||||||
|
<column name="SERVICE_ACCOUNTS_ENABLED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="AUTHENTICATION_FLOW">
|
||||||
|
<column name="PROVIDER_ID" type="VARCHAR(36)" defaultValue="basic-flow">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="TOP_LEVEL" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="BUILT_IN" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="AUTHENTICATION_EXECUTION">
|
||||||
|
<column name="AUTH_FLOW_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="AUTH_CONFIG" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="USER_ATTRIBUTE">
|
||||||
|
<column name="ID" type="VARCHAR(36)" defaultValue="sybase-needs-something-here">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<dropColumn tableName="AUTHENTICATOR" columnName="PROVIDER_ID"/>
|
||||||
|
<renameTable oldTableName="AUTHENTICATOR_CONFIG" newTableName="AUTHENTICATOR_CONFIG_ENTRY"/>
|
||||||
|
<renameTable oldTableName="AUTHENTICATOR" newTableName="AUTHENTICATOR_CONFIG"/>
|
||||||
|
<!-- OAUTH_GRANT,
|
||||||
|
CODE_TO_TOKEN,
|
||||||
|
VERIFY_EMAIL,
|
||||||
|
UPDATE_PROFILE,
|
||||||
|
CONFIGURE_TOTP,
|
||||||
|
UPDATE_PASSWORD,
|
||||||
|
RECOVER_PASSWORD,
|
||||||
|
AUTHENTICATE,
|
||||||
|
SOCIAL_CALLBACK,
|
||||||
|
LOGGED_OUT -->
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="OAUTH_GRANT"/>
|
||||||
|
<where>ACTION = 0</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="CODE_TO_TOKEN"/>
|
||||||
|
<where>ACTION = 1</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="VERIFY_EMAIL"/>
|
||||||
|
<where>ACTION = 2</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="UPDATE_PROFILE"/>
|
||||||
|
<where>ACTION = 3</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="CONFIGURE_TOTP"/>
|
||||||
|
<where>ACTION = 4</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="UPDATE_PASSWORD"/>
|
||||||
|
<where>ACTION = 5</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="RECOVER_PASSWORD"/>
|
||||||
|
<where>ACTION = 6</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="AUTHENTICATE"/>
|
||||||
|
<where>ACTION = 7</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="SOCIAL_CALLBACK"/>
|
||||||
|
<where>ACTION = 8</where>
|
||||||
|
</update>
|
||||||
|
<update tableName="CLIENT_SESSION">
|
||||||
|
<column name="CURRENT_ACTION" value="LOGGED_OUT"/>
|
||||||
|
<where>ACTION = 9</where>
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<createTable tableName="CLIENT_USER_SESSION_NOTE">
|
||||||
|
<column name="NAME" type="VARCHAR(255)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="VALUE" type="VARCHAR(2048)"/>
|
||||||
|
<column name="CLIENT_SESSION" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="REQUIRED_ACTION_PROVIDER">
|
||||||
|
<column name="ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="ALIAS" type="VARCHAR(255)"/>
|
||||||
|
<column name="NAME" type="VARCHAR(255)"/>
|
||||||
|
<column name="REALM_ID" type="VARCHAR(36)"/>
|
||||||
|
<column name="ENABLED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="DEFAULT_ACTION" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="PROVIDER_ID" type="VARCHAR(255)"/>
|
||||||
|
</createTable>
|
||||||
|
<createTable tableName="REQUIRED_ACTION_CONFIG">
|
||||||
|
<column name="REQUIRED_ACTION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="VALUE" type="CLOB"/>
|
||||||
|
<column name="NAME" type="VARCHAR(255)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.JpaUpdate1_4_0_Final"/>
|
||||||
|
|
||||||
|
<dropPrimaryKey constraintName="CONSTRAINT_6" tableName="USER_ATTRIBUTE"/>
|
||||||
|
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_USER_ATTRIBUTE_PK" tableName="USER_ATTRIBUTE"/>
|
||||||
|
<addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_REQ_ACT_PRV_PK" tableName="REQUIRED_ACTION_PROVIDER"/>
|
||||||
|
<addPrimaryKey columnNames="REQUIRED_ACTION_ID, NAME" constraintName="CONSTRAINT_REQ_ACT_CFG_PK" tableName="REQUIRED_ACTION_CONFIG"/>
|
||||||
|
<addPrimaryKey columnNames="CLIENT_SESSION, NAME" constraintName="CONSTR_CL_USR_SES_NOTE" tableName="CLIENT_USER_SESSION_NOTE"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="REQUIRED_ACTION_PROVIDER" constraintName="FK_REQ_ACT_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
|
||||||
|
<addForeignKeyConstraint baseColumnNames="CLIENT_SESSION" baseTableName="CLIENT_USER_SESSION_NOTE" constraintName="FK_CL_USR_SES_NOTE" referencedColumnNames="ID" referencedTableName="CLIENT_SESSION"/>
|
||||||
|
<dropColumn tableName="CLIENT_SESSION" columnName="ACTION"/>
|
||||||
|
<addColumn tableName="USER_ENTITY">
|
||||||
|
<column name="CREATED_TIMESTAMP" type="BIGINT"/>
|
||||||
|
<column name="SERVICE_ACCOUNT_CLIENT_LINK" type="VARCHAR(36)"/>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<!-- Sybase specific hacks -->
|
||||||
|
<modifySql dbms="sybase">
|
||||||
|
<replace replace="[USER_ATTRIBUTE] DROP PRIMARY KEY" with="[USER_ATTRIBUTE] DROP CONSTRAINT CONSTRAINT_6" />
|
||||||
|
</modifySql>
|
||||||
|
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
<changeSet author="bburke@redhat.com" id="1.5.0">
|
||||||
|
<delete tableName="CLIENT_SESSION_AUTH_STATUS"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_ROLE"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_PROT_MAPPER"/>
|
||||||
|
<delete tableName="CLIENT_SESSION_NOTE"/>
|
||||||
|
<delete tableName="CLIENT_SESSION"/>
|
||||||
|
<delete tableName="USER_SESSION_NOTE"/>
|
||||||
|
<delete tableName="USER_SESSION"/>
|
||||||
|
|
||||||
|
<dropDefaultValue tableName="AUTHENTICATION_EXECUTION" columnName="USER_SETUP_ALLOWED" />
|
||||||
|
<dropColumn tableName="AUTHENTICATION_EXECUTION" columnName="USER_SETUP_ALLOWED"/>
|
||||||
|
<addColumn tableName="CREDENTIAL">
|
||||||
|
<column name="COUNTER" type="INT" defaultValueNumeric="0">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="DIGITS" type="INT" defaultValueNumeric="6">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="PERIOD" type="INT" defaultValueNumeric="30">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="ALGORITHM" type="VARCHAR(36)" defaultValue="HmacSHA1">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<addColumn tableName="REALM">
|
||||||
|
<column name="OTP_POLICY_COUNTER" type="INT" defaultValueNumeric="0">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="OTP_POLICY_WINDOW" type="INT" defaultValueNumeric="1">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="OTP_POLICY_PERIOD" type="INT" defaultValueNumeric="30">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="OTP_POLICY_DIGITS" type="INT" defaultValueNumeric="6">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="OTP_POLICY_ALG" type="VARCHAR(36)" defaultValue="HmacSHA1">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="OTP_POLICY_TYPE" type="VARCHAR(36)" defaultValue="totp">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="BROWSER_FLOW" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="REGISTRATION_FLOW" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="DIRECT_GRANT_FLOW" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="RESET_CREDENTIALS_FLOW" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
<column name="CLIENT_AUTH_FLOW" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<addColumn tableName="CLIENT">
|
||||||
|
<column name="CLIENT_AUTHENTICATOR_TYPE" type="VARCHAR(255)">
|
||||||
|
<constraints nullable="true"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<!-- Sybase specific hacks -->
|
||||||
|
<modifySql dbms="sybase">
|
||||||
|
<regExpReplace replace=".*(SET DEFAULT NULL)" with="SELECT 1" />
|
||||||
|
</modifySql>
|
||||||
|
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
<changeSet author="mposolda@redhat.com" id="1.6.0">
|
||||||
|
|
||||||
|
<addColumn tableName="REALM">
|
||||||
|
<column name="OFFLINE_SESSION_IDLE_TIMEOUT" type="INT" defaultValueNumeric="0"/>
|
||||||
|
<column name="REVOKE_REFRESH_TOKEN" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<addColumn tableName="KEYCLOAK_ROLE">
|
||||||
|
<column name="SCOPE_PARAM_REQUIRED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<addColumn tableName="CLIENT">
|
||||||
|
<column name="ROOT_URL" type="VARCHAR(255)"/>
|
||||||
|
<column name="DESCRIPTION" type="VARCHAR(255)"/>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<createTable tableName="OFFLINE_USER_SESSION">
|
||||||
|
<column name="USER_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USER_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="REALM_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="LAST_SESSION_REFRESH" type="INT"/>
|
||||||
|
<column name="OFFLINE" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="DATA" type="CLOB"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<createTable tableName="OFFLINE_CLIENT_SESSION">
|
||||||
|
<column name="CLIENT_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USER_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="CLIENT_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="OFFLINE" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="TIMESTAMP" type="INT"/>
|
||||||
|
<column name="DATA" type="CLOB"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addPrimaryKey columnNames="USER_SESSION_ID, OFFLINE" constraintName="CONSTRAINT_OFFLINE_US_SES_PK" tableName="OFFLINE_USER_SESSION"/>
|
||||||
|
<addPrimaryKey columnNames="CLIENT_SESSION_ID, OFFLINE" constraintName="CONSTRAINT_OFFLINE_CL_SES_PK" tableName="OFFLINE_CLIENT_SESSION"/>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||||
|
<changeSet author="mposolda@redhat.com" id="1.6.1_from15">
|
||||||
|
|
||||||
|
<preConditions onFail="MARK_RAN" onFailMessage="Upgrading from 1.6.0 version. Skipped 1.6.1_from15 changeSet and marked as ran">
|
||||||
|
<not>
|
||||||
|
<changeSetExecuted id="1.6.0" author="mposolda@redhat.com" changeLogFile="META-INF/jpa-changelog-1.6.0.xml" />
|
||||||
|
</not>
|
||||||
|
</preConditions>
|
||||||
|
|
||||||
|
<addColumn tableName="REALM">
|
||||||
|
<column name="OFFLINE_SESSION_IDLE_TIMEOUT" type="INT" defaultValueNumeric="0"/>
|
||||||
|
<column name="REVOKE_REFRESH_TOKEN" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<addColumn tableName="KEYCLOAK_ROLE">
|
||||||
|
<column name="SCOPE_PARAM_REQUIRED" type="BOOLEAN" defaultValueBoolean="false">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<addColumn tableName="CLIENT">
|
||||||
|
<column name="ROOT_URL" type="VARCHAR(255)"/>
|
||||||
|
<column name="DESCRIPTION" type="VARCHAR(255)"/>
|
||||||
|
</addColumn>
|
||||||
|
|
||||||
|
<createTable tableName="OFFLINE_USER_SESSION">
|
||||||
|
<column name="USER_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USER_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="REALM_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="LAST_SESSION_REFRESH" type="INT"/>
|
||||||
|
<column name="OFFLINE_FLAG" type="VARCHAR(4)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="DATA" type="CLOB"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<createTable tableName="OFFLINE_CLIENT_SESSION">
|
||||||
|
<column name="CLIENT_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="USER_SESSION_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="CLIENT_ID" type="VARCHAR(36)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="OFFLINE_FLAG" type="VARCHAR(4)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="TIMESTAMP" type="INT"/>
|
||||||
|
<column name="DATA" type="CLOB"/>
|
||||||
|
</createTable>
|
||||||
|
|
||||||
|
<addPrimaryKey columnNames="USER_SESSION_ID, OFFLINE_FLAG" constraintName="CONSTRAINT_OFFL_US_SES_PK2" tableName="OFFLINE_USER_SESSION"/>
|
||||||
|
<addPrimaryKey columnNames="CLIENT_SESSION_ID, OFFLINE_FLAG" constraintName="CONSTRAINT_OFFL_CL_SES_PK2" tableName="OFFLINE_CLIENT_SESSION"/>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
<!-- Just for the update from 1.6.0 -->
|
||||||
|
<changeSet author="mposolda@redhat.com" id="1.6.1_from16">
|
||||||
|
|
||||||
|
<preConditions onFail="MARK_RAN" onFailMessage="Upgrading from 1.5.0 or older version. Skipped 1.6.1_from16 changeSet and marked as ran">
|
||||||
|
<changeSetExecuted id="1.6.0" author="mposolda@redhat.com" changeLogFile="META-INF/jpa-changelog-1.6.0.xml" />
|
||||||
|
</preConditions>
|
||||||
|
|
||||||
|
<dropPrimaryKey constraintName="CONSTRAINT_OFFLINE_US_SES_PK" tableName="OFFLINE_USER_SESSION" />
|
||||||
|
<dropPrimaryKey constraintName="CONSTRAINT_OFFLINE_CL_SES_PK" tableName="OFFLINE_CLIENT_SESSION" />
|
||||||
|
|
||||||
|
<addColumn tableName="OFFLINE_USER_SESSION">
|
||||||
|
<column name="OFFLINE_FLAG" type="VARCHAR(4)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<update tableName="OFFLINE_USER_SESSION">
|
||||||
|
<column name="OFFLINE_FLAG" value="1"/>
|
||||||
|
</update>
|
||||||
|
<dropColumn tableName="OFFLINE_USER_SESSION" columnName="OFFLINE" />
|
||||||
|
|
||||||
|
<addColumn tableName="OFFLINE_CLIENT_SESSION">
|
||||||
|
<column name="OFFLINE_FLAG" type="VARCHAR(4)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
</addColumn>
|
||||||
|
<update tableName="OFFLINE_CLIENT_SESSION">
|
||||||
|
<column name="OFFLINE_FLAG" value="1"/>
|
||||||
|
</update>
|
||||||
|
<dropColumn tableName="OFFLINE_CLIENT_SESSION" columnName="OFFLINE" />
|
||||||
|
|
||||||
|
<addPrimaryKey columnNames="USER_SESSION_ID, OFFLINE_FLAG" constraintName="CONSTRAINT_OFFL_US_SES_PK2" tableName="OFFLINE_USER_SESSION"/>
|
||||||
|
<addPrimaryKey columnNames="CLIENT_SESSION_ID, OFFLINE_FLAG" constraintName="CONSTRAINT_OFFL_CL_SES_PK2" tableName="OFFLINE_CLIENT_SESSION"/>
|
||||||
|
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
<changeSet author="mposolda@redhat.com" id="1.6.1">
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -7,4 +7,7 @@
|
|||||||
<include file="META-INF/jpa-changelog-1.2.0.CR1.xml"/>
|
<include file="META-INF/jpa-changelog-1.2.0.CR1.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-1.2.0.Final.xml"/>
|
<include file="META-INF/jpa-changelog-1.2.0.Final.xml"/>
|
||||||
<include file="META-INF/jpa-changelog-1.3.0.xml"/>
|
<include file="META-INF/jpa-changelog-1.3.0.xml"/>
|
||||||
|
<include file="META-INF/jpa-changelog-1.4.0.xml"/>
|
||||||
|
<include file="META-INF/jpa-changelog-1.5.0.xml"/>
|
||||||
|
<include file="META-INF/jpa-changelog-1.6.1.xml"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate.javax.persistence</groupId>
|
<groupId>org.hibernate.javax.persistence</groupId>
|
||||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+38
-10
@@ -4,6 +4,7 @@ import org.hibernate.ejb.AvailableSettings;
|
|||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||||
|
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
|
|
||||||
@@ -13,10 +14,12 @@ import javax.persistence.EntityManagerFactory;
|
|||||||
import javax.persistence.Persistence;
|
import javax.persistence.Persistence;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.DriverManager;
|
import java.sql.DriverManager;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +33,8 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
|
|
||||||
private Config.Scope config;
|
private Config.Scope config;
|
||||||
|
|
||||||
|
private Map<String,String> operationalInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JpaConnectionProvider create(KeycloakSession session) {
|
public JpaConnectionProvider create(KeycloakSession session) {
|
||||||
lazyInit(session);
|
lazyInit(session);
|
||||||
@@ -70,14 +75,11 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
|
|
||||||
Connection connection = null;
|
Connection connection = null;
|
||||||
|
|
||||||
String unitName = config.get("unitName");
|
|
||||||
String databaseSchema = config.get("databaseSchema");
|
String databaseSchema = config.get("databaseSchema");
|
||||||
|
|
||||||
Map<String, Object> properties = new HashMap<String, Object>();
|
Map<String, Object> properties = new HashMap<String, Object>();
|
||||||
|
|
||||||
// Only load config from keycloak-server.json if unitName is not specified
|
String unitName = "keycloak-default";
|
||||||
if (unitName == null) {
|
|
||||||
unitName = "keycloak-default";
|
|
||||||
|
|
||||||
String dataSource = config.get("dataSource");
|
String dataSource = config.get("dataSource");
|
||||||
if (dataSource != null) {
|
if (dataSource != null) {
|
||||||
@@ -105,6 +107,11 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
properties.put("hibernate.dialect", driverDialect);
|
properties.put("hibernate.dialect", driverDialect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String schema = config.get("schema");
|
||||||
|
if (schema != null) {
|
||||||
|
properties.put(JpaUtils.HIBERNATE_DEFAULT_SCHEMA, schema);
|
||||||
|
}
|
||||||
|
|
||||||
if (databaseSchema != null) {
|
if (databaseSchema != null) {
|
||||||
if (databaseSchema.equals("development-update")) {
|
if (databaseSchema.equals("development-update")) {
|
||||||
properties.put("hibernate.hbm2ddl.auto", "update");
|
properties.put("hibernate.hbm2ddl.auto", "update");
|
||||||
@@ -117,7 +124,10 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
|
|
||||||
properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
|
properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
|
||||||
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
|
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
|
||||||
}
|
|
||||||
|
connection = getConnection();
|
||||||
|
try{
|
||||||
|
prepareOperationalInfo(connection);
|
||||||
|
|
||||||
if (databaseSchema != null) {
|
if (databaseSchema != null) {
|
||||||
logger.trace("Updating database");
|
logger.trace("Updating database");
|
||||||
@@ -127,12 +137,10 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
throw new RuntimeException("Can't update database: JPA updater provider not found");
|
throw new RuntimeException("Can't update database: JPA updater provider not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
connection = getConnection();
|
|
||||||
|
|
||||||
if (databaseSchema.equals("update")) {
|
if (databaseSchema.equals("update")) {
|
||||||
String currentVersion = null;
|
String currentVersion = null;
|
||||||
try {
|
try {
|
||||||
ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql());
|
ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql(schema));
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
currentVersion = resultSet.getString(1);
|
currentVersion = resultSet.getString(1);
|
||||||
}
|
}
|
||||||
@@ -140,12 +148,12 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
|
if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
|
||||||
updater.update(session, connection);
|
updater.update(session, connection, schema);
|
||||||
} else {
|
} else {
|
||||||
logger.debug("Database is up to date");
|
logger.debug("Database is up to date");
|
||||||
}
|
}
|
||||||
} else if (databaseSchema.equals("validate")) {
|
} else if (databaseSchema.equals("validate")) {
|
||||||
updater.validate(connection);
|
updater.validate(connection, schema);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
|
throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
|
||||||
}
|
}
|
||||||
@@ -157,6 +165,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
emf = Persistence.createEntityManagerFactory(unitName, properties);
|
emf = Persistence.createEntityManagerFactory(unitName, properties);
|
||||||
logger.trace("EntityManagerFactory created");
|
logger.trace("EntityManagerFactory created");
|
||||||
|
|
||||||
|
} finally {
|
||||||
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
|
// Close after creating EntityManagerFactory to prevent in-mem databases from closing
|
||||||
if (connection != null) {
|
if (connection != null) {
|
||||||
try {
|
try {
|
||||||
@@ -169,6 +178,20 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void prepareOperationalInfo(Connection connection) {
|
||||||
|
try {
|
||||||
|
operationalInfo = new LinkedHashMap<>();
|
||||||
|
DatabaseMetaData md = connection.getMetaData();
|
||||||
|
operationalInfo.put("databaseUrl",md.getURL());
|
||||||
|
operationalInfo.put("databaseUser", md.getUserName());
|
||||||
|
operationalInfo.put("databaseProduct", md.getDatabaseProductName() + " " + md.getDatabaseProductVersion());
|
||||||
|
operationalInfo.put("databaseDriver", md.getDriverName() + " " + md.getDriverVersion());
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.warn("Unable to prepare operational info due database exception: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Connection getConnection() {
|
private Connection getConnection() {
|
||||||
try {
|
try {
|
||||||
@@ -185,4 +208,9 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String,String> getOperationalInfo() {
|
||||||
|
return operationalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+3
-2
@@ -1,9 +1,10 @@
|
|||||||
package org.keycloak.connections.jpa;
|
package org.keycloak.connections.jpa;
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface JpaConnectionProviderFactory extends ProviderFactory<JpaConnectionProvider> {
|
public interface JpaConnectionProviderFactory extends ServerInfoAwareProviderFactory<JpaConnectionProvider> {
|
||||||
|
|
||||||
}
|
}
|
||||||
+4
-4
@@ -12,12 +12,12 @@ public interface JpaUpdaterProvider extends Provider {
|
|||||||
|
|
||||||
public String FIRST_VERSION = "1.0.0.Final";
|
public String FIRST_VERSION = "1.0.0.Final";
|
||||||
|
|
||||||
public String LAST_VERSION = "1.3.0.Beta1";
|
public String LAST_VERSION = "1.6.1";
|
||||||
|
|
||||||
public String getCurrentVersionSql();
|
public String getCurrentVersionSql(String defaultSchema);
|
||||||
|
|
||||||
public void update(KeycloakSession session, Connection connection);
|
public void update(KeycloakSession session, Connection connection, String defaultSchema);
|
||||||
|
|
||||||
public void validate(Connection connection);
|
public void validate(Connection connection, String defaultSchema);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.keycloak.connections.jpa.util;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class JpaUtils {
|
||||||
|
|
||||||
|
public static final String HIBERNATE_DEFAULT_SCHEMA = "hibernate.default_schema";
|
||||||
|
|
||||||
|
public static String getTableNameForNativeQuery(String tableName, EntityManager em) {
|
||||||
|
String schema = (String) em.getEntityManagerFactory().getProperties().get(HIBERNATE_DEFAULT_SCHEMA);
|
||||||
|
return (schema==null) ? tableName : schema + "." + tableName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,17 +27,10 @@
|
|||||||
<class>org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity</class>
|
<class>org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.AuthenticationFlowEntity</class>
|
<class>org.keycloak.models.jpa.entities.AuthenticationFlowEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.AuthenticationExecutionEntity</class>
|
<class>org.keycloak.models.jpa.entities.AuthenticationExecutionEntity</class>
|
||||||
<class>org.keycloak.models.jpa.entities.AuthenticatorEntity</class>
|
<class>org.keycloak.models.jpa.entities.AuthenticatorConfigEntity</class>
|
||||||
|
<class>org.keycloak.models.jpa.entities.RequiredActionProviderEntity</class>
|
||||||
<!-- JpaUserSessionProvider -->
|
<class>org.keycloak.models.jpa.session.PersistentUserSessionEntity</class>
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionEntity</class>
|
<class>org.keycloak.models.jpa.session.PersistentClientSessionEntity</class>
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionRoleEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionAuthStatusEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionProtocolMapperEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionNoteEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.UserSessionNoteEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.UserSessionEntity</class>
|
|
||||||
<class>org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity</class>
|
|
||||||
|
|
||||||
<!-- JpaAuditProviders -->
|
<!-- JpaAuditProviders -->
|
||||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+2
-1
@@ -27,7 +27,8 @@ public class DefaultMongoUpdaterProvider implements MongoUpdaterProvider {
|
|||||||
Update1_1_0_Beta1.class,
|
Update1_1_0_Beta1.class,
|
||||||
Update1_2_0_Beta1.class,
|
Update1_2_0_Beta1.class,
|
||||||
Update1_2_0_CR1.class,
|
Update1_2_0_CR1.class,
|
||||||
Update1_3_0.class
|
Update1_3_0.class,
|
||||||
|
Update1_4_0.class
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+1
-1
@@ -249,7 +249,7 @@ public class Update1_2_0_Beta1 extends Update {
|
|||||||
dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper());
|
dbMapper.put("protocolMapper", protocolMapper.getProtocolMapper());
|
||||||
|
|
||||||
Map<String, String> config = protocolMapper.getConfig();
|
Map<String, String> config = protocolMapper.getConfig();
|
||||||
BasicDBObject dbConfig = MapMapper.convertMap(config);
|
BasicDBObject dbConfig = MapMapper.convertMap(config, null);
|
||||||
dbMapper.put("config", dbConfig);
|
dbMapper.put("config", dbConfig);
|
||||||
|
|
||||||
dbProtocolMappers.add(dbMapper);
|
dbProtocolMappers.add(dbMapper);
|
||||||
|
|||||||
+63
@@ -0,0 +1,63 @@
|
|||||||
|
package org.keycloak.connections.mongo.updater.impl.updates;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.mongodb.BasicDBList;
|
||||||
|
import com.mongodb.BasicDBObject;
|
||||||
|
import com.mongodb.DBCollection;
|
||||||
|
import com.mongodb.DBCursor;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
*/
|
||||||
|
public class Update1_4_0 extends Update {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return "1.4.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(KeycloakSession session) throws ClassNotFoundException {
|
||||||
|
deleteEntries("clientSessions");
|
||||||
|
deleteEntries("sessions");
|
||||||
|
|
||||||
|
// Remove warning
|
||||||
|
removeField("realms", "authenticators");
|
||||||
|
|
||||||
|
updateUserAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateUserAttributes() {
|
||||||
|
DBCollection users = db.getCollection("users");
|
||||||
|
DBCursor usersCursor = users.find();
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (usersCursor.hasNext()) {
|
||||||
|
BasicDBObject user = (BasicDBObject) usersCursor.next();
|
||||||
|
|
||||||
|
BasicDBObject attributes = (BasicDBObject) user.get("attributes");
|
||||||
|
if (attributes != null) {
|
||||||
|
for (Map.Entry<String, Object> attr : new HashSet<>(attributes.entrySet())) {
|
||||||
|
String attrName = attr.getKey();
|
||||||
|
Object attrValue = attr.getValue();
|
||||||
|
if (attrValue != null && attrValue instanceof String) {
|
||||||
|
BasicDBList asList = new BasicDBList();
|
||||||
|
asList.add(attrValue);
|
||||||
|
attributes.put(attrName, asList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user.put("attributes", attributes);
|
||||||
|
|
||||||
|
users.save(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
usersCursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.3.0.Final-SNAPSHOT</version>
|
<version>1.6.1.Final</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
+52
-9
@@ -3,8 +3,10 @@ package org.keycloak.connections.mongo;
|
|||||||
import com.mongodb.DB;
|
import com.mongodb.DB;
|
||||||
import com.mongodb.MongoClient;
|
import com.mongodb.MongoClient;
|
||||||
import com.mongodb.MongoClientOptions;
|
import com.mongodb.MongoClientOptions;
|
||||||
|
import com.mongodb.MongoClientURI;
|
||||||
import com.mongodb.MongoCredential;
|
import com.mongodb.MongoCredential;
|
||||||
import com.mongodb.ServerAddress;
|
import com.mongodb.ServerAddress;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
import org.keycloak.connections.mongo.api.MongoStore;
|
import org.keycloak.connections.mongo.api.MongoStore;
|
||||||
@@ -18,35 +20,39 @@ import javax.net.ssl.SSLSocketFactory;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
||||||
|
|
||||||
// TODO Make configurable
|
// TODO Make it dynamic
|
||||||
private String[] entities = new String[]{
|
private String[] entities = new String[]{
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity",
|
"org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity",
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoUserEntity",
|
"org.keycloak.models.mongo.keycloak.entities.MongoUserEntity",
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity",
|
"org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity",
|
||||||
|
"org.keycloak.models.mongo.keycloak.entities.MongoClientEntity",
|
||||||
|
"org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity",
|
||||||
|
"org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
|
||||||
|
"org.keycloak.models.mongo.keycloak.entities.MongoOnlineUserSessionEntity",
|
||||||
|
"org.keycloak.models.mongo.keycloak.entities.MongoOfflineUserSessionEntity",
|
||||||
"org.keycloak.models.entities.IdentityProviderEntity",
|
"org.keycloak.models.entities.IdentityProviderEntity",
|
||||||
"org.keycloak.models.entities.ClientIdentityProviderMappingEntity",
|
"org.keycloak.models.entities.ClientIdentityProviderMappingEntity",
|
||||||
"org.keycloak.models.entities.RequiredCredentialEntity",
|
"org.keycloak.models.entities.RequiredCredentialEntity",
|
||||||
"org.keycloak.models.entities.CredentialEntity",
|
"org.keycloak.models.entities.CredentialEntity",
|
||||||
"org.keycloak.models.entities.FederatedIdentityEntity",
|
"org.keycloak.models.entities.FederatedIdentityEntity",
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoClientEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoUsernameLoginFailureEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoUserSessionEntity",
|
|
||||||
"org.keycloak.models.sessions.mongo.entities.MongoClientSessionEntity",
|
|
||||||
"org.keycloak.models.entities.UserFederationProviderEntity",
|
"org.keycloak.models.entities.UserFederationProviderEntity",
|
||||||
"org.keycloak.models.entities.UserFederationMapperEntity",
|
"org.keycloak.models.entities.UserFederationMapperEntity",
|
||||||
"org.keycloak.models.entities.ProtocolMapperEntity",
|
"org.keycloak.models.entities.ProtocolMapperEntity",
|
||||||
"org.keycloak.models.entities.IdentityProviderMapperEntity",
|
"org.keycloak.models.entities.IdentityProviderMapperEntity",
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity",
|
|
||||||
"org.keycloak.models.mongo.keycloak.entities.MongoMigrationModelEntity",
|
|
||||||
"org.keycloak.models.entities.AuthenticationExecutionEntity",
|
"org.keycloak.models.entities.AuthenticationExecutionEntity",
|
||||||
"org.keycloak.models.entities.AuthenticationFlowEntity",
|
"org.keycloak.models.entities.AuthenticationFlowEntity",
|
||||||
"org.keycloak.models.entities.AuthenticatorEntity",
|
"org.keycloak.models.entities.AuthenticatorConfigEntity",
|
||||||
|
"org.keycloak.models.entities.RequiredActionProviderEntity",
|
||||||
|
"org.keycloak.models.entities.PersistentUserSessionEntity",
|
||||||
|
"org.keycloak.models.entities.PersistentClientSessionEntity",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
|
private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
|
||||||
@@ -57,6 +63,8 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
|
|||||||
private DB db;
|
private DB db;
|
||||||
protected Config.Scope config;
|
protected Config.Scope config;
|
||||||
|
|
||||||
|
private Map<String,String> operationalInfo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MongoConnectionProvider create(KeycloakSession session) {
|
public MongoConnectionProvider create(KeycloakSession session) {
|
||||||
lazyInit(session);
|
lazyInit(session);
|
||||||
@@ -142,9 +150,33 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
|
|||||||
* @throws UnknownHostException
|
* @throws UnknownHostException
|
||||||
*/
|
*/
|
||||||
protected MongoClient createMongoClient() throws UnknownHostException {
|
protected MongoClient createMongoClient() throws UnknownHostException {
|
||||||
|
operationalInfo = new LinkedHashMap<>();
|
||||||
|
String dbName = config.get("db", "keycloak");
|
||||||
|
|
||||||
|
String uriString = config.get("uri");
|
||||||
|
if (uriString != null) {
|
||||||
|
MongoClientURI uri = new MongoClientURI(uriString);
|
||||||
|
MongoClient client = new MongoClient(uri);
|
||||||
|
|
||||||
|
StringBuilder hostsBuilder = new StringBuilder();
|
||||||
|
for (int i=0 ; i<uri.getHosts().size() ; i++) {
|
||||||
|
if (i!=0) {
|
||||||
|
hostsBuilder.append(", ");
|
||||||
|
}
|
||||||
|
hostsBuilder.append(uri.getHosts().get(i));
|
||||||
|
}
|
||||||
|
String hosts = hostsBuilder.toString();
|
||||||
|
|
||||||
|
operationalInfo.put("mongoHosts", hosts);
|
||||||
|
operationalInfo.put("mongoDatabaseName", dbName);
|
||||||
|
operationalInfo.put("mongoUser", uri.getUsername());
|
||||||
|
operationalInfo.put("mongoDriverVersion", client.getVersion());
|
||||||
|
|
||||||
|
logger.debugv("Initialized mongo model. host(s): %s, db: %s", uri.getHosts(), dbName);
|
||||||
|
return client;
|
||||||
|
} else {
|
||||||
String host = config.get("host", ServerAddress.defaultHost());
|
String host = config.get("host", ServerAddress.defaultHost());
|
||||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||||
String dbName = config.get("db", "keycloak");
|
|
||||||
|
|
||||||
String user = config.get("user");
|
String user = config.get("user");
|
||||||
String password = config.get("password");
|
String password = config.get("password");
|
||||||
@@ -159,9 +191,15 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
|
|||||||
client = new MongoClient(new ServerAddress(host, port), clientOptions);
|
client = new MongoClient(new ServerAddress(host, port), clientOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operationalInfo.put("mongoServerAddress", client.getAddress().toString());
|
||||||
|
operationalInfo.put("mongoDatabaseName", dbName);
|
||||||
|
operationalInfo.put("mongoUser", user);
|
||||||
|
operationalInfo.put("mongoDriverVersion", client.getVersion());
|
||||||
|
|
||||||
logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
|
logger.debugv("Initialized mongo model. host: %s, port: %d, db: %s", host, port, dbName);
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected MongoClientOptions getClientOptions() {
|
protected MongoClientOptions getClientOptions() {
|
||||||
MongoClientOptions.Builder builder = MongoClientOptions.builder();
|
MongoClientOptions.Builder builder = MongoClientOptions.builder();
|
||||||
@@ -206,4 +244,9 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String,String> getOperationalInfo() {
|
||||||
|
return operationalInfo;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
package org.keycloak.connections.mongo;
|
package org.keycloak.connections.mongo;
|
||||||
|
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ServerInfoAwareProviderFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public interface MongoConnectionProviderFactory extends ProviderFactory<MongoConnectionProvider> {
|
public interface MongoConnectionProviderFactory extends ServerInfoAwareProviderFactory<MongoConnectionProvider> {
|
||||||
}
|
}
|
||||||
Loaded 100 of 3651 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user