Compare commits
702
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b071b83aa | ||
|
|
eef6e94923 | ||
|
|
f6d50245ac | ||
|
|
f3940bf78c | ||
|
|
62bcf17a1e | ||
|
|
44f9b28618 | ||
|
|
9ec0409a46 | ||
|
|
cd5e191b18 | ||
|
|
a14b3753da | ||
|
|
41b8701d51 | ||
|
|
d84e7eb38b | ||
|
|
d40b256557 | ||
|
|
5304e197e5 | ||
|
|
623e28b9c2 | ||
|
|
274bc4e33a | ||
|
|
42b44ed3b0 | ||
|
|
b0c99e6111 | ||
|
|
fe73feee34 | ||
|
|
629d3ce4aa | ||
|
|
ed6c290bbc | ||
|
|
9dde3f60d6 | ||
|
|
1bcc8c9110 | ||
|
|
bb132e1aa0 | ||
|
|
5e4b843eb7 | ||
|
|
85cc63c7ce | ||
|
|
a697f4bd41 | ||
|
|
7e03c74bc3 | ||
|
|
67f7bcec99 | ||
|
|
267b80c2fa | ||
|
|
66e848710e | ||
|
|
93f48ecb6c | ||
|
|
ecace349f5 | ||
|
|
4a5b313816 | ||
|
|
c79506a34f | ||
|
|
5e97051c07 | ||
|
|
562aa24ebf | ||
|
|
4a66687304 | ||
|
|
42c2066fd8 | ||
|
|
161b3293dc | ||
|
|
a9608904d0 | ||
|
|
1b9358c4c6 | ||
|
|
70ff6c7209 | ||
|
|
3133e30265 | ||
|
|
d0c2e80949 | ||
|
|
89e1937501 | ||
|
|
c05f83c9b3 | ||
|
|
f2e97ff9d6 | ||
|
|
ca4ed6d528 | ||
|
|
8006ea073b | ||
|
|
f8b4a91fa8 | ||
|
|
e17d6c81f9 | ||
|
|
f77de41b2e | ||
|
|
c12577e886 | ||
|
|
5daec20a6e | ||
|
|
6d3aaa0560 | ||
|
|
2e11e71453 | ||
|
|
fb561b8fd6 | ||
|
|
a26ac1758c | ||
|
|
ef60e17641 | ||
|
|
53943f8246 | ||
|
|
0b8b31a3ea | ||
|
|
6f3132eafd | ||
|
|
dcb5717154 | ||
|
|
bfdb8d4e2d | ||
|
|
91fced3b87 | ||
|
|
825c475c7f | ||
|
|
89471b7db1 | ||
|
|
95233af485 | ||
|
|
fc37398235 | ||
|
|
16ea18370d | ||
|
|
1049bca433 | ||
|
|
364174fb7e | ||
|
|
5352872b4b | ||
|
|
bd0887d18e | ||
|
|
9a5f42039d | ||
|
|
ce8dd136bd | ||
|
|
1be2bff95f | ||
|
|
485ca9c90f | ||
|
|
811cfd52c9 | ||
|
|
5c1807eb2d | ||
|
|
7c15a70f53 | ||
|
|
c9c525e942 | ||
|
|
5d141d4d8a | ||
|
|
e96d6f0dfd | ||
|
|
423dc1b8a7 | ||
|
|
ab080dcdd8 | ||
|
|
6f173d4554 | ||
|
|
649a40f58c | ||
|
|
d06668d39b | ||
|
|
b23463a1d2 | ||
|
|
7f81032577 | ||
|
|
280cbf2174 | ||
|
|
228bb297c2 | ||
|
|
f96e59d085 | ||
|
|
86300e7e86 | ||
|
|
5dea07793b | ||
|
|
5e51204114 | ||
|
|
4c0751c1a0 | ||
|
|
ec1434c65e | ||
|
|
aa7bbeb11b | ||
|
|
88a39dbaf7 | ||
|
|
52920119bd | ||
|
|
47ac358bb6 | ||
|
|
62aa2d7f65 | ||
|
|
557de7690e | ||
|
|
4c8da3d614 | ||
|
|
3f539c6d5c | ||
|
|
5b1d67f17d | ||
|
|
e3e32982a0 | ||
|
|
b771cd30e7 | ||
|
|
ac29db51e5 | ||
|
|
6e3770f04a | ||
|
|
d0a3a04d34 | ||
|
|
c5662020d8 | ||
|
|
fea0d1af66 | ||
|
|
30cd28d288 | ||
|
|
c475721dab | ||
|
|
839069ca15 | ||
|
|
09860f1ee1 | ||
|
|
a1b6378bef | ||
|
|
3530fa6259 | ||
|
|
d22afd78e6 | ||
|
|
f1986093e6 | ||
|
|
6c5477bc02 | ||
|
|
ae6fd458e8 | ||
|
|
cdda48d895 | ||
|
|
556314ae15 | ||
|
|
a2845fa0b4 | ||
|
|
8c4a3374d3 | ||
|
|
b97106b750 | ||
|
|
7907abd206 | ||
|
|
090871f8b9 | ||
|
|
0baf12c0ef | ||
|
|
1599371ee5 | ||
|
|
3bc27ef366 | ||
|
|
d5c5cc8321 | ||
|
|
aea00fc574 | ||
|
|
e9dc8b2460 | ||
|
|
eaed199b20 | ||
|
|
f7fcefc11c | ||
|
|
1f0dcbddbe | ||
|
|
9af0743883 | ||
|
|
7d4863783c | ||
|
|
d87718f768 | ||
|
|
c7ba6159b5 | ||
|
|
b43909aff1 | ||
|
|
87d9a5422d | ||
|
|
44937d33ad | ||
|
|
b561080f3a | ||
|
|
d905ce12e3 | ||
|
|
7040bd1c51 | ||
|
|
cd91a29a89 | ||
|
|
b1b452815a | ||
|
|
59d66dd20e | ||
|
|
0763d0d9d6 | ||
|
|
8c8c44e50f | ||
|
|
14b1941454 | ||
|
|
e52811ac28 | ||
|
|
4f3a980f8b | ||
|
|
05a1fc1ded | ||
|
|
ff74d1ddc0 | ||
|
|
31b0f5543f | ||
|
|
39c0be5d99 | ||
|
|
fb18789b05 | ||
|
|
bcbf5da4b8 | ||
|
|
e1b9dfe65d | ||
|
|
52f86f2293 | ||
|
|
e413694cf5 | ||
|
|
20ce36dc64 | ||
|
|
a3c982a630 | ||
|
|
e0542b5260 | ||
|
|
7c7025a83d | ||
|
|
3e6a1f47ec | ||
|
|
32703d19a0 | ||
|
|
cdc6588ac1 | ||
|
|
57aea9b51c | ||
|
|
a2171bf777 | ||
|
|
b9d0f64f74 | ||
|
|
55d614fce8 | ||
|
|
46d118207a | ||
|
|
3bfe3d256e | ||
|
|
b50ab14a0a | ||
|
|
08c58cf2f2 | ||
|
|
d26543360b | ||
|
|
fb18004c1d | ||
|
|
49fb452a79 | ||
|
|
55bd889a0f | ||
|
|
269a0dbec1 | ||
|
|
cf51db88e7 | ||
|
|
fc0889cd2e | ||
|
|
b3b480c25f | ||
|
|
892fa04130 | ||
|
|
8d3e51c236 | ||
|
|
fd9d2ba4d5 | ||
|
|
75bc633a33 | ||
|
|
3fdb22cb05 | ||
|
|
f51ba1cb8a | ||
|
|
688f4a07a3 | ||
|
|
6c7d0f27a7 | ||
|
|
1e5ca3062c | ||
|
|
ca97e7ba35 | ||
|
|
e99afec7ec | ||
|
|
a23853a6bc | ||
|
|
7c8edb5d11 | ||
|
|
83ad045410 | ||
|
|
e5d5276135 | ||
|
|
6f38a02aaa | ||
|
|
5dd84f1d9a | ||
|
|
30147ce25a | ||
|
|
dd011f043d | ||
|
|
7dec0319b6 | ||
|
|
06c14df0f3 | ||
|
|
041d0be990 | ||
|
|
f6a76e673c | ||
|
|
47f361a4ab | ||
|
|
6e7924da76 | ||
|
|
df1a0c03b6 | ||
|
|
971bea8a24 | ||
|
|
c8f0a1ab5a | ||
|
|
0ae9ac0848 | ||
|
|
3dd52e8b28 | ||
|
|
0f6915c615 | ||
|
|
74cd23b331 | ||
|
|
cc17895ef3 | ||
|
|
09ada81b27 | ||
|
|
75e0fa87c3 | ||
|
|
6628e226e4 | ||
|
|
89d47a392b | ||
|
|
c38abb2cfe | ||
|
|
faf18dfdfd | ||
|
|
2dc32fb8c9 | ||
|
|
2ec029e8e0 | ||
|
|
80904209b3 | ||
|
|
8b1483d7ef | ||
|
|
bbeff1ef22 | ||
|
|
aac3c2e0ee | ||
|
|
a240a00983 | ||
|
|
c86a6ba3f3 | ||
|
|
bc301baa1f | ||
|
|
edbf26f007 | ||
|
|
5dca2a3588 | ||
|
|
cf5a7d228b | ||
|
|
f7a7c3ca7b | ||
|
|
28fcdf0b8f | ||
|
|
c38ec33881 | ||
|
|
cfee00d4c5 | ||
|
|
46bf0d78fa | ||
|
|
a14be592de | ||
|
|
29691a3167 | ||
|
|
517a2b99d7 | ||
|
|
edf73af508 | ||
|
|
4a5ea08a2a | ||
|
|
7b86cca649 | ||
|
|
c77b7cd7d6 | ||
|
|
6b0a87c57a | ||
|
|
b1c331c5f3 | ||
|
|
7ae342452e | ||
|
|
4438aa6606 | ||
|
|
8cd8472003 | ||
|
|
687aa78567 | ||
|
|
8419e5883d | ||
|
|
4bac0474c6 | ||
|
|
f0b66a2241 | ||
|
|
51b71e8f20 | ||
|
|
8615515b9a | ||
|
|
10cf486d26 | ||
|
|
abb1647672 | ||
|
|
114c1b95fa | ||
|
|
4e88bbc811 | ||
|
|
504a41aec4 | ||
|
|
e9bf1ef618 | ||
|
|
9d6e450c05 | ||
|
|
fb7e95f1e4 | ||
|
|
f95418dfc9 | ||
|
|
94be235a0f | ||
|
|
100de5a55e | ||
|
|
26570de4cd | ||
|
|
7c97e02715 | ||
|
|
e73bdf9d8c | ||
|
|
8d1ff1d49c | ||
|
|
de770d2881 | ||
|
|
7f96770089 | ||
|
|
3f83538fc1 | ||
|
|
3040f4e89f | ||
|
|
c57c264d91 | ||
|
|
8ba7559cac | ||
|
|
c4d5a4138c | ||
|
|
d699404ce7 | ||
|
|
ee79747cb6 | ||
|
|
5cb6c4e77c | ||
|
|
05638a8953 | ||
|
|
48f7efc97f | ||
|
|
9aa6b4cbfa | ||
|
|
cae0a7628d | ||
|
|
82e29dfcb3 | ||
|
|
ad94b94833 | ||
|
|
687e497455 | ||
|
|
67f31648a6 | ||
|
|
d332851a75 | ||
|
|
4a18a32cfc | ||
|
|
428cd54a81 | ||
|
|
dc4e8603d7 | ||
|
|
b96f8aef6d | ||
|
|
dc50c312cb | ||
|
|
1f12a2d67b | ||
|
|
a2bef7dbbe | ||
|
|
c6af13c8cc | ||
|
|
5be5f6475f | ||
|
|
5673fb34b1 | ||
|
|
5214fe2a55 | ||
|
|
76db33829b | ||
|
|
746da8f270 | ||
|
|
f8667cdb38 | ||
|
|
1ec4fe921d | ||
|
|
915701106c | ||
|
|
2309e6f040 | ||
|
|
839d823edd | ||
|
|
99e6f0edad | ||
|
|
bb138bd6e4 | ||
|
|
32a19563a5 | ||
|
|
3b65127399 | ||
|
|
c17a5823e9 | ||
|
|
c9e88c944a | ||
|
|
b93cf4868c | ||
|
|
53ac88ca26 | ||
|
|
aff32f69bb | ||
|
|
4fcf11d0db | ||
|
|
e04af84ac0 | ||
|
|
965c44a43d | ||
|
|
905061e2b7 | ||
|
|
45df3087f2 | ||
|
|
f9f53a3355 | ||
|
|
ab08ac8ad4 | ||
|
|
12c9475bfc | ||
|
|
a0d7fc12db | ||
|
|
5b5fea347a | ||
|
|
d049007412 | ||
|
|
cc14a3b288 | ||
|
|
bcd3eeda49 | ||
|
|
992b365eab | ||
|
|
3882cc4aa8 | ||
|
|
38bd79ab88 | ||
|
|
790fd1d94d | ||
|
|
19e1ddff1d | ||
|
|
0bbc26bd0b | ||
|
|
1f3db436d8 | ||
|
|
7ac663bd5f | ||
|
|
53fbceb49a | ||
|
|
1159dc091d | ||
|
|
38c0b4ad65 | ||
|
|
f4f563d570 | ||
|
|
550ba16a09 | ||
|
|
0289f5dff9 | ||
|
|
ea0ceeb65d | ||
|
|
3746bf28a1 | ||
|
|
a497c69758 | ||
|
|
731d75c756 | ||
|
|
982ba5ab90 | ||
|
|
c2e2a46025 | ||
|
|
8430fb0ed3 | ||
|
|
9a829a38b1 | ||
|
|
04ec750157 | ||
|
|
3655db2a30 | ||
|
|
5edb84ccfb | ||
|
|
95e2da9c9e | ||
|
|
6cb1eb41cf | ||
|
|
46a0caf2e0 | ||
|
|
d96b660686 | ||
|
|
ae66b1b88e | ||
|
|
60a564dcfd | ||
|
|
69656d2775 | ||
|
|
24415f2186 | ||
|
|
0ae3eafe10 | ||
|
|
6cf708f6e1 | ||
|
|
f5a626006c | ||
|
|
101a72cd65 | ||
|
|
312429cb88 | ||
|
|
c9851f1c05 | ||
|
|
73b7fe6169 | ||
|
|
d1c5c55a61 | ||
|
|
bdc31d9459 | ||
|
|
f08c42a37e | ||
|
|
8fbd39934f | ||
|
|
c460630cf8 | ||
|
|
335bc87ad8 | ||
|
|
6cbeeb1b1a | ||
|
|
47c9f1439d | ||
|
|
64589bc807 | ||
|
|
2eae9c17a4 | ||
|
|
9f6c206078 | ||
|
|
2460eecd75 | ||
|
|
a084695978 | ||
|
|
705da88daa | ||
|
|
ce85a42ecf | ||
|
|
2990b75faa | ||
|
|
94c06f3f5d | ||
|
|
b72a7db6fe | ||
|
|
9e4086e501 | ||
|
|
b960f18f4e | ||
|
|
d0dc75c06f | ||
|
|
13a5eccaf8 | ||
|
|
898195e1da | ||
|
|
8ea0d19d2f | ||
|
|
465318b352 | ||
|
|
fa01d53f9e | ||
|
|
ba8fe1ddaf | ||
|
|
50bc53d673 | ||
|
|
d682701232 | ||
|
|
544883ca9f | ||
|
|
54a7761e15 | ||
|
|
ed51b4e1ea | ||
|
|
fcc4781e3a | ||
|
|
24b5bd6862 | ||
|
|
614c718304 | ||
|
|
e2ce33a86a | ||
|
|
e338f1af15 | ||
|
|
eefc5ed1d7 | ||
|
|
7694b130e6 | ||
|
|
32ad7271f3 | ||
|
|
2b012ff238 | ||
|
|
1bd219ed40 | ||
|
|
02a59812e6 | ||
|
|
7f4849e165 | ||
|
|
628c7dd92a | ||
|
|
5764ad84e9 | ||
|
|
f3fde4a8df | ||
|
|
983ccdd121 | ||
|
|
73ed22c52c | ||
|
|
bace16bac6 | ||
|
|
3bb0842eae | ||
|
|
a6b38397ea | ||
|
|
c63467c79f | ||
|
|
b1cd37814a | ||
|
|
07d10ee583 | ||
|
|
614bee3061 | ||
|
|
81dfea4052 | ||
|
|
1b14444eba | ||
|
|
245d83adce | ||
|
|
b5835fc232 | ||
|
|
8a54f133ba | ||
|
|
511cc483cb | ||
|
|
6e18a16f78 | ||
|
|
43d08f2d05 | ||
|
|
171e9b1ce9 | ||
|
|
eec582e704 | ||
|
|
4b05feb6d6 | ||
|
|
d6f5bf6cde | ||
|
|
f1d72d0b6d | ||
|
|
148d494905 | ||
|
|
38b575d91b | ||
|
|
baf99a2280 | ||
|
|
1d80b87bcc | ||
|
|
84754c47d3 | ||
|
|
64b8a990f9 | ||
|
|
0580c2223b | ||
|
|
824aed773b | ||
|
|
9164e69d49 | ||
|
|
670dc39d4f | ||
|
|
b196d0dded | ||
|
|
bfd62b0807 | ||
|
|
3514d5cd78 | ||
|
|
b3b46339a4 | ||
|
|
9ff4947abd | ||
|
|
469eb77486 | ||
|
|
213b685b43 | ||
|
|
42df327104 | ||
|
|
d2b42e3843 | ||
|
|
b999c1e5b1 | ||
|
|
2ecf696a12 | ||
|
|
063a63445a | ||
|
|
b84bdcf464 | ||
|
|
f275ecf6d5 | ||
|
|
b241920802 | ||
|
|
dcd1406a27 | ||
|
|
d2d408e223 | ||
|
|
9699d8aa82 | ||
|
|
6d8d9107c6 | ||
|
|
fb8483dc56 | ||
|
|
85621bdd9f | ||
|
|
573f7fc1fb | ||
|
|
14af840c3a | ||
|
|
aa2d1bcc93 | ||
|
|
20cde9cd00 | ||
|
|
3dff4afe83 | ||
|
|
3edce7f580 | ||
|
|
35d601d795 | ||
|
|
f00957ec3a | ||
|
|
46c04561ff | ||
|
|
9abe357754 | ||
|
|
3c99350247 | ||
|
|
b041f2a857 | ||
|
|
0a15f873af | ||
|
|
08b0aebe03 | ||
|
|
a323fe7992 | ||
|
|
1963e94e33 | ||
|
|
7437af0131 | ||
|
|
60a1fc3020 | ||
|
|
8714193c97 | ||
|
|
a61733cf47 | ||
|
|
1aff8af336 | ||
|
|
c21be01e97 | ||
|
|
72d240a57e | ||
|
|
83769b3d52 | ||
|
|
1a5c2365a1 | ||
|
|
87e40f1820 | ||
|
|
8fbfba907b | ||
|
|
f342a8c7a3 | ||
|
|
866715b752 | ||
|
|
e0ec121012 | ||
|
|
63ff5736a2 | ||
|
|
3451778f48 | ||
|
|
e4b3007ce2 | ||
|
|
a5593469ae | ||
|
|
484a4c1454 | ||
|
|
09a336c708 | ||
|
|
4ac5fb08e3 | ||
|
|
ff86bdc35f | ||
|
|
726ce08700 | ||
|
|
c14840a4c0 | ||
|
|
24a492ffe0 | ||
|
|
c4ff4e030a | ||
|
|
7244944879 | ||
|
|
1f2db2c049 | ||
|
|
d6e8b1ba2c | ||
|
|
7f0a3eebfb | ||
|
|
5d0345c922 | ||
|
|
99a041158c | ||
|
|
8f7efd5b67 | ||
|
|
d2c27daa16 | ||
|
|
2d2041db5e | ||
|
|
e3f260c57f | ||
|
|
8113c3f05e | ||
|
|
e3bc15a4d9 | ||
|
|
3f68180ee7 | ||
|
|
6bb6dc0aaf | ||
|
|
d625fb014c | ||
|
|
8cc7676335 | ||
|
|
626cecba95 | ||
|
|
65348cd5e7 | ||
|
|
5f5316fbdc | ||
|
|
011bac7a1e | ||
|
|
86671a2354 | ||
|
|
8fac39fffa | ||
|
|
a2710e01da | ||
|
|
38abcd4a90 | ||
|
|
62dd6fbc6b | ||
|
|
75c56a2a7c | ||
|
|
7491b1c369 | ||
|
|
a3cca7424a | ||
|
|
387aed6269 | ||
|
|
20bf888d73 | ||
|
|
ad6d52cb0f | ||
|
|
8dc293f629 | ||
|
|
de8819aae3 | ||
|
|
e98ced5d0f | ||
|
|
6775af302a | ||
|
|
621cae61b6 | ||
|
|
922a8f7eef | ||
|
|
48a0e564b9 | ||
|
|
0758d89a59 | ||
|
|
e94b6acd02 | ||
|
|
a1beff7d3d | ||
|
|
ffc30b4c03 | ||
|
|
6d824231e9 | ||
|
|
060a90197e | ||
|
|
df7aac01dd | ||
|
|
69b00d859b | ||
|
|
9c88979040 | ||
|
|
bda218af07 | ||
|
|
15d7568792 | ||
|
|
18b14b54f4 | ||
|
|
38857cf2e6 | ||
|
|
0647590170 | ||
|
|
099743d448 | ||
|
|
4cbc423d67 | ||
|
|
e37b5613ed | ||
|
|
f92ad89a6c | ||
|
|
e99a675c50 | ||
|
|
4593bff76f | ||
|
|
81d6590544 | ||
|
|
2f9597cf51 | ||
|
|
8a246a6444 | ||
|
|
876d493458 | ||
|
|
6f023fcae4 | ||
|
|
0abd93417a | ||
|
|
b4f5fe9977 | ||
|
|
e15b0c7d90 | ||
|
|
3cf52b018c | ||
|
|
cb9f159091 | ||
|
|
64cea5f25a | ||
|
|
b6fd58e644 | ||
|
|
de774a3058 | ||
|
|
9ebe2ff45e | ||
|
|
4ebc575afc | ||
|
|
a1d4d8e13f | ||
|
|
69f7dfbb47 | ||
|
|
99ce0a36e6 | ||
|
|
67c34554db | ||
|
|
9ba61af83b | ||
|
|
436f5f6229 | ||
|
|
270d6108ca | ||
|
|
18094370a6 | ||
|
|
26eac398e0 | ||
|
|
93c896b4f7 | ||
|
|
6b29202f1f | ||
|
|
3b1d8fd8fe | ||
|
|
630d62f014 | ||
|
|
711b8ca747 | ||
|
|
34a1923d18 | ||
|
|
6291936ce9 | ||
|
|
5220c6c288 | ||
|
|
532c82f752 | ||
|
|
61218715af | ||
|
|
8dce5a90bb | ||
|
|
8d794b8151 | ||
|
|
b1cfab34fd | ||
|
|
159a5e20bf | ||
|
|
aea4fd8e30 | ||
|
|
767e6a9783 | ||
|
|
bb8ac0000e | ||
|
|
d73d2e0788 | ||
|
|
714e83198e | ||
|
|
c780918501 | ||
|
|
8bcb01fadb | ||
|
|
f78f5366cf | ||
|
|
f0d02f24b1 | ||
|
|
15bc33f8e6 | ||
|
|
d21a19925b | ||
|
|
a1e9d99d3e | ||
|
|
094cf675c7 | ||
|
|
efcb7ee110 | ||
|
|
c8321fc96e | ||
|
|
56ea29e899 | ||
|
|
df2305eb02 | ||
|
|
5281793078 | ||
|
|
9beb210c23 | ||
|
|
d1c890db18 | ||
|
|
0be4a4b71d | ||
|
|
19a545049b | ||
|
|
34eb34c5fc | ||
|
|
28adc28a56 | ||
|
|
5d8c803da6 | ||
|
|
2fd7fdaa74 | ||
|
|
f9cb99a1ee | ||
|
|
37bfb2c594 | ||
|
|
3b55248e6c | ||
|
|
b35bccdad2 | ||
|
|
6cabf3e57d | ||
|
|
b31b54e17c | ||
|
|
469d044254 | ||
|
|
9a26d7078f | ||
|
|
896c32a660 | ||
|
|
6e23613b9e | ||
|
|
d15324110e | ||
|
|
153de54fe8 | ||
|
|
2866f6fc23 | ||
|
|
9228f0c076 | ||
|
|
1eafb01c8d | ||
|
|
44f446e745 | ||
|
|
c71fdc72c7 | ||
|
|
bbf944a225 | ||
|
|
dbc5641144 | ||
|
|
9080a64fcd | ||
|
|
f50177996d | ||
|
|
b649dd39d9 | ||
|
|
ab87c03732 | ||
|
|
8eaf77b3c1 | ||
|
|
cbea141a54 | ||
|
|
60a040a141 | ||
|
|
4a518c964b | ||
|
|
bb2ad656a3 | ||
|
|
30b95e0a57 | ||
|
|
852c631eff | ||
|
|
211a279248 | ||
|
|
2ae2067841 | ||
|
|
0dd06e3343 | ||
|
|
4e9bec69e4 | ||
|
|
70392d9f1a | ||
|
|
9a3abf6a6a | ||
|
|
0bfcbdb359 | ||
|
|
2f3c8bf079 | ||
|
|
e7bde986aa | ||
|
|
f3211bf34d | ||
|
|
c086e0a502 | ||
|
|
80f4b668b2 | ||
|
|
01606ab5e0 | ||
|
|
91e29d9710 | ||
|
|
23d101f8fa | ||
|
|
e08b3e7dec | ||
|
|
c4e32b7c45 | ||
|
|
14ece40054 | ||
|
|
eaa6be55d7 | ||
|
|
2ae714aea2 | ||
|
|
5f6687ec62 | ||
|
|
06053fad85 | ||
|
|
d0c06ab0ce | ||
|
|
cfb6f927b2 | ||
|
|
8d33894989 | ||
|
|
ba13cbe004 | ||
|
|
9410adf9ce | ||
|
|
7443c78087 | ||
|
|
d5b34a0b41 |
No files matched your search
@@ -1,4 +1,35 @@
|
||||
keycloak
|
||||
========
|
||||
|
||||
SSO Service for web apps and REST services.
|
||||
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
|
||||
and video tutorials.
|
||||
|
||||
Keycloak is an SSO Service for web apps and REST services.
|
||||
It can be used for social applications as well as enterprise applications. It is based on OpenID Connect with SAML support in the works.
|
||||
Here's some of the features:
|
||||
|
||||
* SSO and Single Log Out for browser applications
|
||||
* Social Broker. Enable Google, Facebook, Yahoo, Twitter social login with no code required.
|
||||
* Optional LDAP/Active Directory integration
|
||||
* Optional User Registration
|
||||
* Password and TOTP support (via Google Authenticator). Client cert auth coming soon.
|
||||
* User session management from both admin and user perspective
|
||||
* Customizable themes for user facing pages: login, grant pages, account management, emails, and admin console all customizable!
|
||||
* OAuth Bearer token auth for REST Services
|
||||
* Integrated Browser App to REST Service token propagation
|
||||
* Admin REST API
|
||||
* OAuth 2.0 Grant requests
|
||||
* CORS Support
|
||||
* CORS Web Origin management and validation
|
||||
* Completely centrally managed user and role mapping metadata. Minimal configuration at the application side
|
||||
* Admin Console for managing users, roles, role mappings, applications, user sessions, allowed CORS web origins, and OAuth clients.
|
||||
* Deployable as a WAR, appliance, or an Openshift cloud service (SaaS).
|
||||
* Supports JBoss AS7, EAP 6.x, and Wildfly applications. Plans to support Node.js, RAILS, GRAILS, and other non-Java applications.
|
||||
* Javascript/HTML 5 adapter for pure Javascript apps
|
||||
* Session management from admin console
|
||||
* Revocation policies
|
||||
* Password policies
|
||||
* OpenID Connect Support
|
||||
|
||||
Please visit [http://keycloak.org](http://keycloak.org) for more information on Keycloak including how to download, documentation,
|
||||
and video tutorials.
|
||||
@@ -1,2 +0,0 @@
|
||||
org.keycloak.audit.AuditProviderSpi
|
||||
org.keycloak.audit.AuditListenerSpi
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.email.EmailAuditListenerFactory
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.log.JBossLoggingAuditListenerFactory
|
||||
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.jpa.JpaAuditProviderFactory
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.keycloak.audit.jpa;
|
||||
|
||||
import org.keycloak.audit.tests.AbstractAuditProviderTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class JpaAuditProviderTest extends AbstractAuditProviderTest {
|
||||
|
||||
@Override
|
||||
protected String getProviderId() {
|
||||
return JpaAuditProviderFactory.ID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||
version="1.0">
|
||||
<persistence-unit name="jpa-keycloak-audit-store" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||
|
||||
<class>org.keycloak.audit.jpa.EventEntity</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
<properties>
|
||||
<property name="hibernate.connection.url" value="jdbc:h2:mem:test"/>
|
||||
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
|
||||
<property name="hibernate.connection.username" value="sa"/>
|
||||
<property name="hibernate.connection.password" value=""/>
|
||||
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
|
||||
<property name="hibernate.show_sql" value="false" />
|
||||
<property name="hibernate.format_sql" value="true" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
@@ -1,136 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project>
|
||||
<parent>
|
||||
<artifactId>keycloak-audit-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-2</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-audit-mongo</artifactId>
|
||||
<name>Keycloak Audit Mongo Provider</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-audit-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<keycloak.audit.mongo.host>localhost</keycloak.audit.mongo.host>
|
||||
<keycloak.audit.mongo.port>27018</keycloak.audit.mongo.port>
|
||||
<keycloak.audit.mongo.db>keycloak</keycloak.audit.mongo.db>
|
||||
<keycloak.audit.mongo.clearOnStartup>true</keycloak.audit.mongo.clearOnStartup>
|
||||
<keycloak.audit.mongo.bindIp>127.0.0.1</keycloak.audit.mongo.bindIp>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Postpone tests to "integration-test" phase, so that we can bootstrap embedded mongo on 27018 before running tests -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test</id>
|
||||
<phase>integration-test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<keycloak.audit.mongo.host>${keycloak.audit.mongo.host}</keycloak.audit.mongo.host>
|
||||
<keycloak.audit.mongo.port>${keycloak.audit.mongo.port}</keycloak.audit.mongo.port>
|
||||
<keycloak.audit.mongo.db>${keycloak.audit.mongo.db}</keycloak.audit.mongo.db>
|
||||
<keycloak.audit.mongo.clearOnStartup>${keycloak.audit.mongo.clearOnStartup}</keycloak.audit.mongo.clearOnStartup>
|
||||
<keycloak.audit.mongo.bindIp>${keycloak.model.mongo.bindIp}</keycloak.audit.mongo.bindIp>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-test</id>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Embedded mongo -->
|
||||
<plugin>
|
||||
<groupId>com.github.joelittlejohn.embedmongo</groupId>
|
||||
<artifactId>embedmongo-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>start-mongodb</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>start</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<port>${keycloak.audit.mongo.port}</port>
|
||||
<logging>file</logging>
|
||||
<logFile>${project.build.directory}/mongodb.log</logFile>
|
||||
<bindIp>${keycloak.audit.mongo.bindIp}</bindIp>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>stop-mongodb</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<goals>
|
||||
<goal>stop</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,96 +0,0 @@
|
||||
package org.keycloak.audit.mongo;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import com.mongodb.WriteConcern;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class MongoAuditProviderFactory implements AuditProviderFactory {
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(MongoAuditProviderFactory.class);
|
||||
|
||||
public static final String ID = "mongo";
|
||||
private MongoClient client;
|
||||
private DB db;
|
||||
|
||||
private Set<EventType> includedEvents = new HashSet<EventType>();
|
||||
|
||||
@Override
|
||||
public AuditProvider create(ProviderSession providerSession) {
|
||||
return new MongoAuditProvider(db.getCollection("audit"), includedEvents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
try {
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
String dbName = config.get("db", "keycloak-audit");
|
||||
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||
} else {
|
||||
client = new MongoClient(host, port);
|
||||
}
|
||||
|
||||
client.setWriteConcern(WriteConcern.UNACKNOWLEDGED);
|
||||
db = client.getDB(dbName);
|
||||
|
||||
if (clearOnStartup) {
|
||||
db.getCollection("audit").drop();
|
||||
}
|
||||
|
||||
logger.infof("Initialized mongo audit. host: %s, port: %d, db: %s, clearOnStartup: %b", host, port, dbName, clearOnStartup);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
String[] include = config.getArray("include-events");
|
||||
if (include != null) {
|
||||
for (String i : include) {
|
||||
includedEvents.add(EventType.valueOf(i.toUpperCase()));
|
||||
}
|
||||
} else {
|
||||
for (EventType i : EventType.values()) {
|
||||
includedEvents.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
String[] exclude = config.getArray("exclude-events");
|
||||
if (exclude != null) {
|
||||
for (String e : exclude) {
|
||||
includedEvents.remove(EventType.valueOf(e.toUpperCase()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
client.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.audit.mongo.MongoAuditProviderFactory
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.keycloak.audit.mongo;
|
||||
|
||||
import org.keycloak.audit.tests.AbstractAuditProviderTest;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class MongoAuditProviderTest extends AbstractAuditProviderTest {
|
||||
|
||||
@Override
|
||||
protected String getProviderId() {
|
||||
return MongoAuditProviderFactory.ID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package org.keycloak.audit.tests;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.audit.AuditProvider;
|
||||
import org.keycloak.audit.AuditProviderFactory;
|
||||
import org.keycloak.audit.Event;
|
||||
import org.keycloak.audit.EventType;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public abstract class AbstractAuditProviderTest {
|
||||
|
||||
private ProviderFactory<AuditProvider> factory;
|
||||
private AuditProvider provider;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
String providerId = getProviderId();
|
||||
ServiceLoader<AuditProviderFactory> factories = ServiceLoader.load(AuditProviderFactory.class);
|
||||
for (AuditProviderFactory f : factories) {
|
||||
if (f.getId().equals(providerId)) {
|
||||
factory = f;
|
||||
factory.init(Config.scope("audit", providerId));
|
||||
}
|
||||
}
|
||||
|
||||
provider = factory.create(null);
|
||||
}
|
||||
|
||||
protected abstract String getProviderId();
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
provider.clear();
|
||||
provider.close();
|
||||
factory.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save() {
|
||||
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void query() {
|
||||
long oldest = System.currentTimeMillis() - 30000;
|
||||
long newest = System.currentTimeMillis() + 30000;
|
||||
|
||||
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(oldest, EventType.LOGIN, "realmId", "clientId2", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
|
||||
|
||||
provider.close();
|
||||
provider = factory.create(null);
|
||||
|
||||
Assert.assertEquals(5, provider.createQuery().client("clientId").getResultList().size());
|
||||
Assert.assertEquals(5, provider.createQuery().realm("realmId").getResultList().size());
|
||||
Assert.assertEquals(4, provider.createQuery().event(EventType.LOGIN).getResultList().size());
|
||||
Assert.assertEquals(6, provider.createQuery().event(EventType.LOGIN, EventType.REGISTER).getResultList().size());
|
||||
Assert.assertEquals(4, provider.createQuery().user("userId").getResultList().size());
|
||||
|
||||
Assert.assertEquals(1, provider.createQuery().user("userId").event(EventType.REGISTER).getResultList().size());
|
||||
|
||||
Assert.assertEquals(2, provider.createQuery().maxResults(2).getResultList().size());
|
||||
Assert.assertEquals(1, provider.createQuery().firstResult(5).getResultList().size());
|
||||
|
||||
Assert.assertEquals(newest, provider.createQuery().maxResults(1).getResultList().get(0).getTime());
|
||||
Assert.assertEquals(oldest, provider.createQuery().firstResult(5).maxResults(1).getResultList().get(0).getTime());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clear() {
|
||||
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||
|
||||
provider.close();
|
||||
provider = factory.create(null);
|
||||
|
||||
provider.clear("realmId");
|
||||
|
||||
Assert.assertEquals(1, provider.createQuery().getResultList().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearOld() {
|
||||
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
|
||||
provider.onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
|
||||
|
||||
provider.close();
|
||||
provider = factory.create(null);
|
||||
|
||||
provider.clear("realmId", System.currentTimeMillis() - 10000);
|
||||
|
||||
Assert.assertEquals(3, provider.createQuery().getResultList().size());
|
||||
}
|
||||
|
||||
private Event create(EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
|
||||
return create(System.currentTimeMillis(), event, realmId, clientId, userId, ipAddress, error);
|
||||
}
|
||||
|
||||
private Event create(long time, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
|
||||
Event e = new Event();
|
||||
e.setTime(time);
|
||||
e.setEvent(event);
|
||||
e.setRealmId(realmId);
|
||||
e.setClientId(clientId);
|
||||
e.setUserId(userId);
|
||||
e.setIpAddress(ipAddress);
|
||||
e.setError(error);
|
||||
|
||||
Map<String, String> details = new HashMap<String, String>();
|
||||
details.put("key1", "value1");
|
||||
details.put("key2", "value2");
|
||||
|
||||
e.setDetails(details);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthProviderConstants {
|
||||
|
||||
// Model is default provider. See AuthenticationProviderModel.DEFAULT_PROVIDER
|
||||
public static final String PROVIDER_NAME_MODEL = "model";
|
||||
public static final String PROVIDER_NAME_EXTERNAL_MODEL = "externalModel";
|
||||
public static final String PROVIDER_NAME_PICKETLINK = "picketlink";
|
||||
|
||||
// Used in external-model provider
|
||||
public static final String EXTERNAL_REALM_ID = "externalRealmId";
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
/**
|
||||
* Result of authentication by AuthenticationProvider
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public enum AuthProviderStatus {
|
||||
|
||||
SUCCESS, INVALID_CREDENTIALS, FAILED
|
||||
|
||||
}
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthUser {
|
||||
|
||||
private String id;
|
||||
private String username;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
private String email;
|
||||
|
||||
private String providerName;
|
||||
|
||||
public AuthUser(String id, String username, String providerName) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.providerName = providerName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public AuthUser setId(String id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public AuthUser setUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public AuthUser setName(String name) {
|
||||
int i = name.lastIndexOf(' ');
|
||||
if (i != -1) {
|
||||
firstName = name.substring(0, i);
|
||||
lastName = name.substring(i + 1);
|
||||
} else {
|
||||
firstName = name;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthUser setName(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public AuthUser setEmail(String email) {
|
||||
this.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getProviderName() {
|
||||
return providerName;
|
||||
}
|
||||
|
||||
public AuthUser setProviderName(String providerName) {
|
||||
this.providerName = providerName;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
-68
@@ -1,68 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface AuthenticationProvider extends Provider {
|
||||
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Get names of all available configuration options of current provider
|
||||
*
|
||||
* @return options or empty list if no options available
|
||||
*/
|
||||
List<String> getAvailableOptions();
|
||||
|
||||
/**
|
||||
* Get user by given username or email. Return user instance or null if user doesn't exists in this authentication provider
|
||||
*
|
||||
* @param realm
|
||||
* @param configuration
|
||||
* @param username or email
|
||||
* @return found user or null if user with given username doesn't exists
|
||||
* @throws AuthenticationProviderException
|
||||
*/
|
||||
AuthUser getUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException;
|
||||
|
||||
/**
|
||||
* Try to register user with this authentication provider
|
||||
*
|
||||
* @param realm
|
||||
* @param configuration
|
||||
* @param username
|
||||
* @return ID of newly created user (For example ID from LDAP)
|
||||
* @throws AuthenticationProviderException if user creation couldn't happen
|
||||
*/
|
||||
String registerUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException;
|
||||
|
||||
/**
|
||||
* Standard Authentication flow
|
||||
*
|
||||
* @param username
|
||||
* @param password
|
||||
* @return result of authentication, which might eventually encapsulate info about authenticated user and provider which successfully authenticated
|
||||
*/
|
||||
AuthProviderStatus validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
||||
|
||||
|
||||
/**
|
||||
* Update credential
|
||||
*
|
||||
* @param realm
|
||||
* @param configuration
|
||||
* @param username
|
||||
* @param password
|
||||
* @return true if credential has been successfully updated
|
||||
* @throws AuthenticationProviderException
|
||||
*/
|
||||
boolean updateCredential(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException;
|
||||
|
||||
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthenticationProviderException extends Exception {
|
||||
|
||||
private static final long serialVersionUID = 15L;
|
||||
|
||||
protected AuthenticationProviderException() {
|
||||
}
|
||||
|
||||
public AuthenticationProviderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public AuthenticationProviderException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public AuthenticationProviderException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface AuthenticationProviderFactory extends ProviderFactory<AuthenticationProvider> {
|
||||
}
|
||||
-219
@@ -1,219 +0,0 @@
|
||||
package org.keycloak.authentication;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.AuthenticationLinkModel;
|
||||
import org.keycloak.models.AuthenticationProviderModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
import org.keycloak.util.ProviderLoader;
|
||||
|
||||
/**
|
||||
* Access point to authentication SPI. It finds configured and available {@link AuthenticationProvider} instances for current realm
|
||||
* and then delegates method call to them.
|
||||
*
|
||||
* Example of usage: AuthenticationProviderManager.getManager(realm).validateUser("joe", "password");
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthenticationProviderManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AuthenticationProviderManager.class);
|
||||
|
||||
private final RealmModel realm;
|
||||
private final Map<String, AuthenticationProvider> delegates;
|
||||
|
||||
public static AuthenticationProviderManager getManager(RealmModel realm, ProviderSession providerSession) {
|
||||
Iterable<AuthenticationProvider> providers = providerSession.getAllProviders(AuthenticationProvider.class);
|
||||
|
||||
Map<String, AuthenticationProvider> providersMap = new HashMap<String, AuthenticationProvider>();
|
||||
for (AuthenticationProvider provider : providers) {
|
||||
providersMap.put(provider.getName(), provider);
|
||||
}
|
||||
|
||||
return new AuthenticationProviderManager(realm, providersMap);
|
||||
}
|
||||
|
||||
public AuthenticationProviderManager(RealmModel realm, Map<String, AuthenticationProvider> delegates) {
|
||||
this.realm = realm;
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
public AuthUser getUser(String username) {
|
||||
List<AuthenticationProviderModel> authProviderModels = getConfiguredProviderModels(realm);
|
||||
for (AuthenticationProviderModel providerModel : authProviderModels) {
|
||||
AuthenticationProvider delegate = getProvider(providerModel.getProviderName());
|
||||
if (delegate == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
AuthUser authUser = delegate.getUser(realm, providerModel.getConfig(), username);
|
||||
if (authUser != null) {
|
||||
logger.debugf("User '%s' found with provider '%s'", username, providerModel.getProviderName());
|
||||
return authUser;
|
||||
}
|
||||
} catch (AuthenticationProviderException ape) {
|
||||
logger.warn(ape.getMessage(), ape);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debugf("User '%s' not found with any provider", username);
|
||||
return null;
|
||||
}
|
||||
|
||||
public AuthProviderStatus validatePassword(UserModel user, String password) {
|
||||
AuthenticationLinkModel authLink = realm.getAuthenticationLink(user);
|
||||
if (authLink == null) {
|
||||
// User not yet linked with any authenticationProvider. Find provider with biggest priority where he is and link
|
||||
AuthUser authUser = getUser(user.getLoginName());
|
||||
authLink = new AuthenticationLinkModel(authUser.getProviderName(), authUser.getId());
|
||||
realm.setAuthenticationLink(user, authLink);
|
||||
logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
|
||||
}
|
||||
|
||||
String providerName = authLink.getAuthProvider();
|
||||
|
||||
AuthenticationProviderModel providerModel = getConfiguredProviderModel(realm, providerName);
|
||||
AuthenticationProvider delegate = getProvider(providerName);
|
||||
if (delegate == null || providerModel == null) {
|
||||
return AuthProviderStatus.FAILED;
|
||||
}
|
||||
|
||||
try {
|
||||
checkCorrectAuthLink(delegate, providerModel, authLink, user.getLoginName());
|
||||
|
||||
AuthProviderStatus currentResult = delegate.validatePassword(realm, providerModel.getConfig(), user.getLoginName(), password);
|
||||
logger.debugf("Authentication provider '%s' finished with '%s' for authentication of '%s'", delegate.getName(), currentResult.toString(), user.getLoginName());
|
||||
return currentResult;
|
||||
} catch (AuthenticationProviderException ape) {
|
||||
logger.warn(ape.getMessage(), ape);
|
||||
return AuthProviderStatus.FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean updatePassword(UserModel user, String password) throws AuthenticationProviderException {
|
||||
AuthenticationLinkModel authLink = realm.getAuthenticationLink(user);
|
||||
if (authLink == null) {
|
||||
// Find provider with biggest priority where password update is supported. Then register user here and link him
|
||||
List<AuthenticationProviderModel> configuredProviders = getConfiguredProviderModels(realm);
|
||||
for (AuthenticationProviderModel providerModel : configuredProviders) {
|
||||
if (providerModel.isPasswordUpdateSupported()) {
|
||||
AuthenticationProvider delegate = getProvider(providerModel.getProviderName());
|
||||
if (delegate != null) {
|
||||
AuthUser authUser = delegate.getUser(realm, providerModel.getConfig(), user.getLoginName());
|
||||
if (authUser != null) {
|
||||
// Linking existing user supported just for "model" provider. In other cases throw exception
|
||||
if (providerModel.getProviderName().equals(AuthenticationProviderModel.DEFAULT_PROVIDER.getProviderName())) {
|
||||
authLink = new AuthenticationLinkModel(providerModel.getProviderName(), authUser.getId());
|
||||
realm.setAuthenticationLink(user, authLink);
|
||||
logger.infof("User '%s' linked with provider '%s'", authUser.getUsername(), authUser.getProviderName());
|
||||
} else {
|
||||
throw new AuthenticationProviderException("User " + authUser.getUsername() + " exists in provider "
|
||||
+ authUser.getProviderName() + " but is not linked with model user");
|
||||
}
|
||||
} else {
|
||||
String userIdInProvider = delegate.registerUser(realm, providerModel.getConfig(), user.getLoginName());
|
||||
authLink = new AuthenticationLinkModel(providerModel.getProviderName(), userIdInProvider);
|
||||
realm.setAuthenticationLink(user, authLink);
|
||||
logger.infof("User '%s' registered in provider '%s' and linked", user.getLoginName(), providerModel.getProviderName());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (authLink == null) {
|
||||
logger.warnf("No providers found where password update is supported for user '%s'", user.getLoginName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String providerName = authLink.getAuthProvider();
|
||||
|
||||
AuthenticationProviderModel providerModel = getConfiguredProviderModel(realm, providerName);
|
||||
if (providerModel == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String username = user.getLoginName();
|
||||
|
||||
// Update just those, which support password update
|
||||
if (providerModel.isPasswordUpdateSupported()) {
|
||||
try {
|
||||
AuthenticationProvider delegate = getProvider(providerName);
|
||||
if (delegate == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
checkCorrectAuthLink(delegate, providerModel, authLink, username);
|
||||
|
||||
if (delegate.updateCredential(realm,providerModel.getConfig(), user.getLoginName(), password)) {
|
||||
logger.debugf("Updated password in authentication provider '%s' for user '%s'", providerName, username);
|
||||
return true;
|
||||
} else {
|
||||
logger.warnf("Password not updated in authentication provider '%s' for user '%s'", providerName, username);
|
||||
return false;
|
||||
}
|
||||
} catch (AuthenticationProviderException ape) {
|
||||
// Rethrow it to upper layer
|
||||
logger.warn("Failed to update password: " + ape.getMessage());
|
||||
throw ape;
|
||||
}
|
||||
} else {
|
||||
logger.warnf("Skip password update for authentication provider '%s' for user '%s'", providerName, username);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private AuthenticationProvider getProvider(String providerName) {
|
||||
AuthenticationProvider delegate = delegates.get(providerName);
|
||||
if (delegate == null) {
|
||||
logger.warnf("Provider '%s' not available on classpath", providerName);
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
|
||||
private static List<AuthenticationProviderModel> getConfiguredProviderModels(RealmModel realm) {
|
||||
List<AuthenticationProviderModel> configuredProviders = realm.getAuthenticationProviders();
|
||||
|
||||
// Use model based authentication of current realm by default
|
||||
if (configuredProviders == null || configuredProviders.isEmpty()) {
|
||||
configuredProviders = Collections.EMPTY_LIST;
|
||||
logger.warnf("No authentication providers found");
|
||||
}
|
||||
|
||||
return configuredProviders;
|
||||
}
|
||||
|
||||
public static AuthenticationProviderModel getConfiguredProviderModel(RealmModel realm, String providerName) {
|
||||
List<AuthenticationProviderModel> providers = getConfiguredProviderModels(realm);
|
||||
for (AuthenticationProviderModel provider : providers) {
|
||||
if (providerName.equals(provider.getProviderName())) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
logger.warnf("Provider '%s' not configured in realm", providerName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if ID of linked AuthUser is same as expected ID from authenticationLink . It should catch the case when for example user "john" was deleted in LDAP
|
||||
// and then user "john" has been created again, but it's actually different user with different ID
|
||||
private void checkCorrectAuthLink(AuthenticationProvider authProvider, AuthenticationProviderModel providerModel,
|
||||
AuthenticationLinkModel authLinkModel, String username) throws AuthenticationProviderException {
|
||||
AuthUser authUser = authProvider.getUser(realm, providerModel.getConfig(), username);
|
||||
if (authUser == null) {
|
||||
throw new AuthenticationProviderException("User " + username + " not found in authentication provider " + providerModel.getProviderName());
|
||||
}
|
||||
String userExternalId = authUser.getId();
|
||||
if (!userExternalId.equals(authLinkModel.getAuthUserId())) {
|
||||
throw new AuthenticationProviderException("ID did not match! ID from provider: " + userExternalId + ", ID from authentication link: " + authLinkModel.getAuthUserId());
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.authentication.AuthenticationSpi
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
package org.keycloak.authentication.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserCredentialModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.authentication.AuthProviderStatus;
|
||||
import org.keycloak.authentication.AuthUser;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderException;
|
||||
|
||||
/**
|
||||
* Authentication provider, which delegates calling of all methods to specified realm
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public abstract class AbstractModelAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AbstractModelAuthenticationProvider.class);
|
||||
|
||||
@Override
|
||||
public AuthUser getUser(RealmModel currentRealm, Map<String, String> config, String username) throws AuthenticationProviderException {
|
||||
RealmModel realm = getRealm(currentRealm, config);
|
||||
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
||||
return user == null ? null : createAuthenticatedUserInstance(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String registerUser(RealmModel currentRealm, Map<String, String> config, String username) throws AuthenticationProviderException {
|
||||
RealmModel realm = getRealm(currentRealm, config);
|
||||
UserModel user = currentRealm.addUser(username);
|
||||
user.setEnabled(true);
|
||||
return user.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProviderStatus validatePassword(RealmModel currentRealm, Map<String, String> config, String username, String password) throws AuthenticationProviderException {
|
||||
RealmModel realm = getRealm(currentRealm, config);
|
||||
UserModel user = KeycloakModelUtils.findUserByNameOrEmail(realm, username);
|
||||
|
||||
boolean result = realm.validatePassword(user, password);
|
||||
return result ? AuthProviderStatus.SUCCESS : AuthProviderStatus.INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCredential(RealmModel currentRealm, Map<String, String> config, String username, String password) throws AuthenticationProviderException {
|
||||
RealmModel realm = getRealm(currentRealm, config);
|
||||
|
||||
// Validate password policy
|
||||
String error = realm.getPasswordPolicy().validate(password);
|
||||
if (error != null) {
|
||||
throw new AuthenticationProviderException(error);
|
||||
}
|
||||
|
||||
UserModel user = realm.getUser(username);
|
||||
if (user == null) {
|
||||
logger.warnf("User '%s' doesn't exists. Skip password update", username);
|
||||
return false;
|
||||
}
|
||||
|
||||
UserCredentialModel cred = new UserCredentialModel();
|
||||
cred.setType(CredentialRepresentation.PASSWORD);
|
||||
cred.setValue(password);
|
||||
|
||||
realm.updateCredential(user, cred);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
protected abstract RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) throws AuthenticationProviderException;
|
||||
|
||||
protected AuthUser createAuthenticatedUserInstance(UserModel user) {
|
||||
return new AuthUser(user.getId(), user.getLoginName(), getName())
|
||||
.setName(user.getFirstName(), user.getLastName())
|
||||
.setEmail(user.getEmail());
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +0,0 @@
|
||||
package org.keycloak.authentication.model;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProviderException;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
/**
|
||||
* AbstractModelAuthenticationProvider, which delegates authentication operations to different (external) realm
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExternalModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
|
||||
|
||||
public ExternalModelAuthenticationProvider(ProviderSession providerSession) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAvailableOptions() {
|
||||
return Arrays.asList(AuthProviderConstants.EXTERNAL_REALM_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RealmModel getRealm(RealmModel currentRealm, Map<String, String> configuration) throws AuthenticationProviderException {
|
||||
String realmId = configuration.get(AuthProviderConstants.EXTERNAL_REALM_ID);
|
||||
if (realmId == null) {
|
||||
throw new AuthenticationProviderException("Option '" + AuthProviderConstants.EXTERNAL_REALM_ID + "' not specified in configuration");
|
||||
}
|
||||
|
||||
// TODO: This won't be needed when KeycloakSession is available from ProviderSession
|
||||
KeycloakSession session = ResteasyProviderFactory.getContextData(KeycloakSession.class);
|
||||
if (session == null) {
|
||||
throw new AuthenticationProviderException("KeycloakSession not available");
|
||||
}
|
||||
|
||||
RealmModel realm = session.getRealm(realmId);
|
||||
if (realm == null) {
|
||||
throw new AuthenticationProviderException("Realm with id '" + realmId + "' doesn't exists");
|
||||
}
|
||||
return realm;
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package org.keycloak.authentication.model;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ExternalModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||
return new ExternalModelAuthenticationProvider(providerSession);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_EXTERNAL_MODEL;
|
||||
}
|
||||
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package org.keycloak.authentication.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
|
||||
/**
|
||||
* AbstractModelAuthenticationProvider, which uses current realm to call operations on
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ModelAuthenticationProvider extends AbstractModelAuthenticationProvider {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAvailableOptions() {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RealmModel getRealm(RealmModel currentRealm, Map<String, String> config) {
|
||||
return currentRealm;
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package org.keycloak.authentication.model;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ModelAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||
return new ModelAuthenticationProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_MODEL;
|
||||
}
|
||||
|
||||
}
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
org.keycloak.authentication.model.ModelAuthenticationProviderFactory
|
||||
org.keycloak.authentication.model.ExternalModelAuthenticationProviderFactory
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
package org.keycloak.authentication.picketlink;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthProviderStatus;
|
||||
import org.keycloak.authentication.AuthUser;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||
import org.picketlink.idm.IdentityManagementException;
|
||||
import org.picketlink.idm.IdentityManager;
|
||||
import org.picketlink.idm.credential.Credentials;
|
||||
import org.picketlink.idm.credential.Password;
|
||||
import org.picketlink.idm.credential.UsernamePasswordCredentials;
|
||||
import org.picketlink.idm.model.basic.BasicModel;
|
||||
import org.picketlink.idm.model.basic.User;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AuthenticationProvider, which delegates authentication to picketlink
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PicketlinkAuthenticationProvider implements AuthenticationProvider {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PicketlinkAuthenticationProvider.class);
|
||||
|
||||
private final IdentityManagerProvider identityManagerProvider;
|
||||
|
||||
public PicketlinkAuthenticationProvider(IdentityManagerProvider identityManagerProvider) {
|
||||
this.identityManagerProvider = identityManagerProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAvailableOptions() {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthUser getUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException {
|
||||
IdentityManager identityManager = getIdentityManager(realm);
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
||||
return picketlinkUser == null ? null : new AuthUser(picketlinkUser.getId(), picketlinkUser.getLoginName(), getName())
|
||||
.setName(picketlinkUser.getFirstName(), picketlinkUser.getLastName())
|
||||
.setEmail(picketlinkUser.getEmail())
|
||||
.setProviderName(getName());
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw convertIDMException(ie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String registerUser(RealmModel realm, Map<String, String> configuration, String username) throws AuthenticationProviderException {
|
||||
IdentityManager identityManager = getIdentityManager(realm);
|
||||
|
||||
try {
|
||||
User picketlinkUser = new User(username);
|
||||
identityManager.add(picketlinkUser);
|
||||
return picketlinkUser.getId();
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw convertIDMException(ie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthProviderStatus validatePassword(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
||||
IdentityManager identityManager = getIdentityManager(realm);
|
||||
|
||||
try {
|
||||
UsernamePasswordCredentials credential = new UsernamePasswordCredentials();
|
||||
credential.setUsername(username);
|
||||
credential.setPassword(new Password(password.toCharArray()));
|
||||
identityManager.validateCredentials(credential);
|
||||
if (credential.getStatus() == Credentials.Status.VALID) {
|
||||
return AuthProviderStatus.SUCCESS;
|
||||
} else {
|
||||
return AuthProviderStatus.INVALID_CREDENTIALS;
|
||||
}
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw convertIDMException(ie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateCredential(RealmModel realm, Map<String, String> configuration, String username, String password) throws AuthenticationProviderException {
|
||||
IdentityManager identityManager = getIdentityManager(realm);
|
||||
|
||||
try {
|
||||
User picketlinkUser = BasicModel.getUser(identityManager, username);
|
||||
if (picketlinkUser == null) {
|
||||
logger.debugf("User '%s' doesn't exists. Skip password update", username);
|
||||
return false;
|
||||
}
|
||||
|
||||
identityManager.updateCredential(picketlinkUser, new Password(password.toCharArray()));
|
||||
return true;
|
||||
} catch (IdentityManagementException ie) {
|
||||
throw convertIDMException(ie);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public IdentityManager getIdentityManager(RealmModel realm) throws AuthenticationProviderException {
|
||||
return identityManagerProvider.getIdentityManager(realm);
|
||||
}
|
||||
|
||||
private AuthenticationProviderException convertIDMException(IdentityManagementException ie) {
|
||||
Throwable realCause = ie;
|
||||
while (realCause.getCause() != null) {
|
||||
realCause = realCause.getCause();
|
||||
}
|
||||
|
||||
// Use the message from the realCause
|
||||
return new AuthenticationProviderException(realCause.getMessage(), ie);
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package org.keycloak.authentication.picketlink;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.AuthProviderConstants;
|
||||
import org.keycloak.authentication.AuthenticationProvider;
|
||||
import org.keycloak.authentication.AuthenticationProviderFactory;
|
||||
import org.keycloak.picketlink.IdentityManagerProvider;
|
||||
import org.keycloak.provider.ProviderSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PicketlinkAuthenticationProviderFactory implements AuthenticationProviderFactory {
|
||||
|
||||
@Override
|
||||
public AuthenticationProvider create(ProviderSession providerSession) {
|
||||
return new PicketlinkAuthenticationProvider(providerSession.getProvider(IdentityManagerProvider.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return AuthProviderConstants.PROVIDER_NAME_PICKETLINK;
|
||||
}
|
||||
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
org.keycloak.authentication.picketlink.PicketlinkAuthenticationProviderFactory
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
<?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.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-connections-jpa</artifactId>
|
||||
<name>Keycloak Connections JPA</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>${hibernate.entitymanager.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultJpaConnectionProvider implements JpaConnectionProvider {
|
||||
|
||||
private final EntityManager em;
|
||||
|
||||
public DefaultJpaConnectionProvider(EntityManager em) {
|
||||
this.em = em;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager getEntityManager() {
|
||||
return em;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
em.close();
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.hibernate.ejb.AvailableSettings;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Persistence;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
|
||||
|
||||
private volatile EntityManagerFactory emf;
|
||||
|
||||
private Config.Scope config;
|
||||
|
||||
@Override
|
||||
public JpaConnectionProvider create(KeycloakSession session) {
|
||||
lazyInit();
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
em = PersistenceExceptionConverter.create(em);
|
||||
session.getTransaction().enlist(new JpaKeycloakTransaction(em));
|
||||
return new DefaultJpaConnectionProvider(em);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (emf != null) {
|
||||
emf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private void lazyInit() {
|
||||
if (emf == null) {
|
||||
synchronized (this) {
|
||||
if (emf == null) {
|
||||
String unitName = config.get("unitName");
|
||||
Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
||||
// Only load config from keycloak-server.json if unitName is not specified
|
||||
if (unitName == null) {
|
||||
unitName = "keycloak-default";
|
||||
|
||||
String dataSource = config.get("dataSource");
|
||||
if (dataSource != null) {
|
||||
if (config.getBoolean("jta", false)) {
|
||||
properties.put(AvailableSettings.JTA_DATASOURCE, dataSource);
|
||||
} else {
|
||||
properties.put(AvailableSettings.NON_JTA_DATASOURCE, dataSource);
|
||||
}
|
||||
} else {
|
||||
properties.put(AvailableSettings.JDBC_URL, config.get("url"));
|
||||
properties.put(AvailableSettings.JDBC_DRIVER, config.get("driver"));
|
||||
|
||||
String user = config.get("user");
|
||||
if (user != null) {
|
||||
properties.put(AvailableSettings.JDBC_USER, user);
|
||||
}
|
||||
String password = config.get("password");
|
||||
if (password != null) {
|
||||
properties.put(AvailableSettings.JDBC_PASSWORD, password);
|
||||
}
|
||||
}
|
||||
|
||||
String driverDialect = config.get("driverDialect");
|
||||
if (driverDialect != null && driverDialect.length() > 0) {
|
||||
properties.put("hibernate.dialect", driverDialect);
|
||||
}
|
||||
|
||||
String databaseSchema = config.get("databaseSchema", "validate");
|
||||
if (databaseSchema != null) {
|
||||
properties.put("hibernate.hbm2ddl.auto", databaseSchema);
|
||||
}
|
||||
|
||||
properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
|
||||
properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
|
||||
}
|
||||
|
||||
emf = Persistence.createEntityManagerFactory(unitName, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface JpaConnectionProvider extends Provider {
|
||||
|
||||
EntityManager getEntityManager();
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface JpaConnectionProviderFactory extends ProviderFactory<JpaConnectionProvider> {
|
||||
}
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.authentication;
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
@@ -7,21 +7,21 @@ import org.keycloak.provider.Spi;
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class AuthenticationSpi implements Spi {
|
||||
public class JpaConnectionSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "authentication";
|
||||
return "connectionsJpa";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return AuthenticationProvider.class;
|
||||
return JpaConnectionProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return AuthenticationProviderFactory.class;
|
||||
return JpaConnectionProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JpaKeycloakTransaction implements KeycloakTransaction {
|
||||
|
||||
protected EntityManager em;
|
||||
|
||||
public JpaKeycloakTransaction(EntityManager em) {
|
||||
this.em = em;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void begin() {
|
||||
em.getTransaction().begin();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commit() {
|
||||
try {
|
||||
em.getTransaction().commit();
|
||||
} catch (PersistenceException e) {
|
||||
throw PersistenceExceptionConverter.convert(e.getCause() != null ? e.getCause() : e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
em.getTransaction().rollback();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRollbackOnly() {
|
||||
em.getTransaction().setRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRollbackOnly() {
|
||||
return em.getTransaction().getRollbackOnly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return em.getTransaction().isActive();
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.keycloak.connections.jpa;
|
||||
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.ModelException;
|
||||
|
||||
import javax.persistence.EntityExistsException;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class PersistenceExceptionConverter implements InvocationHandler {
|
||||
|
||||
private EntityManager em;
|
||||
|
||||
public static EntityManager create(EntityManager em) {
|
||||
return (EntityManager) Proxy.newProxyInstance(EntityManager.class.getClassLoader(), new Class[]{EntityManager.class}, new PersistenceExceptionConverter(em));
|
||||
}
|
||||
|
||||
private PersistenceExceptionConverter(EntityManager em) {
|
||||
this.em = em;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
try {
|
||||
return method.invoke(em, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw convert(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
public static ModelException convert(Throwable t) {
|
||||
if (t.getCause() != null && t.getCause() instanceof ConstraintViolationException) {
|
||||
throw new ModelDuplicateException(t);
|
||||
} if (t instanceof EntityExistsException) {
|
||||
throw new ModelDuplicateException(t);
|
||||
} else {
|
||||
throw new ModelException(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||
version="1.0">
|
||||
<persistence-unit name="keycloak-default" transaction-type="RESOURCE_LOCAL">
|
||||
<class>org.keycloak.models.jpa.entities.ApplicationEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.CredentialEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.OAuthClientEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RealmEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RealmAttributeEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.RoleEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.SocialLinkEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserRequiredActionEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserAttributeEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.UserRoleMappingEntity</class>
|
||||
<class>org.keycloak.models.jpa.entities.ScopeMappingEntity</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.UserSessionEntity</class>
|
||||
<class>org.keycloak.models.sessions.jpa.entities.UsernameLoginFailureEntity</class>
|
||||
|
||||
<!-- JpaAuditProvider -->
|
||||
<class>org.keycloak.events.jpa.EventEntity</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
<properties>
|
||||
<property name="jboss.as.jpa.managed" value="false"/>
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory
|
||||
@@ -0,0 +1 @@
|
||||
org.keycloak.connections.jpa.JpaConnectionSpi
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
<?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.0.5.Final</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-connections-mongo</artifactId>
|
||||
<name>Keycloak Connections Mongo</name>
|
||||
<description/>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-model-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import com.mongodb.MongoClient;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.ServerAddress;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocationContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultMongoConnectionFactoryProvider implements MongoConnectionProviderFactory {
|
||||
|
||||
// TODO Make configurable
|
||||
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.entities.RequiredCredentialEntity",
|
||||
"org.keycloak.models.entities.CredentialEntity",
|
||||
"org.keycloak.models.entities.SocialLinkEntity",
|
||||
"org.keycloak.models.mongo.keycloak.entities.MongoApplicationEntity",
|
||||
"org.keycloak.models.mongo.keycloak.entities.MongoOAuthClientEntity",
|
||||
"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"
|
||||
};
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
|
||||
|
||||
private volatile MongoClient client;
|
||||
|
||||
private MongoStore mongoStore;
|
||||
private DB db;
|
||||
private Config.Scope config;
|
||||
|
||||
@Override
|
||||
public MongoConnectionProvider create(KeycloakSession session) {
|
||||
lazyInit();
|
||||
|
||||
TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
|
||||
session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
|
||||
return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
private void lazyInit() {
|
||||
if (client == null) {
|
||||
synchronized (this) {
|
||||
if (client == null) {
|
||||
try {
|
||||
String host = config.get("host", ServerAddress.defaultHost());
|
||||
int port = config.getInt("port", ServerAddress.defaultPort());
|
||||
String dbName = config.get("db", "keycloak");
|
||||
boolean clearOnStartup = config.getBoolean("clearOnStartup", false);
|
||||
|
||||
String user = config.get("user");
|
||||
String password = config.get("password");
|
||||
if (user != null && password != null) {
|
||||
MongoCredential credential = MongoCredential.createMongoCRCredential(user, dbName, password.toCharArray());
|
||||
client = new MongoClient(new ServerAddress(host, port), Collections.singletonList(credential));
|
||||
} else {
|
||||
client = new MongoClient(host, port);
|
||||
}
|
||||
|
||||
this.db = client.getDB(dbName);
|
||||
|
||||
this.mongoStore = new MongoStoreImpl(db, clearOnStartup, getManagedEntities());
|
||||
|
||||
logger.infof("Initialized mongo model. host: %s, port: %d, db: %s, clearOnStartup: %b", host, port, dbName, clearOnStartup);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Class[] getManagedEntities() throws ClassNotFoundException {
|
||||
Class[] entityClasses = new Class[entities.length];
|
||||
for (int i = 0; i < entities.length; i++) {
|
||||
entityClasses[i] = Thread.currentThread().getContextClassLoader().loadClass(entities[i]);
|
||||
}
|
||||
return entityClasses;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (client != null) {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class DefaultMongoConnectionProvider implements MongoConnectionProvider {
|
||||
|
||||
private DB db;
|
||||
private MongoStore mongoStore;
|
||||
private MongoStoreInvocationContext invocationContext;
|
||||
|
||||
public DefaultMongoConnectionProvider(DB db, MongoStore mongoStore, MongoStoreInvocationContext invocationContext) {
|
||||
this.db = db;
|
||||
this.mongoStore = mongoStore;
|
||||
this.invocationContext = invocationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DB getDB() {
|
||||
return db;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoStore getMongoStore() {
|
||||
return mongoStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MongoStoreInvocationContext getInvocationContext() {
|
||||
return invocationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import com.mongodb.DB;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface MongoConnectionProvider extends Provider {
|
||||
|
||||
DB getDB();
|
||||
|
||||
MongoStore getMongoStore();
|
||||
|
||||
MongoStoreInvocationContext getInvocationContext();
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface MongoConnectionProviderFactory extends ProviderFactory<MongoConnectionProvider> {
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class MongoConnectionSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "connectionsMongo";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return MongoConnectionProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return MongoConnectionProviderFactory.class;
|
||||
}
|
||||
|
||||
}
|
||||
+5
-3
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.models.mongo.keycloak.adapters;
|
||||
package org.keycloak.connections.mongo;
|
||||
|
||||
import com.mongodb.MongoException;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.KeycloakTransaction;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
@@ -42,11 +42,13 @@ public class MongoKeycloakTransaction implements KeycloakTransaction {
|
||||
} catch (MongoException e) {
|
||||
throw MongoStoreImpl.convertException(e);
|
||||
}
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rollback() {
|
||||
invocationContext.rollback();
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
/**
|
||||
* Base interface for object, which is persisted in Mongo
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
|
||||
/**
|
||||
* Entity with Id
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.models.mongo.api;
|
||||
package org.keycloak.connections.mongo.api;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -31,6 +31,10 @@ public interface MongoStore {
|
||||
|
||||
<T extends MongoIdentifiableEntity> List<T> loadEntities(Class<T> type, DBObject query, MongoStoreInvocationContext context);
|
||||
|
||||
<T extends MongoIdentifiableEntity> List<T> loadEntities(Class<T> type, DBObject query, DBObject sort, int firstResult, int maxResults, MongoStoreInvocationContext context);
|
||||
|
||||
<T extends MongoIdentifiableEntity> int countEntities(Class<T> type, DBObject query, MongoStoreInvocationContext context);
|
||||
|
||||
boolean removeEntity(MongoIdentifiableEntity entity, MongoStoreInvocationContext context);
|
||||
|
||||
boolean removeEntity(Class<? extends MongoIdentifiableEntity> type, String id, MongoStoreInvocationContext context);
|
||||
@@ -41,8 +45,4 @@ public interface MongoStore {
|
||||
|
||||
<S> boolean pullItemFromList(MongoIdentifiableEntity entity, String listPropertyName, S itemToPull, MongoStoreInvocationContext context);
|
||||
|
||||
/**
|
||||
* Completely remove all data from DB
|
||||
*/
|
||||
void removeAllEntities();
|
||||
}
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.models.mongo.api.context;
|
||||
package org.keycloak.connections.mongo.api.context;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
|
||||
/**
|
||||
* Context, which provides callback methods to be invoked by MongoStore
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api.context;
|
||||
package org.keycloak.connections.mongo.api.context;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api.types;
|
||||
package org.keycloak.connections.mongo.api.types;
|
||||
|
||||
/**
|
||||
* SPI object to convert object from application type to database type and vice versa. Shouldn't be directly used by application.
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api.types;
|
||||
package org.keycloak.connections.mongo.api.types;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.api.types;
|
||||
package org.keycloak.connections.mongo.api.types;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package org.keycloak.models.mongo.impl;
|
||||
package org.keycloak.connections.mongo.impl;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoEntity;
|
||||
import org.keycloak.models.utils.reflection.Property;
|
||||
|
||||
import java.util.Collection;
|
||||
+51
-32
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.models.mongo.impl;
|
||||
package org.keycloak.connections.mongo.impl;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import com.mongodb.BasicDBObject;
|
||||
@@ -8,31 +8,29 @@ import com.mongodb.DBCursor;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MongoException;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.connections.mongo.api.MongoCollection;
|
||||
import org.keycloak.connections.mongo.api.MongoEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoIndex;
|
||||
import org.keycloak.connections.mongo.api.MongoIndexes;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.api.context.MongoTask;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.connections.mongo.impl.types.BasicDBListMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.BasicDBObjectMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.BasicDBObjectToMapMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.EnumToStringMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.ListMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.MapMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.MongoEntityMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.SimpleMapper;
|
||||
import org.keycloak.connections.mongo.impl.types.StringToEnumMapper;
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.mongo.api.MongoCollection;
|
||||
import org.keycloak.models.mongo.api.MongoEntity;
|
||||
import org.keycloak.models.mongo.api.MongoField;
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.MongoIndex;
|
||||
import org.keycloak.models.mongo.api.MongoIndexes;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.api.context.MongoTask;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.models.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.models.mongo.impl.types.BasicDBListMapper;
|
||||
import org.keycloak.models.mongo.impl.types.BasicDBObjectMapper;
|
||||
import org.keycloak.models.mongo.impl.types.BasicDBObjectToMapMapper;
|
||||
import org.keycloak.models.mongo.impl.types.EnumToStringMapper;
|
||||
import org.keycloak.models.mongo.impl.types.ListMapper;
|
||||
import org.keycloak.models.mongo.impl.types.MapMapper;
|
||||
import org.keycloak.models.mongo.impl.types.MongoEntityMapper;
|
||||
import org.keycloak.models.mongo.impl.types.SimpleMapper;
|
||||
import org.keycloak.models.mongo.impl.types.StringToEnumMapper;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.utils.reflection.AnnotatedPropertyCriteria;
|
||||
import org.keycloak.models.utils.reflection.Property;
|
||||
import org.keycloak.models.utils.reflection.PropertyQueries;
|
||||
|
||||
@@ -41,7 +39,6 @@ import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
@@ -283,6 +280,35 @@ public class MongoStoreImpl implements MongoStore {
|
||||
return convertCursor(type, cursor, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends MongoIdentifiableEntity> List<T> loadEntities(Class<T> type, DBObject query, DBObject sort, int firstResult, int maxResults, MongoStoreInvocationContext context) {
|
||||
// First we should execute all pending tasks before searching DB
|
||||
context.beforeDBSearch(type);
|
||||
|
||||
DBCollection dbCollection = getDBCollectionForType(type);
|
||||
DBCursor cursor = dbCollection.find(query);
|
||||
if (firstResult != -1) {
|
||||
cursor.skip(firstResult);
|
||||
}
|
||||
if (maxResults != -1) {
|
||||
cursor.limit(maxResults);
|
||||
}
|
||||
if (sort != null) {
|
||||
cursor.sort(sort);
|
||||
}
|
||||
|
||||
return convertCursor(type, cursor, context);
|
||||
}
|
||||
|
||||
public <T extends MongoIdentifiableEntity> int countEntities(Class<T> type, DBObject query, MongoStoreInvocationContext context) {
|
||||
context.beforeDBSearch(type);
|
||||
|
||||
DBCollection dbCollection = getDBCollectionForType(type);
|
||||
Long count = dbCollection.count(query);
|
||||
|
||||
// For now, assume that int is sufficient
|
||||
return count.intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeEntity(MongoIdentifiableEntity entity, MongoStoreInvocationContext context) {
|
||||
@@ -417,13 +443,6 @@ public class MongoStoreImpl implements MongoStore {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllEntities() {
|
||||
Set<Class<?>> managedTypes = this.entityInfoCache.keySet();
|
||||
Class<? extends MongoEntity>[] arrayTemplate = (Class<? extends MongoEntity>[])new Class<?>[0];
|
||||
this.clearManagedCollections(managedTypes.toArray(arrayTemplate));
|
||||
}
|
||||
|
||||
// Possibility to add user-defined mappers
|
||||
public void addAppObjectConverter(Mapper<?, ?> mapper) {
|
||||
mapperRegistry.addAppObjectMapper(mapper);
|
||||
+5
-6
@@ -1,10 +1,9 @@
|
||||
package org.keycloak.models.mongo.impl.context;
|
||||
package org.keycloak.connections.mongo.impl.context;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoEntity;
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.api.context.MongoTask;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.api.context.MongoTask;
|
||||
|
||||
/**
|
||||
* Context, which is not doing any postponing of tasks and does not cache anything
|
||||
+6
-6
@@ -1,4 +1,9 @@
|
||||
package org.keycloak.models.mongo.impl.context;
|
||||
package org.keycloak.connections.mongo.impl.context;
|
||||
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.MongoStore;
|
||||
import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.connections.mongo.api.context.MongoTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -6,11 +11,6 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.MongoStore;
|
||||
import org.keycloak.models.mongo.api.context.MongoStoreInvocationContext;
|
||||
import org.keycloak.models.mongo.api.context.MongoTask;
|
||||
|
||||
/**
|
||||
* Invocation context, which has some very basic support for transactions, and is able to cache loaded objects.
|
||||
* It always execute all pending update tasks before start searching for other objects
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.models.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.MapperRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
+12
-13
@@ -1,22 +1,21 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
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.models.utils.reflection.Types;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.mongo.api.MongoEntity;
|
||||
import org.keycloak.models.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.models.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.mongo.impl.EntityInfo;
|
||||
import org.keycloak.models.utils.reflection.Property;
|
||||
import org.keycloak.models.utils.reflection.Types;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
|
||||
/**
|
||||
* For now, there is support just for convert to Map<String, String>
|
||||
*
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBList;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.models.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.MapperRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
|
||||
/**
|
||||
* For now, we support just convert from Map<String, String>
|
||||
*
|
||||
+8
-7
@@ -1,11 +1,12 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.models.mongo.api.types.MapperRegistry;
|
||||
import org.keycloak.models.mongo.impl.MongoStoreImpl;
|
||||
import org.keycloak.models.mongo.impl.EntityInfo;
|
||||
import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
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 java.util.Collection;
|
||||
@@ -38,7 +39,7 @@ public class MongoEntityMapper<T> implements Mapper<T, BasicDBObject> {
|
||||
String propName = property.getName();
|
||||
|
||||
// Ignore "id" property
|
||||
if (!"id".equals(propName)) {
|
||||
if (!"id".equals(propName) || !(applicationObject instanceof MongoIdentifiableEntity)) {
|
||||
Object propValue = property.getValue(applicationObject);
|
||||
if (propValue != null) {
|
||||
Object dbValue = propValue == null ? null : mapperRegistry.convertApplicationObjectToDBObject(propValue, Object.class);
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
|
||||
/**
|
||||
* Just returns input
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
package org.keycloak.models.mongo.impl.types;
|
||||
package org.keycloak.connections.mongo.impl.types;
|
||||
|
||||
import org.keycloak.models.mongo.api.types.Mapper;
|
||||
import org.keycloak.models.mongo.api.types.MapperContext;
|
||||
import org.keycloak.connections.mongo.api.types.Mapper;
|
||||
import org.keycloak.connections.mongo.api.types.MapperContext;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.keycloak.connections.mongo.DefaultMongoConnectionFactoryProvider
|
||||
@@ -0,0 +1 @@
|
||||
org.keycloak.connections.mongo.MongoConnectionSpi
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
<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.0.5.Final</version>
|
||||
</parent>
|
||||
<name>Connections Parent</name>
|
||||
<description/>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-connections-pom</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>jpa</module>
|
||||
<module>mongo</module>
|
||||
</modules>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-2</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+11
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>keycloak-parent</artifactId>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<version>1.0-beta-2</version>
|
||||
<version>1.0.5.Final</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -13,6 +13,10 @@
|
||||
<name>Keycloak Core</name>
|
||||
<description/>
|
||||
|
||||
<properties>
|
||||
<timestamp>${maven.build.timestamp}</timestamp>
|
||||
<maven.build.timestamp.format>yyyy-MM-dd HH:mm</maven.build.timestamp.format>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
@@ -41,6 +45,12 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
||||
@@ -19,6 +19,7 @@ public class AbstractOAuthClient {
|
||||
protected String authUrl;
|
||||
protected String codeUrl;
|
||||
protected String refreshUrl;
|
||||
protected boolean relativeUrls;
|
||||
protected String scope;
|
||||
protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
|
||||
protected String stateCookiePath;
|
||||
@@ -100,6 +101,14 @@ public class AbstractOAuthClient {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
public boolean isRelativeUrls() {
|
||||
return relativeUrls;
|
||||
}
|
||||
|
||||
public void setRelativeUrls(boolean relativeUrls) {
|
||||
this.relativeUrls = relativeUrls;
|
||||
}
|
||||
|
||||
protected String stripOauthParametersFromRedirect(String uri) {
|
||||
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
|
||||
.replaceQueryParam(OAuth2Constants.CODE, null)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.keycloak.services;
|
||||
package org.keycloak;
|
||||
|
||||
/**
|
||||
* Information about the client connection
|
||||
@@ -16,7 +16,12 @@ public class Config {
|
||||
}
|
||||
|
||||
public static String getProvider(String spi) {
|
||||
return configProvider.getProvider(spi);
|
||||
String provider = configProvider.getProvider(spi);
|
||||
if (provider == null || provider.trim().equals("")) {
|
||||
return null;
|
||||
} else {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
public static Scope scope(String... scope) {
|
||||
|
||||
@@ -17,7 +17,12 @@ public class RSATokenVerifier {
|
||||
}
|
||||
|
||||
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realm, boolean checkActive) throws VerificationException {
|
||||
JWSInput input = new JWSInput(tokenString);
|
||||
JWSInput input = null;
|
||||
try {
|
||||
input = new JWSInput(tokenString);
|
||||
} catch (Exception e) {
|
||||
throw new VerificationException("Couldn't parse token", e);
|
||||
}
|
||||
if (!isPublicKeyValid(input, realmKey)) throw new VerificationException("Invalid token signature.");
|
||||
|
||||
AccessToken token;
|
||||
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
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 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");
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ public interface AdapterConstants {
|
||||
|
||||
// URL endpoints
|
||||
public static final String K_LOGOUT = "k_logout";
|
||||
public static final String K_VERSION = "k_version";
|
||||
public static final String K_PUSH_NOT_BEFORE = "k_push_not_before";
|
||||
public static final String K_GET_USER_STATS = "k_get_user_stats";
|
||||
public static final String K_GET_SESSION_STATS = "k_get_session_stats";
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.keycloak.enums;
|
||||
|
||||
import org.keycloak.ClientConnection;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public enum SslRequired {
|
||||
|
||||
ALL,
|
||||
EXTERNAL,
|
||||
NONE;
|
||||
|
||||
public boolean isRequired(ClientConnection connection) {
|
||||
return isRequired(connection.getRemoteAddr());
|
||||
}
|
||||
|
||||
public boolean isRequired(String address) {
|
||||
switch (this) {
|
||||
case ALL:
|
||||
return true;
|
||||
case NONE:
|
||||
return false;
|
||||
case EXTERNAL:
|
||||
return !isLocal(address);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isLocal(String remoteAddress) {
|
||||
try {
|
||||
InetAddress inetAddress = InetAddress.getByName(remoteAddress);
|
||||
return inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isSiteLocalAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.keycloak.provider;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface ProviderSession {
|
||||
|
||||
<T extends Provider> T getProvider(Class<T> clazz);
|
||||
|
||||
<T extends Provider> T getProvider(Class<T> clazz, String id);
|
||||
|
||||
<T extends Provider> Set<String> listProviderIds(Class<T> clazz);
|
||||
|
||||
<T extends Provider> Set<T> getAllProviders(Class<T> clazz);
|
||||
|
||||
void close();
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package org.keycloak.provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public interface ProviderSessionFactory {
|
||||
|
||||
ProviderSession createSession();
|
||||
|
||||
void close();
|
||||
|
||||
void init();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.keycloak.representations;
|
||||
|
||||
import org.keycloak.util.Time;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
public class PasswordToken {
|
||||
|
||||
private String realm;
|
||||
private String user;
|
||||
private int timestamp;
|
||||
|
||||
public PasswordToken() {
|
||||
}
|
||||
|
||||
public PasswordToken(String realm, String user) {
|
||||
this.realm = realm;
|
||||
this.user = user;
|
||||
this.timestamp = Time.currentTime();
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
return realm;
|
||||
}
|
||||
|
||||
public void setRealm(String realm) {
|
||||
this.realm = realm;
|
||||
}
|
||||
|
||||
public String getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(String user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public int getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(int timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
|
||||
"resource", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ import java.util.Map;
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required",
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required",
|
||||
"resource", "public-client", "credentials",
|
||||
"use-resource-role-mappings",
|
||||
"enable-cors", "cors-max-age", "cors-allowed-methods",
|
||||
|
||||
+7
-7
@@ -9,7 +9,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-not-required"})
|
||||
@JsonPropertyOrder({"realm", "realm-public-key", "auth-server-url", "ssl-required"})
|
||||
public class BaseRealmConfig {
|
||||
@JsonProperty("realm")
|
||||
protected String realm;
|
||||
@@ -17,15 +17,15 @@ public class BaseRealmConfig {
|
||||
protected String realmKey;
|
||||
@JsonProperty("auth-server-url")
|
||||
protected String authServerUrl;
|
||||
@JsonProperty("ssl-not-required")
|
||||
protected boolean sslNotRequired;
|
||||
@JsonProperty("ssl-required")
|
||||
protected String sslRequired;
|
||||
|
||||
public boolean isSslNotRequired() {
|
||||
return sslNotRequired;
|
||||
public String getSslRequired() {
|
||||
return sslRequired;
|
||||
}
|
||||
|
||||
public void setSslNotRequired(boolean sslNotRequired) {
|
||||
this.sslNotRequired = sslNotRequired;
|
||||
public void setSslRequired(String sslRequired) {
|
||||
this.sslRequired = sslRequired;
|
||||
}
|
||||
|
||||
public String getRealm() {
|
||||
|
||||
@@ -21,6 +21,7 @@ public class ApplicationRepresentation {
|
||||
protected Integer notBefore;
|
||||
protected Boolean bearerOnly;
|
||||
protected Boolean publicClient;
|
||||
protected Boolean fullScopeAllowed;
|
||||
|
||||
|
||||
public String getId() {
|
||||
@@ -134,4 +135,12 @@ public class ApplicationRepresentation {
|
||||
public void setPublicClient(Boolean publicClient) {
|
||||
this.publicClient = publicClient;
|
||||
}
|
||||
|
||||
public Boolean isFullScopeAllowed() {
|
||||
return fullScopeAllowed;
|
||||
}
|
||||
|
||||
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
||||
this.fullScopeAllowed = fullScopeAllowed;
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthenticationLinkRepresentation {
|
||||
|
||||
private String authProvider;
|
||||
private String authUserId;
|
||||
|
||||
public String getAuthProvider() {
|
||||
return authProvider;
|
||||
}
|
||||
|
||||
public void setAuthProvider(String authProvider) {
|
||||
this.authProvider = authProvider;
|
||||
}
|
||||
|
||||
public String getAuthUserId() {
|
||||
return authUserId;
|
||||
}
|
||||
|
||||
public void setAuthUserId(String authUserId) {
|
||||
this.authUserId = authUserId;
|
||||
}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AuthenticationProviderRepresentation {
|
||||
|
||||
private String providerName;
|
||||
private boolean passwordUpdateSupported = true;
|
||||
private Map<String, String> config;
|
||||
|
||||
public String getProviderName() {
|
||||
return providerName;
|
||||
}
|
||||
|
||||
public void setProviderName(String providerName) {
|
||||
this.providerName = providerName;
|
||||
}
|
||||
|
||||
public boolean isPasswordUpdateSupported() {
|
||||
return passwordUpdateSupported;
|
||||
}
|
||||
|
||||
public void setPasswordUpdateSupported(boolean passwordUpdateSupported) {
|
||||
this.passwordUpdateSupported = passwordUpdateSupported;
|
||||
}
|
||||
|
||||
public Map<String, String> getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public void setConfig(Map<String, String> config) {
|
||||
this.config = config;
|
||||
}
|
||||
}
|
||||
@@ -95,4 +95,40 @@ public class ClaimRepresentation {
|
||||
public void setPhone(boolean phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ClaimRepresentation that = (ClaimRepresentation) o;
|
||||
|
||||
if (address != that.address) return false;
|
||||
if (email != that.email) return false;
|
||||
if (gender != that.gender) return false;
|
||||
if (locale != that.locale) return false;
|
||||
if (name != that.name) return false;
|
||||
if (phone != that.phone) return false;
|
||||
if (picture != that.picture) return false;
|
||||
if (profile != that.profile) return false;
|
||||
if (username != that.username) return false;
|
||||
if (website != that.website) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (name ? 1 : 0);
|
||||
result = 31 * result + (username ? 1 : 0);
|
||||
result = 31 * result + (profile ? 1 : 0);
|
||||
result = 31 * result + (picture ? 1 : 0);
|
||||
result = 31 * result + (website ? 1 : 0);
|
||||
result = 31 * result + (email ? 1 : 0);
|
||||
result = 31 * result + (gender ? 1 : 0);
|
||||
result = 31 * result + (locale ? 1 : 0);
|
||||
result = 31 * result + (address ? 1 : 0);
|
||||
result = 31 * result + (phone ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,23 @@ package org.keycloak.representations.idm;
|
||||
public class CredentialRepresentation {
|
||||
public static final String SECRET = "secret";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String PASSWORD_TOKEN = "password-token";
|
||||
public static final String TOTP = "totp";
|
||||
public static final String CLIENT_CERT = "cert";
|
||||
|
||||
protected String type;
|
||||
protected String value;
|
||||
protected String device;
|
||||
|
||||
// Plain-text value of credential (used for example during import from manually created JSON file)
|
||||
protected String value;
|
||||
|
||||
// Value stored in DB (used for example during export/import)
|
||||
protected String hashedSaltedValue;
|
||||
protected String salt;
|
||||
protected Integer hashIterations;
|
||||
// only used when updating a credential. Might set required action
|
||||
protected boolean temporary;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -37,4 +47,36 @@ public class CredentialRepresentation {
|
||||
public void setDevice(String device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public String getHashedSaltedValue() {
|
||||
return hashedSaltedValue;
|
||||
}
|
||||
|
||||
public void setHashedSaltedValue(String hashedSaltedValue) {
|
||||
this.hashedSaltedValue = hashedSaltedValue;
|
||||
}
|
||||
|
||||
public String getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
public void setSalt(String salt) {
|
||||
this.salt = salt;
|
||||
}
|
||||
|
||||
public Integer getHashIterations() {
|
||||
return hashIterations;
|
||||
}
|
||||
|
||||
public void setHashIterations(Integer hashIterations) {
|
||||
this.hashIterations = hashIterations;
|
||||
}
|
||||
|
||||
public boolean isTemporary() {
|
||||
return temporary;
|
||||
}
|
||||
|
||||
public void setTemporary(boolean temporary) {
|
||||
this.temporary = temporary;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ import java.util.List;
|
||||
public class OAuthClientRepresentation {
|
||||
protected String id;
|
||||
protected String name;
|
||||
protected String baseUrl;
|
||||
protected List<String> redirectUris;
|
||||
protected List<String> webOrigins;
|
||||
protected Boolean enabled;
|
||||
@@ -18,6 +17,7 @@ public class OAuthClientRepresentation {
|
||||
protected Integer notBefore;
|
||||
protected Boolean publicClient;
|
||||
protected Boolean directGrantsOnly;
|
||||
protected Boolean fullScopeAllowed;
|
||||
|
||||
|
||||
public String getId() {
|
||||
@@ -44,14 +44,6 @@ public class OAuthClientRepresentation {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
public List<String> getRedirectUris() {
|
||||
return redirectUris;
|
||||
}
|
||||
@@ -107,4 +99,13 @@ public class OAuthClientRepresentation {
|
||||
public void setDirectGrantsOnly(Boolean directGrantsOnly) {
|
||||
this.directGrantsOnly = directGrantsOnly;
|
||||
}
|
||||
|
||||
public Boolean isFullScopeAllowed() {
|
||||
return fullScopeAllowed;
|
||||
}
|
||||
|
||||
public void setFullScopeAllowed(Boolean fullScopeAllowed) {
|
||||
this.fullScopeAllowed = fullScopeAllowed;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RealmAuditRepresentation {
|
||||
protected boolean auditEnabled;
|
||||
protected Long auditExpiration;
|
||||
protected List<String> auditListeners;
|
||||
|
||||
public boolean isAuditEnabled() {
|
||||
return auditEnabled;
|
||||
}
|
||||
|
||||
public void setAuditEnabled(boolean auditEnabled) {
|
||||
this.auditEnabled = auditEnabled;
|
||||
}
|
||||
|
||||
public Long getAuditExpiration() {
|
||||
return auditExpiration;
|
||||
}
|
||||
|
||||
public void setAuditExpiration(Long auditExpiration) {
|
||||
this.auditExpiration = auditExpiration;
|
||||
}
|
||||
|
||||
public List<String> getAuditListeners() {
|
||||
return auditListeners;
|
||||
}
|
||||
|
||||
public void setAuditListeners(List<String> auditListeners) {
|
||||
this.auditListeners = auditListeners;
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RealmEventsConfigRepresentation {
|
||||
protected boolean eventsEnabled;
|
||||
protected Long eventsExpiration;
|
||||
protected List<String> eventsListeners;
|
||||
|
||||
public boolean isEventsEnabled() {
|
||||
return eventsEnabled;
|
||||
}
|
||||
|
||||
public void setEventsEnabled(boolean eventsEnabled) {
|
||||
this.eventsEnabled = eventsEnabled;
|
||||
}
|
||||
|
||||
public Long getEventsExpiration() {
|
||||
return eventsExpiration;
|
||||
}
|
||||
|
||||
public void setEventsExpiration(Long eventsExpiration) {
|
||||
this.eventsExpiration = eventsExpiration;
|
||||
}
|
||||
|
||||
public List<String> getEventsListeners() {
|
||||
return eventsListeners;
|
||||
}
|
||||
|
||||
public void setEventsListeners(List<String> eventsListeners) {
|
||||
this.eventsListeners = eventsListeners;
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class RealmRepresentation {
|
||||
protected Integer accessCodeLifespan;
|
||||
protected Integer accessCodeLifespanUserAction;
|
||||
protected Boolean enabled;
|
||||
protected Boolean sslNotRequired;
|
||||
protected String sslRequired;
|
||||
protected Boolean passwordCredentialGrantAllowed;
|
||||
protected Boolean registrationAllowed;
|
||||
protected Boolean rememberMe;
|
||||
@@ -27,6 +27,10 @@ public class RealmRepresentation {
|
||||
protected Boolean resetPasswordAllowed;
|
||||
protected Boolean social;
|
||||
protected Boolean updateProfileOnInitialSocialLogin;
|
||||
|
||||
protected Boolean userCacheEnabled;
|
||||
protected Boolean realmCacheEnabled;
|
||||
|
||||
//--- brute force settings
|
||||
protected Boolean bruteForceProtected;
|
||||
protected Integer maxFailureWaitSeconds;
|
||||
@@ -44,24 +48,21 @@ public class RealmRepresentation {
|
||||
protected Set<String> requiredCredentials;
|
||||
protected String passwordPolicy;
|
||||
protected List<UserRepresentation> users;
|
||||
protected List<UserRoleMappingRepresentation> roleMappings;
|
||||
protected List<ScopeMappingRepresentation> scopeMappings;
|
||||
protected Map<String, List<UserRoleMappingRepresentation>> applicationRoleMappings;
|
||||
protected Map<String, List<ScopeMappingRepresentation>> applicationScopeMappings;
|
||||
protected List<SocialMappingRepresentation> socialMappings;
|
||||
protected List<ApplicationRepresentation> applications;
|
||||
protected List<OAuthClientRepresentation> oauthClients;
|
||||
protected Map<String, String> browserSecurityHeaders;
|
||||
protected Map<String, String> socialProviders;
|
||||
protected Map<String, String> smtpServer;
|
||||
protected Map<String, String> ldapServer;
|
||||
protected List<AuthenticationProviderRepresentation> authenticationProviders;
|
||||
protected List<UserFederationProviderRepresentation> userFederationProviders;
|
||||
protected String loginTheme;
|
||||
protected String accountTheme;
|
||||
protected String adminTheme;
|
||||
protected String emailTheme;
|
||||
protected boolean auditEnabled;
|
||||
protected long auditExpiration;
|
||||
protected List<String> auditListeners;
|
||||
protected boolean eventsEnabled;
|
||||
protected long eventsExpiration;
|
||||
protected List<String> eventsListeners;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
@@ -119,12 +120,12 @@ public class RealmRepresentation {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Boolean isSslNotRequired() {
|
||||
return sslNotRequired;
|
||||
public String getSslRequired() {
|
||||
return sslRequired;
|
||||
}
|
||||
|
||||
public void setSslNotRequired(Boolean sslNotRequired) {
|
||||
this.sslNotRequired = sslNotRequired;
|
||||
public void setSslRequired(String sslRequired) {
|
||||
this.sslRequired = sslRequired;
|
||||
}
|
||||
|
||||
public Integer getAccessTokenLifespan() {
|
||||
@@ -151,18 +152,6 @@ public class RealmRepresentation {
|
||||
this.ssoSessionMaxLifespan = ssoSessionMaxLifespan;
|
||||
}
|
||||
|
||||
public List<UserRoleMappingRepresentation> getRoleMappings() {
|
||||
return roleMappings;
|
||||
}
|
||||
|
||||
public UserRoleMappingRepresentation roleMapping(String username) {
|
||||
UserRoleMappingRepresentation mapping = new UserRoleMappingRepresentation();
|
||||
mapping.setUsername(username);
|
||||
if (roleMappings == null) roleMappings = new ArrayList<UserRoleMappingRepresentation>();
|
||||
roleMappings.add(mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public List<ScopeMappingRepresentation> getScopeMappings() {
|
||||
return scopeMappings;
|
||||
}
|
||||
@@ -175,18 +164,6 @@ public class RealmRepresentation {
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public List<SocialMappingRepresentation> getSocialMappings() {
|
||||
return socialMappings;
|
||||
}
|
||||
|
||||
public SocialMappingRepresentation socialMapping(String username) {
|
||||
SocialMappingRepresentation mapping = new SocialMappingRepresentation();
|
||||
mapping.setUsername(username);
|
||||
if (socialMappings == null) socialMappings = new ArrayList<SocialMappingRepresentation>();
|
||||
socialMappings.add(mapping);
|
||||
return mapping;
|
||||
}
|
||||
|
||||
public Set<String> getRequiredCredentials() {
|
||||
return requiredCredentials;
|
||||
}
|
||||
@@ -267,6 +244,22 @@ public class RealmRepresentation {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public Boolean isRealmCacheEnabled() {
|
||||
return realmCacheEnabled;
|
||||
}
|
||||
|
||||
public void setRealmCacheEnabled(Boolean realmCacheEnabled) {
|
||||
this.realmCacheEnabled = realmCacheEnabled;
|
||||
}
|
||||
|
||||
public Boolean isUserCacheEnabled() {
|
||||
return userCacheEnabled;
|
||||
}
|
||||
|
||||
public void setUserCacheEnabled(Boolean userCacheEnabled) {
|
||||
this.userCacheEnabled = userCacheEnabled;
|
||||
}
|
||||
|
||||
public Boolean isVerifyEmail() {
|
||||
return verifyEmail;
|
||||
}
|
||||
@@ -299,6 +292,14 @@ public class RealmRepresentation {
|
||||
this.updateProfileOnInitialSocialLogin = updateProfileOnInitialSocialLogin;
|
||||
}
|
||||
|
||||
public Map<String, String> getBrowserSecurityHeaders() {
|
||||
return browserSecurityHeaders;
|
||||
}
|
||||
|
||||
public void setBrowserSecurityHeaders(Map<String, String> browserSecurityHeaders) {
|
||||
this.browserSecurityHeaders = browserSecurityHeaders;
|
||||
}
|
||||
|
||||
public Map<String, String> getSocialProviders() {
|
||||
return socialProviders;
|
||||
}
|
||||
@@ -315,22 +316,6 @@ public class RealmRepresentation {
|
||||
this.smtpServer = smtpServer;
|
||||
}
|
||||
|
||||
public Map<String, String> getLdapServer() {
|
||||
return ldapServer;
|
||||
}
|
||||
|
||||
public void setLdapServer(Map<String, String> ldapServer) {
|
||||
this.ldapServer = ldapServer;
|
||||
}
|
||||
|
||||
public List<AuthenticationProviderRepresentation> getAuthenticationProviders() {
|
||||
return authenticationProviders;
|
||||
}
|
||||
|
||||
public void setAuthenticationProviders(List<AuthenticationProviderRepresentation> authenticationProviders) {
|
||||
this.authenticationProviders = authenticationProviders;
|
||||
}
|
||||
|
||||
public List<OAuthClientRepresentation> getOauthClients() {
|
||||
return oauthClients;
|
||||
}
|
||||
@@ -339,14 +324,6 @@ public class RealmRepresentation {
|
||||
this.oauthClients = oauthClients;
|
||||
}
|
||||
|
||||
public Map<String, List<UserRoleMappingRepresentation>> getApplicationRoleMappings() {
|
||||
return applicationRoleMappings;
|
||||
}
|
||||
|
||||
public void setApplicationRoleMappings(Map<String, List<UserRoleMappingRepresentation>> applicationRoleMappings) {
|
||||
this.applicationRoleMappings = applicationRoleMappings;
|
||||
}
|
||||
|
||||
public Map<String, List<ScopeMappingRepresentation>> getApplicationScopeMappings() {
|
||||
return applicationScopeMappings;
|
||||
}
|
||||
@@ -458,4 +435,36 @@ public class RealmRepresentation {
|
||||
public void setFailureFactor(Integer failureFactor) {
|
||||
this.failureFactor = failureFactor;
|
||||
}
|
||||
|
||||
public boolean isEventsEnabled() {
|
||||
return eventsEnabled;
|
||||
}
|
||||
|
||||
public void setEventsEnabled(boolean eventsEnabled) {
|
||||
this.eventsEnabled = eventsEnabled;
|
||||
}
|
||||
|
||||
public long getEventsExpiration() {
|
||||
return eventsExpiration;
|
||||
}
|
||||
|
||||
public void setEventsExpiration(long eventsExpiration) {
|
||||
this.eventsExpiration = eventsExpiration;
|
||||
}
|
||||
|
||||
public List<String> getEventsListeners() {
|
||||
return eventsListeners;
|
||||
}
|
||||
|
||||
public void setEventsListeners(List<String> eventsListeners) {
|
||||
this.eventsListeners = eventsListeners;
|
||||
}
|
||||
|
||||
public List<UserFederationProviderRepresentation> getUserFederationProviders() {
|
||||
return userFederationProviders;
|
||||
}
|
||||
|
||||
public void setUserFederationProviders(List<UserFederationProviderRepresentation> userFederationProviders) {
|
||||
this.userFederationProviders = userFederationProviders;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class SocialMappingRepresentation {
|
||||
|
||||
protected String self; // link
|
||||
protected String username;
|
||||
protected List<SocialLinkRepresentation> socialLinks;
|
||||
|
||||
public String getSelf() {
|
||||
return self;
|
||||
}
|
||||
|
||||
public void setSelf(String self) {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public List<SocialLinkRepresentation> getSocialLinks() {
|
||||
return socialLinks;
|
||||
}
|
||||
|
||||
public SocialLinkRepresentation socialLink(String socialProvider, String socialUserId, String socialUsername) {
|
||||
SocialLinkRepresentation link = new SocialLinkRepresentation();
|
||||
link.setSocialProvider(socialProvider);
|
||||
link.setSocialUserId(socialUserId);
|
||||
link.setSocialUsername(socialUsername);
|
||||
if (socialLinks == null) socialLinks = new ArrayList<SocialLinkRepresentation>();
|
||||
socialLinks.add(link);
|
||||
return link;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1117 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user