Compare commits
591
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
No files matched your search
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.keycloak.broker.provider;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -43,6 +44,7 @@ public class BrokeredIdentityContext {
|
||||
private IdentityProviderModel idpConfig;
|
||||
private IdentityProvider idp;
|
||||
private Map<String, Object> contextData = new HashMap<>();
|
||||
private ClientSessionModel clientSession;
|
||||
|
||||
public BrokeredIdentityContext(String id) {
|
||||
if (id == null) {
|
||||
@@ -166,6 +168,14 @@ public class BrokeredIdentityContext {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public ClientSessionModel getClientSession() {
|
||||
return clientSession;
|
||||
}
|
||||
|
||||
public void setClientSession(ClientSessionModel clientSession) {
|
||||
this.clientSession = clientSession;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
if (name != null) {
|
||||
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.";
|
||||
}
|
||||
}
|
||||
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.";
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -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>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<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.map.ObjectMapper;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.broker.provider.util.SimpleHttp;
|
||||
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.RealmsResource;
|
||||
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.Path;
|
||||
@@ -289,10 +289,9 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
||||
}
|
||||
JsonWebToken token = jws.readJsonContent(JsonWebToken.class);
|
||||
|
||||
String aud = token.getAudience();
|
||||
String iss = token.getIssuer();
|
||||
|
||||
if (aud != null && !aud.equals(getConfig().getClientId())) {
|
||||
if (!token.hasAudience(getConfig().getClientId())) {
|
||||
throw new IdentityBrokerException("Wrong audience from token.");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.keycloak.broker.saml;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.VerificationException;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.broker.provider.BrokeredIdentityContext;
|
||||
import org.keycloak.broker.provider.IdentityBrokerException;
|
||||
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.AttributeType;
|
||||
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.SubjectType;
|
||||
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.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.saml.SAML2LogoutResponseBuilder;
|
||||
import org.keycloak.protocol.saml.SAMLRequestParser;
|
||||
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
|
||||
import org.keycloak.saml.SAML2LogoutResponseBuilder;
|
||||
import org.keycloak.saml.SAMLRequestParser;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
import org.keycloak.protocol.saml.SamlProtocolUtils;
|
||||
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.exceptions.ConfigurationException;
|
||||
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.constants.X500SAMLProfileConstants;
|
||||
import org.keycloak.saml.processing.core.util.JAXPValidationUtil;
|
||||
import org.keycloak.saml.processing.core.util.XMLEncryptionUtil;
|
||||
import org.keycloak.saml.processing.core.saml.v2.util.AssertionUtil;
|
||||
import org.keycloak.saml.processing.core.util.XMLSignatureUtil;
|
||||
import org.keycloak.saml.processing.web.util.PostBindingUtil;
|
||||
import org.keycloak.services.ErrorPage;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
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.FormParam;
|
||||
@@ -61,9 +52,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import javax.xml.namespace.QName;
|
||||
import java.io.IOException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.List;
|
||||
@@ -155,7 +144,7 @@ public class SAMLEndpoint {
|
||||
}
|
||||
|
||||
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 extractResponseDocument(String response);
|
||||
protected PublicKey getIDPKey() {
|
||||
@@ -188,7 +177,7 @@ public class SAMLEndpoint {
|
||||
}
|
||||
if (config.isValidateSignature()) {
|
||||
try {
|
||||
verifySignature(holder);
|
||||
verifySignature(GeneralConstants.SAML_REQUEST_KEY, holder);
|
||||
} catch (VerificationException e) {
|
||||
logger.error("validation failed", e);
|
||||
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
||||
@@ -247,16 +236,18 @@ public class SAMLEndpoint {
|
||||
builder.logoutRequestID(request.getID());
|
||||
builder.destination(config.getSingleLogoutServiceUrl());
|
||||
builder.issuer(issuerURL);
|
||||
builder.relayState(relayState);
|
||||
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||
.relayState(relayState);
|
||||
if (config.isWantAuthnRequestsSigned()) {
|
||||
builder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||
binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||
.signatureAlgorithm(provider.getSignatureAlgorithm())
|
||||
.signDocument();
|
||||
}
|
||||
try {
|
||||
if (config.isPostBindingResponse()) {
|
||||
return builder.postBinding().response();
|
||||
return binding.postBinding(builder.buildDocument()).response(config.getSingleLogoutServiceUrl());
|
||||
} else {
|
||||
return builder.redirectBinding().response();
|
||||
return binding.redirectBinding(builder.buildDocument()).response(config.getSingleLogoutServiceUrl());
|
||||
}
|
||||
} catch (ConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -274,7 +265,7 @@ public class SAMLEndpoint {
|
||||
protected Response handleLoginResponse(String samlResponse, SAMLDocumentHolder holder, ResponseType responseType, String relayState) {
|
||||
|
||||
try {
|
||||
AssertionType assertion = getAssertion(responseType);
|
||||
AssertionType assertion = AssertionUtil.getAssertion(responseType, realm.getPrivateKey());
|
||||
SubjectType subject = assertion.getSubject();
|
||||
SubjectType.STSubType subType = subject.getSubType();
|
||||
NameIDType subjectNameID = (NameIDType) subType.getBaseID();
|
||||
@@ -334,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) {
|
||||
SAMLDocumentHolder holder = extractResponseDocument(samlResponse);
|
||||
@@ -363,7 +338,7 @@ public class SAMLEndpoint {
|
||||
}
|
||||
if (config.isValidateSignature()) {
|
||||
try {
|
||||
verifySignature(holder);
|
||||
verifySignature(GeneralConstants.SAML_RESPONSE_KEY, holder);
|
||||
} catch (VerificationException e) {
|
||||
logger.error("validation failed", e);
|
||||
event.event(EventType.IDENTITY_PROVIDER_RESPONSE);
|
||||
@@ -406,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 {
|
||||
@Override
|
||||
protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||
protected void verifySignature(String key, SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||
SamlProtocolUtils.verifyDocumentSignature(documentHolder.getSamlDocument(), getIDPKey());
|
||||
}
|
||||
|
||||
@@ -465,9 +411,9 @@ public class SAMLEndpoint {
|
||||
|
||||
protected class RedirectBinding extends Binding {
|
||||
@Override
|
||||
protected void verifySignature(SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||
protected void verifySignature(String key, SAMLDocumentHolder documentHolder) throws VerificationException {
|
||||
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.RealmModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.saml.SAML2AuthnRequestBuilder;
|
||||
import org.keycloak.protocol.saml.SAML2LogoutRequestBuilder;
|
||||
import org.keycloak.protocol.saml.SAML2NameIDPolicyBuilder;
|
||||
import org.keycloak.protocol.saml.JaxrsSAML2BindingBuilder;
|
||||
import org.keycloak.saml.SAML2AuthnRequestBuilder;
|
||||
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.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.Response;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
@@ -92,7 +90,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
.issuer(issuerURL)
|
||||
.forceAuthn(getConfig().isForceAuthn())
|
||||
.protocolBinding(protocolBinding)
|
||||
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat))
|
||||
.nameIdPolicy(SAML2NameIDPolicyBuilder.format(nameIDPolicyFormat));
|
||||
JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder()
|
||||
.relayState(request.getState());
|
||||
|
||||
if (getConfig().isWantAuthnRequestsSigned()) {
|
||||
@@ -109,14 +108,15 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
|
||||
KeyPair keypair = new KeyPair(publicKey, privateKey);
|
||||
|
||||
authnRequestBuilder.signWith(keypair);
|
||||
authnRequestBuilder.signDocument();
|
||||
binding.signWith(keypair);
|
||||
binding.signatureAlgorithm(getSignatureAlgorithm());
|
||||
binding.signDocument();
|
||||
}
|
||||
|
||||
if (getConfig().isPostBindingAuthnRequest()) {
|
||||
return authnRequestBuilder.postBinding().request();
|
||||
return binding.postBinding(authnRequestBuilder.toDocument()).request(destinationUrl);
|
||||
} else {
|
||||
return authnRequestBuilder.redirectBinding().request();
|
||||
return binding.redirectBinding(authnRequestBuilder.toDocument()).request(destinationUrl);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IdentityBrokerException("Could not create authentication request.", e);
|
||||
@@ -153,9 +153,10 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
String singleLogoutServiceUrl = getConfig().getSingleLogoutServiceUrl();
|
||||
if (singleLogoutServiceUrl == null || singleLogoutServiceUrl.trim().equals("") || !getConfig().isBackchannelSupported()) return;
|
||||
SAML2LogoutRequestBuilder logoutBuilder = buildLogoutRequest(userSession, uriInfo, realm, singleLogoutServiceUrl);
|
||||
JaxrsSAML2BindingBuilder binding = buildLogoutBinding(userSession, realm);
|
||||
try {
|
||||
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();
|
||||
boolean success = status >=200 && status < 400;
|
||||
if (!success) {
|
||||
@@ -178,7 +179,8 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
} else {
|
||||
try {
|
||||
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) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -192,13 +194,19 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
.issuer(getEntityId(uriInfo, realm))
|
||||
.sessionIndex(userSession.getNote(SAMLEndpoint.SAML_FEDERATED_SESSION_INDEX))
|
||||
.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());
|
||||
if (getConfig().isWantAuthnRequestsSigned()) {
|
||||
logoutBuilder.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||
binding.signWith(realm.getPrivateKey(), realm.getPublicKey(), realm.getCertificate())
|
||||
.signatureAlgorithm(getSignatureAlgorithm())
|
||||
.signDocument();
|
||||
}
|
||||
return logoutBuilder;
|
||||
return binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -220,7 +228,7 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
|
||||
|
||||
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" +
|
||||
" 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" +
|
||||
@@ -245,4 +253,14 @@ public class SAMLIdentityProvider extends AbstractIdentityProvider<SAMLIdentityP
|
||||
"</EntityDescriptor>\n";
|
||||
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));
|
||||
}
|
||||
|
||||
public String getSignatureAlgorithm() {
|
||||
return getConfig().get("signatureAlgorithm");
|
||||
}
|
||||
|
||||
public void setSignatureAlgorithm(String signatureAlgorithm) {
|
||||
getConfig().put("signatureAlgorithm", signatureAlgorithm);
|
||||
}
|
||||
|
||||
public String getEncryptionPublicKey() {
|
||||
return getConfig().get("encryptionPublicKey");
|
||||
}
|
||||
|
||||
+69
-65
@@ -73,75 +73,79 @@ public class SAMLIdentityProviderFactory extends AbstractIdentityProviderFactory
|
||||
List<EntityDescriptorType.EDTChoiceType> choiceType = entityType.getChoiceType();
|
||||
|
||||
if (!choiceType.isEmpty()) {
|
||||
EntityDescriptorType.EDTChoiceType edtChoiceType = choiceType.get(0);
|
||||
List<EntityDescriptorType.EDTDescriptorChoiceType> descriptors = edtChoiceType.getDescriptors();
|
||||
IDPSSODescriptorType idpDescriptor = null;
|
||||
|
||||
if (!descriptors.isEmpty()) {
|
||||
EntityDescriptorType.EDTDescriptorChoiceType edtDescriptorChoiceType = descriptors.get(0);
|
||||
IDPSSODescriptorType idpDescriptor = edtDescriptorChoiceType.getIdpDescriptor();
|
||||
//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();
|
||||
|
||||
if (idpDescriptor != null) {
|
||||
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
||||
String singleSignOnServiceUrl = null;
|
||||
boolean postBinding = false;
|
||||
for (EndpointType endpoint : idpDescriptor.getSingleSignOnService()) {
|
||||
if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||
postBinding = true;
|
||||
break;
|
||||
} else if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||
}
|
||||
}
|
||||
String singleLogoutServiceUrl = null;
|
||||
for (EndpointType endpoint : idpDescriptor.getSingleLogoutService()) {
|
||||
if (postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||
break;
|
||||
} else if (!postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
samlIdentityProviderConfig.setSingleLogoutServiceUrl(singleLogoutServiceUrl);
|
||||
samlIdentityProviderConfig.setSingleSignOnServiceUrl(singleSignOnServiceUrl);
|
||||
samlIdentityProviderConfig.setWantAuthnRequestsSigned(idpDescriptor.isWantAuthnRequestsSigned());
|
||||
samlIdentityProviderConfig.setValidateSignature(idpDescriptor.isWantAuthnRequestsSigned());
|
||||
samlIdentityProviderConfig.setPostBindingResponse(postBinding);
|
||||
samlIdentityProviderConfig.setPostBindingAuthnRequest(postBinding);
|
||||
|
||||
List<KeyDescriptorType> keyDescriptor = idpDescriptor.getKeyDescriptor();
|
||||
String defaultCertificate = null;
|
||||
|
||||
if (keyDescriptor != null) {
|
||||
for (KeyDescriptorType keyDescriptorType : keyDescriptor) {
|
||||
Element keyInfo = keyDescriptorType.getKeyInfo();
|
||||
Element x509KeyInfo = DocumentUtil.getChildElement(keyInfo, new QName("dsig", "X509Certificate"));
|
||||
|
||||
if (KeyTypes.SIGNING.equals(keyDescriptorType.getUse())) {
|
||||
samlIdentityProviderConfig.setSigningCertificate(x509KeyInfo.getTextContent());
|
||||
} else if (KeyTypes.ENCRYPTION.equals(keyDescriptorType.getUse())) {
|
||||
samlIdentityProviderConfig.setEncryptionPublicKey(x509KeyInfo.getTextContent());
|
||||
} else if (keyDescriptorType.getUse() == null) {
|
||||
defaultCertificate = x509KeyInfo.getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultCertificate != null) {
|
||||
if (samlIdentityProviderConfig.getSigningCertificate() == null) {
|
||||
samlIdentityProviderConfig.setSigningCertificate(defaultCertificate);
|
||||
}
|
||||
|
||||
if (samlIdentityProviderConfig.getEncryptionPublicKey() == null) {
|
||||
samlIdentityProviderConfig.setEncryptionPublicKey(defaultCertificate);
|
||||
}
|
||||
}
|
||||
|
||||
return samlIdentityProviderConfig.getConfig();
|
||||
if(!descriptors.isEmpty() && descriptors.get(0).getIdpDescriptor() != null) {
|
||||
idpDescriptor = descriptors.get(0).getIdpDescriptor();
|
||||
}
|
||||
}
|
||||
|
||||
if (idpDescriptor != null) {
|
||||
SAMLIdentityProviderConfig samlIdentityProviderConfig = new SAMLIdentityProviderConfig();
|
||||
String singleSignOnServiceUrl = null;
|
||||
boolean postBinding = false;
|
||||
for (EndpointType endpoint : idpDescriptor.getSingleSignOnService()) {
|
||||
if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||
postBinding = true;
|
||||
break;
|
||||
} else if (endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||
singleSignOnServiceUrl = endpoint.getLocation().toString();
|
||||
}
|
||||
}
|
||||
String singleLogoutServiceUrl = null;
|
||||
for (EndpointType endpoint : idpDescriptor.getSingleLogoutService()) {
|
||||
if (postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_POST_BINDING.get())) {
|
||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||
break;
|
||||
} else if (!postBinding && endpoint.getBinding().toString().equals(JBossSAMLURIConstants.SAML_HTTP_REDIRECT_BINDING.get())){
|
||||
singleLogoutServiceUrl = endpoint.getLocation().toString();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
samlIdentityProviderConfig.setSingleLogoutServiceUrl(singleLogoutServiceUrl);
|
||||
samlIdentityProviderConfig.setSingleSignOnServiceUrl(singleSignOnServiceUrl);
|
||||
samlIdentityProviderConfig.setWantAuthnRequestsSigned(idpDescriptor.isWantAuthnRequestsSigned());
|
||||
samlIdentityProviderConfig.setValidateSignature(idpDescriptor.isWantAuthnRequestsSigned());
|
||||
samlIdentityProviderConfig.setPostBindingResponse(postBinding);
|
||||
samlIdentityProviderConfig.setPostBindingAuthnRequest(postBinding);
|
||||
|
||||
List<KeyDescriptorType> keyDescriptor = idpDescriptor.getKeyDescriptor();
|
||||
String defaultCertificate = null;
|
||||
|
||||
if (keyDescriptor != null) {
|
||||
for (KeyDescriptorType keyDescriptorType : keyDescriptor) {
|
||||
Element keyInfo = keyDescriptorType.getKeyInfo();
|
||||
Element x509KeyInfo = DocumentUtil.getChildElement(keyInfo, new QName("dsig", "X509Certificate"));
|
||||
|
||||
if (KeyTypes.SIGNING.equals(keyDescriptorType.getUse())) {
|
||||
samlIdentityProviderConfig.setSigningCertificate(x509KeyInfo.getTextContent());
|
||||
} else if (KeyTypes.ENCRYPTION.equals(keyDescriptorType.getUse())) {
|
||||
samlIdentityProviderConfig.setEncryptionPublicKey(x509KeyInfo.getTextContent());
|
||||
} else if (keyDescriptorType.getUse() == null) {
|
||||
defaultCertificate = x509KeyInfo.getTextContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultCertificate != null) {
|
||||
if (samlIdentityProviderConfig.getSigningCertificate() == null) {
|
||||
samlIdentityProviderConfig.setSigningCertificate(defaultCertificate);
|
||||
}
|
||||
|
||||
if (samlIdentityProviderConfig.getEncryptionPublicKey() == null) {
|
||||
samlIdentityProviderConfig.setEncryptionPublicKey(defaultCertificate);
|
||||
}
|
||||
}
|
||||
|
||||
return samlIdentityProviderConfig.getConfig();
|
||||
}
|
||||
}
|
||||
} catch (ParsingException pe) {
|
||||
throw new RuntimeException("Could not parse IdP SAML Metadata", pe);
|
||||
|
||||
@@ -98,7 +98,7 @@ public class UserAttributeMapper extends AbstractIdentityProviderMapper {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
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();
|
||||
if (attributeValue == null || attributeValue.isEmpty()) return null;
|
||||
|
||||
@@ -4,25 +4,27 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
<version>1.6.1.Final</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-model-sessions-mem</artifactId>
|
||||
<name>Keycloak Model Sessions Mem</name>
|
||||
<artifactId>keycloak-client-api</artifactId>
|
||||
<name>Keycloak Client API</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</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
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak;
|
||||
package org.keycloak.common;
|
||||
|
||||
/**
|
||||
* @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>
|
||||
+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>
|
||||
+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>
|
||||
+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>
|
||||
+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.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>
|
||||
* @version $Revision: 1 $
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
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.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Calendar;
|
||||
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.Iterator;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
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.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.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.FileNotFoundException;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
/**
|
||||
* @author pedroigor
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@@ -12,13 +12,12 @@ import java.lang.reflect.Method;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
|
||||
import net.iharder.Base64;
|
||||
import org.ietf.jgss.GSSCredential;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.GSSManager;
|
||||
import org.ietf.jgss.Oid;
|
||||
import org.keycloak.constants.KerberosConstants;
|
||||
import org.keycloak.util.reflections.Reflections;
|
||||
import org.keycloak.common.constants.KerberosConstants;
|
||||
import org.keycloak.common.util.reflections.Reflections;
|
||||
import sun.security.jgss.GSSCredentialImpl;
|
||||
import sun.security.jgss.GSSManagerImpl;
|
||||
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;
|
||||
@@ -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 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.Collection;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
/*
|
||||
* 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>
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
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.DataInputStream;
|
||||
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.text.DateFormat;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 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.util.Properties;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util;
|
||||
package org.keycloak.common.util;
|
||||
|
||||
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.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.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.security.PrivilegedAction;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.util.reflections;
|
||||
package org.keycloak.common.util.reflections;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
version=${product.version}
|
||||
build-time=${product.build-time}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+2
-2
@@ -12,8 +12,8 @@ import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.util.EnvUtil;
|
||||
import org.keycloak.util.KeystoreUtil;
|
||||
import org.keycloak.common.util.EnvUtil;
|
||||
import org.keycloak.common.util.KeystoreUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -27,5 +27,6 @@
|
||||
<artifactId>infinispan-core</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</project>
|
||||
+13
@@ -66,6 +66,19 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
|
||||
} else {
|
||||
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 USER_CACHE_NAME = "users";
|
||||
static final String SESSION_CACHE_NAME = "sessions";
|
||||
static final String OFFLINE_SESSION_CACHE_NAME = "offlineSessions";
|
||||
static final String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
|
||||
|
||||
<K, V> Cache<K, V> getCache(String name);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+1
-1
@@ -231,7 +231,7 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
|
||||
|
||||
}
|
||||
|
||||
private String getTable(String table, String defaultSchema) {
|
||||
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.structure.core.Schema;
|
||||
import liquibase.structure.core.Table;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -36,7 +37,7 @@ public class AddRealmCodeSecret implements CustomSqlChange {
|
||||
|
||||
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
||||
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()) {
|
||||
String id = resultSet.getString(1);
|
||||
|
||||
|
||||
+7
-1
@@ -16,6 +16,7 @@ import liquibase.snapshot.SnapshotGeneratorFactory;
|
||||
import liquibase.statement.SqlStatement;
|
||||
import liquibase.structure.core.Table;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.ThreadLocalSessionContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||
@@ -88,7 +89,7 @@ public abstract class CustomKeycloakTask implements CustomSqlChange {
|
||||
try {
|
||||
String correctedTableName = database.correctObjectName("REALM", Table.class);
|
||||
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 {
|
||||
return (resultSet.next());
|
||||
} finally {
|
||||
@@ -108,4 +109,9 @@ public abstract class CustomKeycloakTask implements CustomSqlChange {
|
||||
protected abstract void generateStatementsImpl() throws CustomChangeException;
|
||||
|
||||
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.structure.core.Table;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||
import org.keycloak.migration.MigrationProvider;
|
||||
import org.keycloak.models.AdminRoles;
|
||||
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 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 {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
@@ -124,7 +128,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
|
||||
protected void convertSocialToIdFedUsers() throws SQLException, DatabaseException {
|
||||
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 {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
@@ -170,7 +174,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
String adminRoleId = getAdminRoleId();
|
||||
String masterRealmId = Config.getAdminRealm();
|
||||
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME from REALM");
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME from " + getTableName("REALM"));
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
try {
|
||||
@@ -178,7 +182,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
String realmName = resultSet.getString("NAME");
|
||||
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(2, masterAdminAppName);
|
||||
|
||||
@@ -209,7 +213,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
}
|
||||
|
||||
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(2, Config.getAdminRealm());
|
||||
|
||||
@@ -231,7 +235,8 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
|
||||
|
||||
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);
|
||||
|
||||
try {
|
||||
@@ -280,7 +285,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
String protocolMapperTableName = database.correctObjectName("PROTOCOL_MAPPER", 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 {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
@@ -293,7 +298,7 @@ public class JpaUpdate1_2_0_Beta1 extends CustomKeycloakTask {
|
||||
}
|
||||
|
||||
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);
|
||||
List<ProtocolMapperRepresentation> protocolMappers = migrationProvider.getMappersForClaimMask(mask);
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ public class JpaUpdate1_2_0_CR1 extends CustomKeycloakTask {
|
||||
|
||||
try {
|
||||
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 {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ public class JpaUpdate1_4_0_Final extends CustomKeycloakTask {
|
||||
String userAttributeTableName = database.correctObjectName("USER_ATTRIBUTE", Table.class);
|
||||
|
||||
try {
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME, USER_ID from USER_ATTRIBUTE");
|
||||
PreparedStatement statement = jdbcConnection.prepareStatement("select NAME, USER_ID from " + getTableName("USER_ATTRIBUTE"));
|
||||
|
||||
try {
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
+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>
|
||||
@@ -8,4 +8,6 @@
|
||||
<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.4.0.xml"/>
|
||||
<include file="META-INF/jpa-changelog-1.5.0.xml"/>
|
||||
<include file="META-INF/jpa-changelog-1.6.1.xml"/>
|
||||
</databaseChangeLog>
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -24,7 +24,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.1-api</artifactId>
|
||||
<artifactId>${hibernate.javax.persistence.artifactId}</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import org.hibernate.ejb.AvailableSettings;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
|
||||
import org.keycloak.connections.jpa.util.JpaUtils;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
@@ -108,7 +109,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
|
||||
|
||||
String schema = config.get("schema");
|
||||
if (schema != null) {
|
||||
properties.put("hibernate.default_schema", schema);
|
||||
properties.put(JpaUtils.HIBERNATE_DEFAULT_SCHEMA, schema);
|
||||
}
|
||||
|
||||
if (databaseSchema != null) {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ public interface JpaUpdaterProvider extends Provider {
|
||||
|
||||
public String FIRST_VERSION = "1.0.0.Final";
|
||||
|
||||
public String LAST_VERSION = "1.4.0";
|
||||
public String LAST_VERSION = "1.6.1";
|
||||
|
||||
public String getCurrentVersionSql(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;
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,8 @@
|
||||
<class>org.keycloak.models.jpa.entities.AuthenticationExecutionEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.AuthenticatorConfigEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RequiredActionProviderEntity</class>
|
||||
|
||||
<!-- JpaUserSessionProvider -->
|
||||
<class>org.keycloak.models.sessions.jpa.entities.ClientSessionEntity</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.ClientUserSessionNoteEntity</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>
|
||||
<class>org.keycloak.models.jpa.session.PersistentUserSessionEntity</class>
|
||||
<class>org.keycloak.models.jpa.session.PersistentClientSessionEntity</class>
|
||||
|
||||
<!-- JpaAuditProviders -->
|
||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+52
-26
@@ -3,6 +3,7 @@ package org.keycloak.connections.mongo;
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoClientOptions;
|
||||
import com.mongodb.MongoClientURI;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
|
||||
@@ -27,30 +28,31 @@ import java.util.Map;
|
||||
*/
|
||||
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
||||
|
||||
// TODO Make configurable
|
||||
// TODO Make it dynamic
|
||||
private String[] entities = new String[]{
|
||||
"org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity",
|
||||
"org.keycloak.models.mongo.keycloak.entities.MongoUserEntity",
|
||||
"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.ClientIdentityProviderMappingEntity",
|
||||
"org.keycloak.models.entities.RequiredCredentialEntity",
|
||||
"org.keycloak.models.entities.CredentialEntity",
|
||||
"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.UserFederationMapperEntity",
|
||||
"org.keycloak.models.entities.ProtocolMapperEntity",
|
||||
"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.AuthenticationFlowEntity",
|
||||
"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);
|
||||
@@ -148,31 +150,55 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
protected MongoClient createMongoClient() throws UnknownHostException {
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
operationalInfo = new LinkedHashMap<>();
|
||||
String dbName = config.get("db", "keycloak");
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
String uriString = config.get("uri");
|
||||
if (uriString != null) {
|
||||
MongoClientURI uri = new MongoClientURI(uriString);
|
||||
MongoClient client = new MongoClient(uri);
|
||||
|
||||
MongoClientOptions clientOptions = getClientOptions();
|
||||
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();
|
||||
|
||||
MongoClient client;
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential), clientOptions);
|
||||
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 {
|
||||
client = new MongoClient(new ServerAddress(host, port), clientOptions);
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
|
||||
MongoClientOptions clientOptions = getClientOptions();
|
||||
|
||||
MongoClient client;
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential), clientOptions);
|
||||
} else {
|
||||
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);
|
||||
return client;
|
||||
}
|
||||
|
||||
operationalInfo = new LinkedHashMap<>();
|
||||
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);
|
||||
return client;
|
||||
}
|
||||
|
||||
protected MongoClientOptions getClientOptions() {
|
||||
|
||||
+1
-2
@@ -9,11 +9,10 @@ import org.keycloak.connections.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.connections.mongo.impl.EntityInfo;
|
||||
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.utils.reflection.Property;
|
||||
import org.keycloak.util.reflections.Types;
|
||||
import org.keycloak.common.util.reflections.Types;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
</parent>
|
||||
<name>Connections Parent</name>
|
||||
<description/>
|
||||
|
||||
+5
-11
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.4.0.Final-SNAPSHOT</version>
|
||||
<version>1.6.1.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -21,35 +21,29 @@
|
||||
org.keycloak.*
|
||||
</keycloak.osgi.export>
|
||||
<keycloak.osgi.import>
|
||||
net.iharder;version=${base64.version},
|
||||
*;resolution:=optional
|
||||
</keycloak.osgi.import>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.iharder</groupId>
|
||||
<artifactId>base64</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-core-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jackson</groupId>
|
||||
<artifactId>jackson-mapper-asl</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.keycloak;
|
||||
|
||||
import org.keycloak.enums.RelativeUrlsUsed;
|
||||
import org.keycloak.util.KeycloakUriBuilder;
|
||||
import org.keycloak.common.enums.RelativeUrlsUsed;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -16,7 +16,7 @@ public class AbstractOAuthClient {
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
|
||||
protected String clientId;
|
||||
protected Map<String, String> credentials;
|
||||
protected Map<String, Object> credentials;
|
||||
protected String authUrl;
|
||||
protected String tokenUrl;
|
||||
protected RelativeUrlsUsed relativeUrlsUsed;
|
||||
@@ -37,11 +37,11 @@ public class AbstractOAuthClient {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public Map<String, String> getCredentials() {
|
||||
public Map<String, Object> getCredentials() {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
public void setCredentials(Map<String, String> credentials) {
|
||||
public void setCredentials(Map<String, Object> credentials) {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.keycloak;
|
||||
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -31,6 +31,19 @@ public interface OAuth2Constants {
|
||||
|
||||
String CLIENT_CREDENTIALS = "client_credentials";
|
||||
|
||||
// https://tools.ietf.org/html/draft-ietf-oauth-assertions-01#page-5
|
||||
String CLIENT_ASSERTION_TYPE = "client_assertion_type";
|
||||
String CLIENT_ASSERTION = "client_assertion";
|
||||
|
||||
// https://tools.ietf.org/html/draft-jones-oauth-jwt-bearer-03#section-2.2
|
||||
String CLIENT_ASSERTION_TYPE_JWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer";
|
||||
|
||||
// http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
||||
String OFFLINE_ACCESS = "offline_access";
|
||||
|
||||
String UI_LOCALES_PARAM = "ui_locales";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.keycloak;
|
||||
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
@@ -13,10 +15,10 @@ import java.security.PublicKey;
|
||||
*/
|
||||
public class RSATokenVerifier {
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl) throws VerificationException {
|
||||
return verifyToken(tokenString, realmKey, realmUrl, true);
|
||||
return verifyToken(tokenString, realmKey, realmUrl, true, true);
|
||||
}
|
||||
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl, boolean checkActive) throws VerificationException {
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl, boolean checkActive, boolean checkTokenType) throws VerificationException {
|
||||
JWSInput input = null;
|
||||
try {
|
||||
input = new JWSInput(tokenString);
|
||||
@@ -42,6 +44,13 @@ public class RSATokenVerifier {
|
||||
throw new VerificationException("Token audience doesn't match domain. Token issuer is " + token.getIssuer() + ", but URL from configuration is " + realmUrl);
|
||||
|
||||
}
|
||||
|
||||
if (checkTokenType) {
|
||||
String type = token.getType();
|
||||
if (type == null || !type.equalsIgnoreCase(TokenUtil.TOKEN_TYPE_BEARER)) {
|
||||
throw new VerificationException("Token type is incorrect. Expected '" + TokenUtil.TOKEN_TYPE_BEARER + "' but was '" + type + "'");
|
||||
}
|
||||
}
|
||||
if (checkActive && !token.isActive()) {
|
||||
throw new VerificationException("Token is not active.");
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.keycloak;
|
||||
|
||||
import org.codehaus.jackson.annotate.JsonProperty;
|
||||
|
||||
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 String VERSION;
|
||||
public static String RESOURCES_VERSION;
|
||||
public static String BUILD_TIME;
|
||||
public static final String UNKNOWN = "UNKNOWN";
|
||||
public static final Version SINGLETON;
|
||||
|
||||
private final String version = VERSION;
|
||||
private final String buildTime = BUILD_TIME;
|
||||
|
||||
static {
|
||||
Properties props = new Properties();
|
||||
InputStream is = Version.class.getResourceAsStream("/keycloak-version.properties");
|
||||
try {
|
||||
props.load(is);
|
||||
VERSION = props.getProperty("version");
|
||||
BUILD_TIME = props.getProperty("build-time");
|
||||
RESOURCES_VERSION = VERSION.toLowerCase();
|
||||
} catch (IOException e) {
|
||||
VERSION=UNKNOWN;
|
||||
BUILD_TIME=UNKNOWN;
|
||||
}
|
||||
|
||||
SINGLETON = new Version();
|
||||
}
|
||||
|
||||
@JsonProperty("version")
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@JsonProperty("build-time")
|
||||
public String getBuildTime() {
|
||||
return buildTime;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
package org.keycloak.jose.jwk;
|
||||
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.Key;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.jose.jwk;
|
||||
|
||||
import org.codehaus.jackson.type.TypeReference;
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.keycloak.jose.jws;
|
||||
|
||||
import org.keycloak.jose.jws.crypto.HMACProvider;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package org.keycloak.jose.jws;
|
||||
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import static org.keycloak.jose.jws.Algorithm.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.keycloak.jose.jws.crypto;
|
||||
|
||||
import org.keycloak.jose.jws.Algorithm;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.util.Base64Url;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.keycloak.jose.jws.crypto;
|
||||
|
||||
import org.keycloak.jose.jws.Algorithm;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.util.PemUtils;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.keycloak.json;
|
||||
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.codehaus.jackson.JsonParser;
|
||||
import org.codehaus.jackson.JsonProcessingException;
|
||||
import org.codehaus.jackson.map.DeserializationContext;
|
||||
import org.codehaus.jackson.map.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class StringOrArrayDeserializer extends JsonDeserializer<Object> {
|
||||
|
||||
@Override
|
||||
public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||
JsonNode jsonNode = jsonParser.readValueAsTree();
|
||||
if (jsonNode.isArray()) {
|
||||
ArrayList<String> a = new ArrayList<>(1);
|
||||
Iterator<JsonNode> itr = jsonNode.iterator();
|
||||
while (itr.hasNext()) {
|
||||
a.add(itr.next().getTextValue());
|
||||
}
|
||||
return a.toArray(new String[a.size()]);
|
||||
} else {
|
||||
return new String[] { jsonNode.getTextValue() };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package org.keycloak.json;
|
||||
|
||||
import org.codehaus.jackson.JsonGenerator;
|
||||
import org.codehaus.jackson.map.JsonSerializer;
|
||||
import org.codehaus.jackson.map.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class StringOrArraySerializer extends JsonSerializer<Object> {
|
||||
@Override
|
||||
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
|
||||
String[] array = (String[]) o;
|
||||
if (array == null) {
|
||||
jsonGenerator.writeNull();
|
||||
} else if (array.length == 1) {
|
||||
jsonGenerator.writeString(array[0]);
|
||||
} else {
|
||||
jsonGenerator.writeStartArray();
|
||||
for (String s : array) {
|
||||
jsonGenerator.writeString(s);
|
||||
}
|
||||
jsonGenerator.writeEndArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,11 +163,6 @@ public class AccessToken extends IDToken {
|
||||
return (AccessToken) super.issuer(issuer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken audience(String audience) {
|
||||
return (AccessToken) super.audience(audience);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken subject(String subject) {
|
||||
return (AccessToken) super.subject(subject);
|
||||
|
||||
Loaded 100 of 2897 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user